DEADSOFTWARE

hopefully no more windows
authorFGSFDSFGS <derp.primus@gmail.com>
Wed, 21 Dec 2016 01:06:32 +0000 (04:06 +0300)
committerFGSFDSFGS <derp.primus@gmail.com>
Wed, 21 Dec 2016 01:06:32 +0000 (04:06 +0300)
107 files changed:
src/editor/Editor.lpi
src/editor/Editor.lpr
src/editor/f_addresource_sound.pas
src/editor/f_addresource_texture.pas
src/editor/f_main.lfm
src/editor/f_main.pas
src/editor/f_mapoptions.lfm
src/editor/f_options.lfm
src/editor/g_language.pas
src/editor/g_map.pas
src/editor/g_textures.pas
src/engine/e_graphics.pas
src/engine/e_textures.pas
src/lib/dgl/GL.pas [deleted file]
src/lib/dgl/dglOpenGL.pas [deleted file]
src/lib/dgl/glExt.pas [deleted file]
src/lib/vampimg/Imaging.pas [new file with mode: 0644]
src/lib/vampimg/ImagingBitmap.pas [new file with mode: 0644]
src/lib/vampimg/ImagingCanvases.pas [new file with mode: 0644]
src/lib/vampimg/ImagingClasses.pas [new file with mode: 0644]
src/lib/vampimg/ImagingColors.pas [new file with mode: 0644]
src/lib/vampimg/ImagingComponents.pas [new file with mode: 0644]
src/lib/vampimg/ImagingDds.pas [new file with mode: 0644]
src/lib/vampimg/ImagingExtras.pas [new file with mode: 0644]
src/lib/vampimg/ImagingFormats.pas [new file with mode: 0644]
src/lib/vampimg/ImagingGif.pas [new file with mode: 0644]
src/lib/vampimg/ImagingIO.pas [new file with mode: 0644]
src/lib/vampimg/ImagingJpeg.pas [new file with mode: 0644]
src/lib/vampimg/ImagingNetworkGraphics.pas [new file with mode: 0644]
src/lib/vampimg/ImagingOptions.inc [new file with mode: 0644]
src/lib/vampimg/ImagingPcx.pas [new file with mode: 0644]
src/lib/vampimg/ImagingPortableMaps.pas [new file with mode: 0644]
src/lib/vampimg/ImagingPsd.pas [new file with mode: 0644]
src/lib/vampimg/ImagingRadiance.pas [new file with mode: 0644]
src/lib/vampimg/ImagingTarga.pas [new file with mode: 0644]
src/lib/vampimg/ImagingTypes.pas [new file with mode: 0644]
src/lib/vampimg/ImagingUtility.pas [new file with mode: 0644]
src/lib/vampimg/ImagingXpm.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcapimin.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcapistd.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjccoefct.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjccolor.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcdctmgr.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjchuff.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcinit.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcmainct.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcmarker.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcmaster.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcomapi.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjconfig.inc [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcparam.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcphuff.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcprepct.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjcsample.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdapimin.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdapistd.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdcoefct.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdcolor.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdct.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjddctmgr.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdeferr.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdhuff.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdinput.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdmainct.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdmarker.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdmaster.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdmerge.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdphuff.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdpostct.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjdsample.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjerror.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjfdctflt.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjfdctfst.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjfdctint.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjidctasm.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjidctflt.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjidctfst.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjidctint.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjidctred.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjinclude.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjmemmgr.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjmemnobs.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjmorecfg.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjpeglib.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjquant1.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjquant2.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/imjutils.pas [new file with mode: 0644]
src/lib/vampimg/JpegLib/readme.txt [new file with mode: 0644]
src/lib/vampimg/ZLib/dzlib.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/imadler.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/iminfblock.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/iminfcodes.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/iminffast.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/iminftrees.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/iminfutil.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/impaszlib.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/imtrees.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/imzconf.inc [new file with mode: 0644]
src/lib/vampimg/ZLib/imzdeflate.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/imzinflate.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/imzutil.pas [new file with mode: 0644]
src/lib/vampimg/ZLib/readme.txt [new file with mode: 0644]
src/shared/WADEDITOR.pas
src/shared/WADSTRUCT.pas
src/shared/mapstructio.inc [new file with mode: 0644]
src/shared/mapstructsizes.inc [new file with mode: 0644]
src/shared/utils.pas [new file with mode: 0644]

index 46e8ea60a02f84e999ce1c6edb494cabd84c7a00..6125b9787042dc1de1aed5da40e45011bca91477 100644 (file)
         <FormatVersion Value="1"/>
       </local>
     </RunParams>
-    <RequiredPackages Count="1">
+    <RequiredPackages Count="2">
       <Item1>
-        <PackageName Value="LCL"/>
+        <PackageName Value="LazOpenGLContext"/>
       </Item1>
+      <Item2>
+        <PackageName Value="LCL"/>
+      </Item2>
     </RequiredPackages>
     <Units Count="40">
       <Unit0>
       <Unit14>
         <Filename Value="f_main.pas"/>
         <IsPartOfProject Value="True"/>
+        <ComponentName Value="MainForm"/>
         <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
       </Unit14>
       <Unit15>
         <Filename Value="g_map.pas"/>
       <Filename Value="../../bin/editor"/>
     </Target>
     <SearchPaths>
-      <IncludeFiles Value="..;../lib/dgl;../engine;../shared;../lib/fmod;$(ProjOutDir)"/>
-      <OtherUnitFiles Value="..;../lib/dgl;../engine;../shared;../lib/fmod"/>
+      <IncludeFiles Value="..;../engine;../shared;../lib/fmod;../lib/vampimg;../lib/vampimg/JpegLib;../lib/vampimg/ZLib;$(ProjOutDir)"/>
+      <OtherUnitFiles Value="..;../engine;../shared;../lib/fmod;../lib/vampimg;../lib/vampimg/JpegLib;../lib/vampimg/ZLib"/>
       <UnitOutputDirectory Value="../../tmp"/>
       <ObjectPath Value=".."/>
     </SearchPaths>
index a0da9cee345627e9a57ab9fcbcab4aab587b794d..647bfae8129308cbab1781174315cc8acacfec16 100644 (file)
@@ -4,7 +4,7 @@ program Editor;
 
 uses
   Forms, Interfaces,
-  dglOpenGL in '../lib/dgl/dglOpenGL.pas',
+  GL, GLExt,
   e_graphics in '../engine/e_graphics.pas',
   e_log in '../engine/e_log.pas',
   e_textures in '../engine/e_textures.pas',
@@ -37,10 +37,13 @@ uses
   f_packmap in 'f_packmap.pas' {PackMapForm},
   f_maptest in 'f_maptest.pas' {MapTestForm},
   f_choosetype in 'f_choosetype.pas' {ChooseTypeForm},
-  fmod in '../lib/fmod/fmod.pas',
-  fmoderrors in '../lib/fmod/fmoderrors.pas',
-  fmodpresets in '../lib/fmod/fmodpresets.pas',
-  fmodtypes in '../lib/fmod/fmodtypes.pas',
+  fmod,
+  fmoderrors,
+  fmodpresets,
+  fmodtypes,
+  ImagingTypes,
+  Imaging,
+  ImagingUtility,
   g_language in 'g_language.pas',
   f_selectlang in 'f_selectlang.pas' {SelectLanguageForm};
 
index 4efa9878cc1be4d8c082dd6f64beb944b94a6131..2dfc49d720e0e7c8505a828866e0fc40f83c9c66 100644 (file)
@@ -105,7 +105,8 @@ function CreateSoundWAD(Resource: String): Boolean;
 var
   WAD: TWADEditor_1;
   FileName, SectionName, ResourceName: String;
-  ResLength, sz: Integer;
+  ResLength: Integer;
+  sz: LongWord;
   soundExInfo: FMOD_CREATESOUNDEXINFO;
   res: FMOD_RESULT;
 
@@ -126,10 +127,10 @@ begin
       sz := SizeOf(FMOD_CREATESOUNDEXINFO);
       FillMemory(@soundExInfo, sz, 0);
       soundExInfo.cbsize := sz;
-      soundExInfo.length := ResLength;
+      soundExInfo.length := LongWord(ResLength);
 
       res := FMOD_System_CreateStream(F_System, SoundData,
-        FMOD_LOOP_OFF + FMOD_2D + FMOD_SOFTWARE + FMOD_OPENMEMORY,
+        FMOD_LOOP_OFF or FMOD_2D or FMOD_OPENMEMORY,
         @soundExInfo, Sound);
         
       if res <> FMOD_OK then
index f9ebe0a83fc499ab110bf1718250b61d94178f0a..ce9a073d40b5e6fafddff15b492908cfb9b0f213 100644 (file)
@@ -37,13 +37,13 @@ var
   AddTextureForm: TAddTextureForm;
 
 function IsAnim(Res: String): Boolean;
-function GetFrame(Res: String; var Data: Pointer;
+function GetFrame(Res: String; var Data: Pointer; var DataLen: Integer;
                   var Width, Height: Word): Boolean;
 
 implementation
 
 uses
-  BinEditor, WADEDITOR, f_main, g_textures, WADSTRUCT, CONFIG, g_map,
+  BinEditor, WADEDITOR, WADSTRUCT, f_main, g_textures, CONFIG, g_map,
   g_language;
 
 type
@@ -169,7 +169,7 @@ begin
   Result := ok;
 end;
 
-function GetFrame(Res: String; var Data: Pointer;
+function GetFrame(Res: String; var Data: Pointer; var DataLen: Integer;
                   var Width, Height: Word): Boolean;
 var
   AnimWAD:      Pointer;
@@ -232,6 +232,8 @@ begin
     Exit;
   end;
 
+  DataLen := Len;
+
   Height := config.ReadInt('', 'frameheight', 0);
   Width := config.ReadInt('', 'framewidth', 0);
 
index 58c22a2c9caf246492beaca129eda9a4d2084ece..fcc7377e6df71a29c4e52a7d2adb963b3cb7cd50 100644 (file)
@@ -1,21 +1,19 @@
 object MainForm: TMainForm
   Left = 434
+  Height = 480
   Top = 255
-  AutoScroll = False
+  Width = 672
   Caption = '2'
-  ClientHeight = 554
-  ClientWidth = 792
+  ClientHeight = 460
+  ClientWidth = 672
   Color = clBtnFace
   Constraints.MinHeight = 480
   Constraints.MinWidth = 672
-  Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
   Font.Height = -11
   Font.Name = 'MS Sans Serif'
-  Font.Style = []
   KeyPreview = True
   Menu = MainMenu
-  Position = poDefault
   OnActivate = FormActivate
   OnCloseQuery = FormCloseQuery
   OnCreate = FormCreate
@@ -23,303 +21,333 @@ object MainForm: TMainForm
   OnKeyDown = FormKeyDown
   OnKeyUp = FormKeyUp
   OnResize = FormResize
-  PixelsPerInch = 96
+  Position = poDefault
+  LCLVersion = '1.6.0.4'
   object Splitter1: TSplitter
-    Left = 640
+    Left = 518
+    Height = 289
     Top = 34
-    Height = 387
+    Width = 5
     Align = alRight
     Beveled = True
     MinSize = 64
     OnCanResize = Splitter1CanResize
+    ResizeAnchor = akRight
   end
   object Splitter2: TSplitter
+    Cursor = crVSplit
     Left = 0
-    Top = 421
-    Width = 792
     Height = 3
-    Cursor = crVSplit
+    Top = 323
+    Width = 672
     Align = alBottom
     MinSize = 64
     OnCanResize = Splitter2CanResize
+    ResizeAnchor = akBottom
   end
   object PanelProps: TPanel
-    Left = 643
+    Left = 523
+    Height = 289
     Top = 34
     Width = 149
-    Height = 387
     Align = alRight
     BevelInner = bvRaised
     BevelOuter = bvLowered
+    ClientHeight = 289
+    ClientWidth = 149
     TabOrder = 0
     object vleObjectProperty: TValueListEditor
-      Left = 0
-      Top = 0
+      Left = 2
+      Height = 255
+      Top = 2
       Width = 145
-      Height = 353
       Align = alClient
       Constraints.MinWidth = 145
       DefaultColWidth = 60
       DefaultRowHeight = 16
-      DisplayOptions = [doColumnTitles, doAutoColResize]
-      DropDownRows = 11
-      FixedCols = 1
-      Font.Charset = DEFAULT_CHARSET
       Font.Color = clWindowText
       Font.Height = -12
       Font.Name = 'MS Sans Serif'
-      Font.Style = []
       ParentFont = False
+      RowCount = 2
       ScrollBars = ssVertical
       TabOrder = 0
-      TitleCaptions.Strings = (
-        'Свойство'
-        'Значение')
+      TitleFont.Color = clWindowText
+      TitleFont.Height = -12
+      TitleFont.Name = 'MS Sans Serif'
       OnEditButtonClick = vleObjectPropertyEditButtonClick
       OnEnter = vleObjectPropertyEnter
       OnExit = vleObjectPropertyExit
-      OnGetPickList = vleObjectPropertyGetPickList
       OnKeyDown = vleObjectPropertyKeyDown
+      DisplayOptions = [doColumnTitles, doAutoColResize]
+      DropDownRows = 11
+      Strings.Strings = (
+        ''
+      )
+      TitleCaptions.Strings = (
+        'Свойство'
+        'Значение'
+      )
+      OnGetPickList = vleObjectPropertyGetPickList
       ColWidths = (
-        70
-        71)
+        62
+        62
+      )
     end
     object PanelPropApply: TPanel
-      Left = 0
-      Top = 353
-      Width = 145
+      Left = 2
       Height = 30
+      Top = 257
+      Width = 145
       Align = alBottom
       BevelOuter = bvNone
+      ClientHeight = 30
+      ClientWidth = 145
       TabOrder = 1
       object bApplyProperty: TButton
         Left = 6
+        Height = 25
         Top = 1
         Width = 129
-        Height = 25
         Caption = 'Применить свойства'
-        TabOrder = 0
         OnClick = bApplyPropertyClick
+        TabOrder = 0
       end
     end
   end
   object PanelMap: TPanel
     Left = 0
+    Height = 289
     Top = 34
-    Width = 640
-    Height = 387
+    Width = 518
     Align = alClient
     BevelOuter = bvNone
+    ClientHeight = 289
+    ClientWidth = 518
     TabOrder = 1
-    object RenderPanel: TPanel
+    object sbHorizontal: TScrollBar
+      Left = 0
+      Height = 13
+      Top = 276
+      Width = 518
+      Align = alBottom
+      LargeChange = 256
+      Max = 0
+      PageSize = 0
+      SmallChange = 16
+      TabOrder = 0
+      TabStop = False
+      OnScroll = sbHorizontalScroll
+    end
+    object sbVertical: TScrollBar
+      Left = 504
+      Height = 276
+      Top = 0
+      Width = 14
+      Align = alRight
+      Kind = sbVertical
+      LargeChange = 256
+      Max = 0
+      PageSize = 0
+      SmallChange = 16
+      TabOrder = 1
+      TabStop = False
+      OnScroll = sbVerticalScroll
+    end
+    object RenderPanel: TOpenGLControl
       Left = 0
+      Height = 276
       Top = 0
-      Width = 626
-      Height = 374
+      Width = 504
       Align = alClient
-      BevelInner = bvRaised
-      BevelOuter = bvLowered
-      TabOrder = 0
+      AlphaBits = 8
       OnMouseDown = RenderPanelMouseDown
       OnMouseMove = RenderPanelMouseMove
       OnMouseUp = RenderPanelMouseUp
+      OnPaint = RenderPanelPaint
       OnResize = RenderPanelResize
       object pLoadProgress: TPanel
         Left = 142
+        Height = 49
         Top = 94
         Width = 185
-        Height = 49
+        ClientHeight = 49
+        ClientWidth = 185
         TabOrder = 0
         Visible = False
         object lLoad: TLabel
           Left = 6
+          Height = 13
           Top = 30
           Width = 169
-          Height = 13
           AutoSize = False
+          ParentColor = False
         end
         object pbLoad: TProgressBar
           Left = 6
+          Height = 16
           Top = 6
           Width = 169
-          Height = 16
           Step = 1
           TabOrder = 0
         end
       end
     end
-    object sbHorizontal: TScrollBar
-      Left = 0
-      Top = 372
-      Width = 640
-      Height = 13
-      Align = alBottom
-      LargeChange = 256
-      Max = 0
-      PageSize = 0
-      SmallChange = 16
-      TabOrder = 1
-      TabStop = False
-      OnScroll = sbHorizontalScroll
-    end
-    object sbVertical: TScrollBar
-      Left = 624
-      Top = 0
-      Width = 14
-      Height = 374
-      Align = alRight
-      Kind = sbVertical
-      LargeChange = 256
-      Max = 0
-      PageSize = 0
-      SmallChange = 16
-      TabOrder = 2
-      TabStop = False
-      OnScroll = sbVerticalScroll
-    end
   end
   object StatusBar: TStatusBar
     Left = 0
-    Top = 535
-    Width = 792
-    Height = 19
+    Height = 23
+    Top = 437
+    Width = 672
     AutoHint = True
-    Panels = <
+    Panels = <    
       item
         Width = 600
-      end
+      end    
       item
         Width = 50
       end>
-    SizeGrip = False
     SimplePanel = False
+    SizeGrip = False
   end
   object PanelObjs: TPanel
     Left = 0
-    Top = 424
-    Width = 792
     Height = 111
+    Top = 326
+    Width = 672
     Align = alBottom
     BevelInner = bvRaised
     BevelOuter = bvLowered
+    ClientHeight = 111
+    ClientWidth = 672
     Constraints.MinHeight = 111
     TabOrder = 3
     object pcObjects: TPageControl
-      Left = 0
-      Top = 0
-      Width = 788
+      Left = 2
       Height = 107
+      Top = 2
+      Width = 668
       ActivePage = tsPanels
       Align = alClient
       Images = ImageList
+      TabIndex = 0
       TabOrder = 0
       object tsPanels: TTabSheet
         Caption = 'Панели'
+        ClientHeight = 80
+        ClientWidth = 660
         ImageIndex = 12
         object lbTextureList: TListBox
           Left = 206
-          Top = 0
-          Width = 362
-          Height = 78
+          Height = 80
           Hint = 'Список текстур'
-          Style = lbOwnerDrawFixed
+          Top = 0
+          Width = 242
           Align = alClient
           Constraints.MaxHeight = 600
           Constraints.MinHeight = 70
           ItemHeight = 13
-          TabOrder = 0
           OnClick = lbTextureListClick
+          Style = lbOwnerDrawFixed
+          TabOrder = 0
         end
         object PanelTextures: TPanel
-          Left = 568
+          Left = 448
+          Height = 80
           Top = 0
           Width = 212
-          Height = 78
           Align = alRight
           BevelOuter = bvNone
+          ClientHeight = 80
+          ClientWidth = 212
           TabOrder = 1
           object LabelTxH: TLabel
             Left = 33
+            Height = 13
             Top = 22
             Width = 91
-            Height = 13
             Caption = 'Высота текстуры:'
+            ParentColor = False
           end
           object LabelTxW: TLabel
             Left = 33
+            Height = 13
             Top = 0
             Width = 92
-            Height = 13
             Caption = 'Ширина текстуры:'
+            ParentColor = False
           end
           object lTextureHeight: TLabel
             Left = 139
+            Height = 13
             Top = 22
             Width = 33
-            Height = 13
             AutoSize = False
+            ParentColor = False
           end
           object lTextureWidth: TLabel
             Left = 139
+            Height = 13
             Top = 0
             Width = 33
-            Height = 13
             AutoSize = False
+            ParentColor = False
           end
           object cbPreview: TCheckBox
             Left = 35
+            Height = 19
             Top = 54
-            Width = 169
-            Height = 17
+            Width = 165
             Caption = 'Предварительный просмотр'
             TabOrder = 0
           end
           object bbAddTexture: TBitBtn
             Left = 3
-            Top = 0
-            Width = 25
             Height = 25
             Hint = 'Добавить текстуру в список'
+            Top = 0
+            Width = 25
             Caption = '+'
-            TabOrder = 1
             OnClick = bbAddTextureClick
+            TabOrder = 1
           end
           object bbRemoveTexture: TBitBtn
             Left = 3
-            Top = 24
-            Width = 25
             Height = 25
             Hint = 'Удалить текстуру из списка'
+            Top = 24
+            Width = 25
             Caption = '-'
-            TabOrder = 2
             OnClick = bbRemoveTextureClick
+            TabOrder = 2
           end
           object bClearTexture: TButton
             Left = 3
-            Top = 48
-            Width = 25
             Height = 25
             Hint = 'Убрать выбор текстуры'
-            TabOrder = 3
+            Top = 48
+            Width = 25
             OnClick = bClearTextureClick
+            TabOrder = 3
           end
         end
         object PanelPanelType: TPanel
           Left = 0
+          Height = 80
           Top = 0
           Width = 206
-          Height = 78
           Align = alLeft
           BevelOuter = bvNone
+          ClientHeight = 80
+          ClientWidth = 206
           TabOrder = 2
           object lbPanelType: TListBox
             Left = 0
+            Height = 80
+            Hint = 'Тип панели'
             Top = 0
             Width = 201
-            Height = 78
-            Hint = 'Тип панели'
             Align = alLeft
-            ItemHeight = 13
             Items.Strings = (
               'Стена'
               'Фон'
@@ -332,22 +360,25 @@ object MainForm: TMainForm
               'Кислота 2'
               'Лифт вверх'
               'Лифт вниз'
-              'Блокиратор монстров')
+              'Блокиратор монстров'
+            )
+            ItemHeight = 13
             TabOrder = 0
           end
         end
       end
       object tsItems: TTabSheet
         Caption = 'Предметы'
+        ClientHeight = 0
+        ClientWidth = 0
         ImageIndex = 4
         object lbItemList: TListBox
           Left = 0
-          Top = 0
-          Width = 201
           Height = 78
           Hint = 'Список предметов'
+          Top = 0
+          Width = 201
           Align = alLeft
-          ItemHeight = 13
           Items.Strings = (
             'Аптечка'
             'Большая аптечка'
@@ -380,37 +411,40 @@ object MainForm: TMainForm
             'Зеленый ключ'
             'Синий ключ'
             'Бутылек здоровья'
-            'Часть брони')
+            'Часть брони'
+          )
+          ItemHeight = 13
           TabOrder = 0
         end
         object cbOnlyDM: TCheckBox
           Left = 208
+          Height = 17
           Top = 0
           Width = 97
-          Height = 17
           Caption = 'Только в DM'
           TabOrder = 1
         end
         object cbFall: TCheckBox
           Left = 208
+          Height = 17
           Top = 16
           Width = 97
-          Height = 17
           Caption = 'Падает'
           TabOrder = 2
         end
       end
       object tsMonsters: TTabSheet
         Caption = 'Монстры'
+        ClientHeight = 0
+        ClientWidth = 0
         ImageIndex = 15
         object lbMonsterList: TListBox
           Left = 0
-          Top = 0
-          Width = 201
           Height = 78
           Hint = 'Список монстров'
+          Top = 0
+          Width = 201
           Align = alLeft
-          ItemHeight = 13
           Items.Strings = (
             'Демон'
             'Бес'
@@ -431,14 +465,16 @@ object MainForm: TMainForm
             'Рыба'
             'Бочка'
             'Робот'
-            'Приколист')
+            'Приколист'
+          )
+          ItemHeight = 13
           TabOrder = 0
         end
         object rbMonsterLeft: TRadioButton
           Left = 208
+          Height = 17
           Top = 0
           Width = 113
-          Height = 17
           Caption = 'Влево'
           Checked = True
           TabOrder = 1
@@ -446,24 +482,25 @@ object MainForm: TMainForm
         end
         object rbMonsterRight: TRadioButton
           Left = 208
+          Height = 17
           Top = 16
           Width = 113
-          Height = 17
           Caption = 'Вправо'
           TabOrder = 2
         end
       end
       object tsAreas: TTabSheet
         Caption = 'Области'
+        ClientHeight = 0
+        ClientWidth = 0
         ImageIndex = 3
         object lbAreasList: TListBox
           Left = 0
-          Top = 0
-          Width = 201
           Height = 78
           Hint = 'Список областей'
+          Top = 0
+          Width = 201
           Align = alLeft
-          ItemHeight = 13
           Items.Strings = (
             '1ый игрок'
             '2ой игрок'
@@ -472,14 +509,16 @@ object MainForm: TMainForm
             'Синий флаг'
             'DOM флаг'
             'Красная команда'
-            'Синяя команда')
+            'Синяя команда'
+          )
+          ItemHeight = 13
           TabOrder = 0
         end
         object rbAreaLeft: TRadioButton
           Left = 208
+          Height = 17
           Top = 0
           Width = 113
-          Height = 17
           Caption = 'Влево'
           Checked = True
           TabOrder = 1
@@ -487,24 +526,25 @@ object MainForm: TMainForm
         end
         object rbAreaRight: TRadioButton
           Left = 208
+          Height = 17
           Top = 16
           Width = 113
-          Height = 17
           Caption = 'Вправо'
           TabOrder = 2
         end
       end
       object tsTriggers: TTabSheet
         Caption = 'Триггеры'
+        ClientHeight = 0
+        ClientWidth = 0
         ImageIndex = 6
         object lbTriggersList: TListBox
           Left = 0
-          Top = 0
-          Width = 201
           Height = 78
           Hint = 'Список триггеров'
+          Top = 0
+          Width = 201
           Align = alLeft
-          ItemHeight = 13
           Items.Strings = (
             'Выход'
             'Телепортация'
@@ -526,125 +566,137 @@ object MainForm: TMainForm
             'Звук'
             'Создать монстра'
             'Создать предмет'
-            'Музыка')
+            'Музыка'
+          )
+          ItemHeight = 13
           TabOrder = 0
         end
         object clbActivationType: TCheckListBox
           Left = 201
-          Top = 0
-          Width = 128
           Height = 78
           Hint = 'Тип активации триггера'
+          Top = 0
+          Width = 128
           Align = alLeft
-          ItemHeight = 13
           Items.Strings = (
             'Игрок близко'
             'Монстр близко'
             'Игрок нажал'
             'Монстр нажал'
             'Выстрел'
-            'Монстров нет')
+            'Монстров нет'
+          )
+          ItemHeight = 17
           TabOrder = 1
+          Data = {
+            06000000000000000000
+          }
         end
         object clbKeys: TCheckListBox
           Left = 329
-          Top = 0
-          Width = 128
           Height = 78
           Hint = 'Ключи для активации'
+          Top = 0
+          Width = 128
           Align = alLeft
-          ItemHeight = 13
           Items.Strings = (
             'Красный ключ'
             'Зеленый ключ'
             'Синий ключ'
             'Красная команда'
-            'Синяя команда')
+            'Синяя команда'
+          )
+          ItemHeight = 17
           TabOrder = 2
+          Data = {
+            050000000000000000
+          }
         end
       end
     end
   end
   object MainToolBar: TToolBar
     Left = 0
-    Top = 0
-    Width = 792
     Height = 34
+    Top = 0
+    Width = 672
     ButtonHeight = 31
     ButtonWidth = 31
     Caption = 'MainToolBar'
-    Flat = True
     Images = ilToolbar
     TabOrder = 4
     object tbNewMap: TToolButton
-      Left = 0
-      Top = 0
+      Left = 1
       Hint = 'Очистить карту'
+      Top = 2
       Caption = 'tbNewMap'
       ImageIndex = 0
       OnClick = aNewMapExecute
     end
     object tbOpenMap: TToolButton
-      Left = 31
-      Top = 0
+      Left = 32
       Hint = 'Открыть карту'
+      Top = 2
       Caption = 'tbOpenMap'
       ImageIndex = 1
       OnClick = aOpenMapExecute
     end
     object tbSaveMap: TToolButton
-      Left = 62
-      Top = 0
+      Left = 63
       Hint = 'Сохранить карту'
+      Top = 2
       Caption = 'tbSaveMap'
       ImageIndex = 2
       OnClick = aSaveMapExecute
     end
     object tbOpenWadMap: TToolButton
-      Left = 93
-      Top = 0
+      Left = 94
       Hint = 'Открыть другую карты из этого же WAD''а'
+      Top = 2
       Caption = 'tbOpenWadMap'
       ImageIndex = 8
       OnClick = miOpenWadMapClick
     end
     object tbLine1: TToolButton
-      Left = 124
-      Top = 0
+      Left = 125
+      Height = 31
+      Top = 2
       Width = 8
       Caption = 'tbLine1'
       ImageIndex = 3
       Style = tbsSeparator
     end
     object tbShowMap: TToolButton
-      Left = 132
-      Top = 0
+      Left = 133
       Hint = 'Показать мини-карту'
+      Top = 2
       Caption = 'tbShowMap'
       ImageIndex = 3
       OnClick = miMiniMapClick
     end
     object tbLine2: TToolButton
-      Left = 163
-      Top = 0
+      Left = 164
+      Height = 31
+      Top = 2
       Width = 8
       Caption = 'tbLine2'
       ImageIndex = 6
       Style = tbsSeparator
     end
     object tbShow: TToolButton
-      Left = 171
-      Top = 0
+      Left = 172
       Hint = 'Отрисовка панелей/объектов'
+      Top = 2
       Caption = 'tbShow'
       DropdownMenu = pmShow
       ImageIndex = 4
-      Style = tbsDropDown
       OnClick = tbShowClick
+      Style = tbsDropDown
     end
     object tbLine3: TToolButton
       Left = 215
-      Top = 0
+      Height = 31
+      Top = 2
       Width = 8
       Caption = 'tbLine3'
       ImageIndex = 7
@@ -652,23 +704,24 @@ object MainForm: TMainForm
     end
     object tbGridOn: TToolButton
       Left = 223
-      Top = 0
       Hint = 'Включить/Отключить отображение сетки'
+      Top = 2
       Caption = 'tbGridOn'
       ImageIndex = 6
       OnClick = tbGridOnClick
     end
     object tbGrid: TToolButton
       Left = 254
-      Top = 0
       Hint = 'Изменить шаг сетки'
+      Top = 2
       Caption = 'tbGrid'
       ImageIndex = 5
       OnClick = miSwitchGridClick
     end
     object tbLine4: TToolButton
       Left = 285
-      Top = 0
+      Height = 31
+      Top = 2
       Width = 8
       Caption = 'tbLine4'
       ImageIndex = 7
@@ -676,97 +729,598 @@ object MainForm: TMainForm
     end
     object tbTestMap: TToolButton
       Left = 293
-      Top = 0
       Hint = 'Тест карты в игре'
+      Top = 2
       Caption = 'tbTestMap'
       DropdownMenu = pmMapTest
       ImageIndex = 7
-      Style = tbsDropDown
       OnClick = miTestMapClick
+      Style = tbsDropDown
     end
   end
   object OpenDialog: TOpenDialog
-    DefaultExt = 'wad'
-    Filter = 
-      'Карты Doom 2D: Forever (*.wad)|*.wad|Старые карты Doom 2D: Forev' +
-      'er (*.ini)|*.ini|Все файлы (*.*)|*.*'
+    DefaultExt = '.wad'
+    Filter = 'Карты Doom 2D: Forever (*.wad)|*.wad|Старые карты Doom 2D: Forever (*.ini)|*.ini|Все файлы (*.*)|*.*'
     Options = [ofHideReadOnly, ofNoChangeDir, ofPathMustExist, ofFileMustExist, ofEnableSizing, ofDontAddToRecent]
-    Left = 32
-    Top = 64
+    left = 32
+    top = 64
   end
   object ImageList: TImageList
-    Left = 32
-    Top = 101
+    left = 32
+    top = 101
     Bitmap = {
-      494C01011E002200040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
-      0000000000003600000028000000400000009000000001002000000000000090
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      4C691E000000100000001000000000000000737373FF737373FF737373FF7373
+      73FF7B7B7BFF7B7B7BFF7B7B7BFF848484FF848484FF848484FF848484FF8484
+      84FF000000000000000000000000000000006B6B6BFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCECECEFFFFFFFFFFB5D6
+      CEFF737373FF0000000000000000000000006B6B6BFFFFFFFFFFE7FFF7FFE7FF
+      F7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7F7FFB5B5B5FFFFFFFFFFD6F7
+      EFFFB5D6CEFF6B6B6BFF00000000000000006B6B6BFFFFFFFFFFE7FFF7FFE7FF
+      F7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7F7FFA5A5A5FFFFFFFFFFFFFF
+      FFFFFFFFFFFF5A5A5AFF00000000000000006B6B6BFFFFFFFFFFDEF7F7FFDEF7
+      F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFF7F7F7FF949494FF8C8C8CFF7373
+      73FF5A5A5AFF5A5A5AFF00000000000000006B6B6BFFFFFFFFFFDEF7F7FFDEF7
+      F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFF7F7F7FFD6D6D6FFC6C6C6FFB5B5
+      B5FF9C9C9CFF525252FF00000000000000006B6B6BFFFFFFFFFFDEF7F7FFDEF7
+      F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFCEEFE7FFC6DE
+      DEFFDEDEDEFF525252FF0000000000000000636363FFFFFFFFFFD6EFEFFFD6EF
+      EFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EF
+      EFFFFFFFFFFF4A4A4AFF00000000000000005A5A5AFFFFFFFFFFD6EFE7FFD6EF
+      E7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EF
+      E7FFFFFFFFFF424242FF00000000000000005A5A5AFFFFFFFFFFD6EFE7FFD6EF
+      E7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EF
+      E7FFFFFFFFFF424242FF00000000000000004A4A4AFFFFFFFFFFCEE7E7FFCEE7
+      E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7
+      E7FFFFFFFFFF393939FF00000000000000004A4A4AFFFFFFFFFFCEE7E7FFCEE7
+      E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7
+      E7FFFFFFFFFF313131FF00000000000000004A4A4AFFFFFFFFFFBDDED6FFBDDE
+      D6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDE
+      D6FFFFFFFFFF313131FF0000000000000000424242FFFFFFFFFFC6DEDEFFC6DE
+      DEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+      DEFFFFFFFFFF313131FF0000000000000000424242FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFF292929FF00000000000000006B6B6BFF292929FF212121FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+      18FF181818FF4A4A4AFF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000008C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF00000000000000000000000000000000000000000000
+      000000000000000000000000000000000000949494FF9C9C9CFF9C9C9CFF9C9C
+      9CFF9C9C9CFF9C9C9CFF949494FF000000000000000000000000000000000000
+      0000000000000000000000000000000000008C8C8CFF949494FF8C948CFF8C94
+      94FF949494FF949494FF8C8C8CFF7B7B7BFF7B7B7BFF737373FF737373FF7373
+      73FF737373FF000000000000000000000000848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF848484FF848C84FF848C
+      84FF848C84FF848484FF00000000000000007B7B7BFF848484FF848484FF8484
+      84FF848484FF848484FF848484FF7B7B7BFF848C84FFD6EFE7FFDEF7F7FFDEF7
+      F7FFDEF7F7FFE7F7F7FF7B9494FF00000000737373FF847B7BFF7B7B7BFF6B6B
+      6BFF737373FF737373FF737373FF6B736BFFADC6BDFFCEE7E7FFC6DED6FFC6DE
+      D6FFC6DED6FFC6E7DEFF7B9494FF000000006B6B6BFF7B7373FF6B6B6BFF7B84
+      84FFB5CECEFFB5CECEFFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6
+      D6FFBDDED6FFCEE7DEFF7B9494FF00000000636363FF6B6B6BFF636363FFA5B5
+      B5FFBDD6D6FFBDD6D6FFB5D6CEFFB5D6CEFFB5CECEFFB5CECEFFB5CECEFFB5D6
+      CEFFBDD6D6FFC6DEDEFF7B9494FF000000005A5A5AFF5A5A5AFF737B7BFFB5CE
+      C6FFADC6BDFFADC6BDFFADC6BDFFADC6C6FFADC6BDFFADC6BDFFB5CEC6FFB5CE
+      CEFFBDDED6FF7B9494FF0000000000000000525252FF5A5A5AFF7B8C8CFFADC6
+      C6FFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFADC6
+      C6FFBDD6CEFF7B9494FF00000000000000004A4A4AFF5A5A5AFF94B5ADFFA5BD
+      B5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BD
+      BDFFADCEC6FF7B9494FF0000000000000000424242FF5A6363FF9CB5ADFF94AD
+      ADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF9CB5B5FF9CBD
+      B5FFA5BDBDFF7B9494FF0000000000000000393939FF7B9494FF94ADADFF94AD
+      A5FF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94ADADFF94B5ADFF94B5
+      B5FF7B9494FF000000000000000000000000393939FF7B8C8CFF849C94FF7B94
+      94FF7B9494FF7B9494FF7B9494FF7B9494FF7B9494FF7B9494FF7B9494FF7B94
+      94FF7B9494FF0000000000000000000000004A4A52FF4A4A52FF4A4A52FF4A4A
+      52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A
+      52FF7B9494FF000000000000000000000000848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF00000000848484FFDEF7F7FFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7
+      F7FF9CB5ADFFB5CECEFF737373FF7B7B7BFFD6F7EFFFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFF94ADA5FFADCEC6FF6B6B6BFF7B7B7BFFD6EFE7FFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFF94ADADFFADC6C6FF636363FF7B7B7BFFCEE7DEFFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFF8CA5A5FFADC6C6FF5A5A5AFF6B6B6BFFADCEC6FF9CB5ADFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7
+      F7FF7B9C94FF9CB5B5FF525252FF636363FFADC6C6FF94ADADFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7
+      F7FF7B9494FF94ADADFF4A4A4AFF5A5A5AFFADC6BDFF94ADA5FFE7E7E7FFF7F7
+      F7FFF7F7F7FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFF7F7F7FFEFEFEFFFDEDE
+      DEFF73948CFF94ADADFF4A4A4AFF5A5A5AFFA5C6BDFF8CA59CFF8CA5A5FF849C
+      9CFF7B948CFF738C84FF738C84FF738C84FF738C8CFF738C8CFF738C8CFF738C
+      8CFF6B8484FF8CADA5FF424242FF525252FFA5BDB5FFA5BDB5FFA5BDB5FF94B5
+      ADFF8CADA5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+      A5FF8CA5A5FF8CA5A5FF424242FF525252FF9CB5B5FF9CB5ADFF9C9C9CFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF7B7B
+      7BFF849C9CFF849C9CFF393939FF4A4A4AFF94ADA5FF8CA5A5FF7B7B7BFFFFFF
+      FFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF6B6B
+      6BFF849C9CFF849C9CFF393939FF4A4A4AFF94ADA5FF8CA5A5FF7B7B7BFFFFFF
+      FFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF6B6B
+      6BFF849C9CFF849C9CFF393939FF424242FF7B9494FF7B9494FF6B6B6BFFFFFF
+      FFFFE7E7E7FFA5BDB5FFFFFFFFFFFFFFFFFFEFEFEFFFE7E7E7FFE7E7E7FF6B6B
+      6BFF7B9494FF7B9494FF292929FF393939FF7B9494FF7B9494FF636363FFE7E7
+      E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FFD6D6D6FFE7E7E7FF5A5A
+      5AFF7B9494FF7B9494FF292929FF00000000292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000849CB5FF849CB5FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000849CB5FF315284FF000052FF0000
+      52FF000052FF000052FF000052FF000000000000000000000000000000000000
+      000000000000000000000000000000000000849CB5FF315284FF0800A5FF0800
+      A5FF0800A5FF08008CFF0800C6FF000052FF000052FF000052FF000052FF0000
+      52FF000052FF000000000000000000000000849CB5FF315284FF0800A5FF0800
+      A5FF08008CFF0800C6FF0800C6FF08008CFF0800A5FF0800A5FF0800A5FF0000
+      52FF00000000000000000000000000000000849CB5FF315284FF0800A5FF0800
+      A5FF0800A5FF08008CFF0800C6FF08008CFF08008CFF0800A5FF000052FF0000
+      000000000000000000000000000000000000849CB5FF315284FF0800A5FF0800
+      A5FF08008CFF0800C6FF0800C6FF08008CFF0800A5FF000052FF000000000000
+      000000000000000000000000000000000000849CB5FF315284FF0800A5FF0800
+      A5FF0800A5FF08008CFF0800C6FF08008CFF08008CFF000052FF000000000000
+      000000000000000000000000000000000000849CB5FF315284FF08008CFF0800
+      8CFF08008CFF0800C6FF0800C6FF08008CFF0800A5FF0800A5FF000052FF0000
+      000000000000000000000000000000000000849CB5FF315284FF000052FF0000
+      52FF000052FF000052FF000052FF08008CFF08008CFF08008CFF08008CFF0000
+      52FF00000000000000000000000000000000849CB5FF315284FF000000000000
+      0000000000000000000000000000000052FF000052FF000052FF000052FF0000
+      52FF000052FF000000000000000000000000849CB5FF315284FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000849CB5FF315284FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000849CB5FF315284FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000849CB5FF315284FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000315284FF315284FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00004A3939FF4A3939FF4A3939FF4A3939FF4A3939FF4A3939FF000000000000
+      0000000000000000000000000000000000000000000000000000080000FF2118
+      18FF000000FF180000FF180000FF210000FF210000FF100000FF210808FF0800
+      00FF0000000000000000000000000000000000000000080000FF080000FF1000
+      00FF520000FF9C0000FF9C0000FF9C0000FF9C0000FF730000FF4A0000FF1800
+      00FF080000FF000000000000000000000000080000FF080000FF180000FFBD18
+      18FFF74A4AFFF73939FFF74242FFF74242FFFF3939FFF70808FFC60000FF5200
+      00FF210000FF080000FF0000000000000000000000FF840000FF840000FFFF4A
+      4AFFFF9C9CFFFF5252FFFF4A4AFFFF6363FFFF3131FFE70000FFDE0000FFAD00
+      00FF940000FF000000FF000000004A3939FF100000FF840000FFA50000FFDE10
+      10FFFF4A4AFFC61818FFCE0000FFDE0000FF940000FF8C0000FFC60808FFBD00
+      00FF940000FF420000FF421010FF423131FF840000FF840000FFCE0000FFCE10
+      10FFF73939FFA50808FF840000FF8C0000FF630000FFD64242FFF73131FFAD00
+      00FF940000FF730000FF290808FF4A3939FF9C0000FFA50000FFBD0000FFA500
+      00FFCE1010FFE70000FFE70808FFE71010FFC60000FFDE0808FFC60808FF9400
+      00FFA50000FF9C0000FF421010FF523131FF940000FF9C0000FFE70000FFF721
+      21FFF71818FFEF0000FFB50000FF9C0808FFE70000FFF71010FFF72929FFDE00
+      00FFB50000FF940000FF421010FF4A3131FF840000FF9C0000FFCE0000FFE700
+      00FFEF0000FFDE0000FFAD1010FFA51818FFCE0000FFD60000FFEF0000FFDE00
+      00FFB50000FF840000FF310808FF4A3131FF290000FFCE0000FFCE0000FFDE00
+      00FFCE0000FFCE0000FFB51010FFB51010FFCE0000FFBD0000FFDE0000FFBD00
+      00FFAD0000FF630000FF310808FF00000000000000FF000000FFAD0000FFF710
+      10FFC61010FF5A0000FF080000FF080000FF420000FFB50000FFF70808FFC600
+      00FF6B0000FF421818FF0000000000000000080000FF210000FF630000FFCE00
+      00FFAD0000FF630000FF420000FF420000FF5A0000FF9C0000FFBD0000FF9400
+      00FF290000FF080000FF000000000000000000000000080000FF100000FF6B00
+      00FF840000FFAD0000FFEF1010FFEF1818FFBD0000FF8C0000FF730000FF3100
+      00FF080000FF0000000000000000000000000000000000000000080000FF3921
+      21FF210000FF520000FF6B0808FF6B0808FF5A0000FF290000FF291010FF0800
+      00FF000000000000000000000000000000000000000000000000000000000000
+      00004A3939FF4A3939FF4A3939FF4A3939FF4A3939FF4A3939FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000006B8484FF6B8484FF6B8484FF6B8484FF6B8484FF0000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000006B8484FF42635AFF42635AFF42635AFF42635AFF42635AFF6B84
+      84FF000000000000000000000000000000000000000000000000000000000000
+      00006B8484FF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+      5AFF6B8484FF0000000000000000000000000000000000000000000000000000
+      000042635AFF42635AFF294A4AFF294A4AFF294A4AFF294A4AFF294A4AFF4263
+      5AFF42635AFF000000000000000000000000000000006B8484FF000000006B84
+      84FF42635AFF294A4AFF294A4AFF00000000000000000000000000000000294A
+      4AFF42635AFF6B8484FF0000000000000000000000006B8484FF6B8484FF4263
+      5AFF294A4AFF294A4AFF00000000000000000000000000000000000000000000
+      000042635AFF294A4AFF0000000000000000000000006B8484FF42635AFF4263
+      5AFF294A4AFF0000000000000000000000000000000000000000000000000000
+      0000294A4AFF000000000000000000000000000000006B8484FF42635AFF294A
+      4AFF294A4AFF0000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000294A4AFF294A4AFF294A
+      4AFF294A4AFF294A4AFF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000949494FF848484FF7B7B7BFF9C9C
+      9CFF9C9C9CFF9C9C9CFF7B7B7BFF8C8C8CFF9C9C9CFFA5A5A5FF8C8C8CFF7B7B
+      7BFF7B7B7BFF5A5A5AFF00000000000000007B7B7BFF6B6B6BFF636363FF7373
+      73FF737373FF737373FF636363FF6B6B6BFF737373FF848484FF6B6B6BFF6363
+      63FF636363FF424242FF0000000000000000848484FF6B6B6BFF6B6B6BFF7B7B
+      7BFF7B7B7BFF7B7B7BFF424242FF424242FF7B7B7BFF8C8C8CFF737373FF6363
+      63FF6B6B6BFF4A4A4AFF0000000000000000949494FF737373FF6B6B6BFF8484
+      84FF848484FF848484FF292929FF212121FF7B7B7BFF8C8C8CFF7B7B7BFF6B6B
+      6BFF6B6B6BFF4A4A4AFF0000000000000000949494FF737373FF6B6B6BFF8C8C
+      8CFF8C8C8CFF8C8C8CFF212121FF101010FF848484FF949494FF7B7B7BFF6B6B
+      6BFF6B6B6BFF4A4A4AFF00000000000000009C9C9CFF7B7B7BFF6B6B6BFF5252
+      52FF4A4A4AFF636363FF212121FF101010FF636363FF525252FF525252FF6B6B
+      6BFF737373FF525252FF0000000000000000A5A5A5FF848484FF4A6B63FF3939
+      39FF636363FF4A4A4AFF393939FF313131FF424242FF5A5A5AFF212121FF4A6B
+      63FF7B7B7BFF5A5A5AFF00000000000000009C9C9CFF7B7B7BFF8C8C8CFF4242
+      42FF8C8C8CFF8C8C8CFF737373FF737373FF8C8C8CFF949494FF313131FF7373
+      73FF737373FF5A5A5AFF00000000000000009C9C9CFF7B7B7BFF636363FF4242
+      42FF6B6B6BFF8C8C8CFF737373FF7B7B7BFF8C8C8CFF6B6B6BFF393939FF5A5A
+      5AFF737373FF525252FF0000000000000000949494FF737373FF7B7B7BFF8484
+      84FF848484FF848484FF6B6B6BFF737373FF848484FF949494FF7B7B7BFF7373
+      73FF6B6B6BFF4A4A4AFF00000000000000008C8C8CFF6B6B6BFF6B6B6BFF7B7B
+      7BFF7B7B7BFF7B7B7BFF6B6B6BFF6B6B6BFF7B7B7BFF848484FF737373FF6363
+      63FF636363FF4A4A4AFF0000000000000000848484FF6B6B6BFF636363FF7373
+      73FF737373FF737373FF636363FF6B6B6BFF737373FF848484FF6B6B6BFF6363
+      63FF636363FF424242FF00000000000000007B7B7BFF636363FF636363FF6B6B
+      6BFF6B6B6BFF6B6B6BFF5A5A5AFF636363FF6B6B6BFF7B7B7BFF6B6B6BFF5A5A
+      5AFF5A5A5AFF424242FF0000000000000000424242FF393939FF393939FF4242
+      42FF424242FF424242FF313131FF393939FF424242FF424242FF393939FF3939
+      39FF292929FF393939FF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000000000A5A5
+      A5FFA5A5A5FF000000000000000000000000A5A5A5FFA5A5A5FF000000000000
+      0000000000000000000000000000000000000000000000000000000000008484
+      84FFA5A5A5FF000000000000000000000000A5A5A5FF848484FF000000000000
+      0000000000000000000000000000000000000000000000000000000000008484
+      84FFA5A5A5FF000000000000000000000000A5A5A5FF848484FF000000000000
+      0000000000000000000000000000000000000000000000000000000000006B6B
+      6BFF848484FFA5A5A5FF00000000A5A5A5FF848484FF6B6B6BFF000000000000
+      0000000000000000000000000000000000000000000000000000000000004A4A
+      4AFF6B6B6BFFA5A5A5FF00000000A5A5A5FF6B6B6BFF4A4A4AFF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00006B6B6BFF848484FF4A4A4AFF848484FF6B6B6BFF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00004A4A4AFF6B6B6BFF4A4A4AFF6B6B6BFF4A4A4AFF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000004A4A4AFF4A4A4AFF4A4A4AFF0000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000004A6B
+      5AFF6B8C7BFF52846BFF6B9C8CFF6B9C8CFF527363FF526B63FF000000000000
+      00000000000000000000000000000000000000000000000000004A6B5AFF5273
+      63FF00000000315A4AFF4A7B6BFF295A4AFF000000004A7363FF4A6B5AFF0000
+      00000000000000000000000000000000000000000000000000004A6B5AFF0000
+      00000000000000000000426B5AFF000000000000000000000000527B63FF0000
+      00000000000000000000000000000000000000000000294231FF4A7B63FF0000
+      000000000000637B73FF396352FF5A7B6BFF0000000000000000527B63FF395A
+      42FF0000000000000000000000000000000000000000315242FF52846BFF528C
+      6BFF5A8C73FF4A6B5AFF00000000426B5AFF5A8473FF5A9473FF639473FF214A
+      31FF000000000000000000000000000000000000000000000000295239FF315A
+      4AFF295239FF000000000000000000000000295239FF31634AFF214A31FF0000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000737373FF737373FF737373FF737373FF7B7B
+      7BFF848484FF848484FF848484FF000000000000000000000000000000000000
+      00000000000000000000000000006B6B6BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFCECECEFFB5D6CEFF737373FF0000000000000000000000000000
+      00000000000000000000000000006B6B6BFFFFFFFFFFE7FFF7FFE7FFF7FFE7FF
+      F7FFF7F7F7FF737373FF737373FF737373FF737373FF7B7B7BFF848484FF8484
+      84FF848484FF00000000000000006B6B6BFFFFFFFFFFDEF7F7FFDEF7F7FFDEF7
+      F7FFF7F7F7FF6B6B6BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCECE
+      CEFFDEB5BDFF737373FF000000006B6B6BFFFFFFFFFFDEF7F7FFDEF7F7FFDEF7
+      F7FFF7F7F7FF6B6B6BFFFFFFFFFFFFE7EFFFFFE7EFFFFFE7EFFFF7F7F7FFA5A5
+      A5FFFFFFFFFFFFFFFFFF5A5A5AFF6B6B6BFFFFFFFFFFDEF7F7FFDEF7F7FFDEF7
+      F7FFDEF7F7FF6B6B6BFFFFFFFFFFFFDEDEFFFFDEDEFFFFDEDEFFF7F7F7FF9494
+      94FF737373FF5A5A5AFF5A5A5AFF5A5A5AFFFFFFFFFFD6EFE7FFD6EFE7FFD6EF
+      E7FFD6EFE7FF6B6B6BFFFFFFFFFFFFDEDEFFFFDEDEFFFFDEDEFFF7F7F7FFD6D6
+      D6FFB5B5B5FF9C9C9CFF525252FF5A5A5AFFFFFFFFFFD6EFE7FFD6EFE7FFD6EF
+      E7FFD6EFE7FF6B6B6BFFFFFFFFFFFFDEDEFFFFDEDEFFFFDEDEFFFFDEDEFFFFDE
+      DEFFE7C6C6FFDEDEDEFF525252FF4A4A4AFFFFFFFFFFCEE7E7FFCEE7E7FFCEE7
+      E7FFCEE7E7FF5A5A5AFFFFFFFFFFF7D6DEFFF7D6DEFFF7D6DEFFF7D6DEFFF7D6
+      DEFFF7D6DEFFFFFFFFFF424242FF424242FFFFFFFFFFC6DEDEFFC6DEDEFFC6DE
+      DEFFC6DEDEFF5A5A5AFFFFFFFFFFF7D6DEFFF7D6DEFFF7D6DEFFF7D6DEFFF7D6
+      DEFFF7D6DEFFFFFFFFFF424242FF424242FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFF4A4A4AFFFFFFFFFFEFCECEFFEFCECEFFEFCECEFFEFCECEFFEFCE
+      CEFFEFCECEFFFFFFFFFF313131FF6B6B6BFF292929FF212121FF181818FF1818
+      18FF181818FF424242FFFFFFFFFFE7C6C6FFE7C6C6FFE7C6C6FFE7C6C6FFE7C6
+      C6FFE7C6C6FFFFFFFFFF313131FF000000000000000000000000000000000000
+      000000000000424242FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFF292929FF000000000000000000000000000000000000
+      0000000000006B6B6BFF292929FF212121FF181818FF181818FF181818FF1818
+      18FF181818FF181818FF4A4A4AFF000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000737373FF737373FF737373FF848484FF8484
+      84FF848484FF0000000000000000000000000000000000000000000000000000
+      00000000000000000000000000006B6B6BFFFFFFFFFFFFFFFFFFFFFFFFFFCECE
+      CEFFDEB5BDFF737373FF00000000848484FF848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF6B6B6BFFFFFFFFFFFFE7EFFFF7F7F7FFA5A5
+      A5FFFFFFFFFFFFFFFFFF5A5A5AFF848484FF525A5AFF4A5A52FF525A5AFF525A
+      5AFF525A5AFF525A5AFF525A5AFF6B6B6BFFFFFFFFFFFFFFFFFFFFFFFFFF9494
+      94FF737373FF5A5A5AFF5A5A5AFF7B7B7BFF394242FF394242FF394242FF3942
+      42FF394242FF394242FF394242FF6B6B6BFFFFFFFFFF6B8484FFFFFFFFFFFFFF
+      FFFFB5B5B5FF9C9C9CFF525252FF5A5A5AFF313939FF313939FF313939FF3139
+      39FF313939FF313939FF313939FFFFFFFFFF6B8484FF6B8484FF42635AFFFFFF
+      FFFFFFFFFFFFDEDEDEFF525252FF7B7B7BFF212929FF212929FFF7F7F7FFF7F7
+      F7FFF7F7F7FF212929FFF7F7F7FF6B8484FF6B8484FF5A7373FF42635AFF4263
+      5AFFFFFFFFFFFFFFFFFF313131FF5A5A5AFF080808FF212929FFDEE7E7FF6B84
+      84FFDEE7E7FFF7F7F7FF6B8484FF6B8484FF5A7373FF42635AFF42635AFFFFFF
+      FFFFFFFFFFFFFFFFFFFF292929FF5A5A5AFF080808FF080808FFDEDEDEFF6B84
+      84FF6B8484FF6B8484FF6B8484FF5A7373FF42635AFF42635AFFEFEFEFFF1818
+      18FF181818FF181818FF4A4A4AFF525252FFFFFFFFFFFFFFFFFFFFFFFFFF6B84
+      84FF5A7373FF6B8484FF5A7373FF42635AFF42635AFFDEDEDEFF080808FF4242
+      42FF000000000000000000000000525252FFFFFFFFFFEF0000FFFFDEDEFF6B84
+      84FF5A7373FF5A7373FF42635AFF42635AFFFFFFFFFF000000FF000000FF3939
+      39FF0000000000000000000000004A4A4AFFFFFFFFFFD60000FFFFDEDEFF6B84
+      84FF5A7373FF5A7373FF5A7373FF42635AFFFFFFFFFF000000FF000000FF3939
+      39FF0000000000000000000000004A4A4AFFFFFFFFFFBD0000FFFFDEDEFF4A63
+      52FF42635AFF42635AFF42635AFF42635AFF42635AFFDEDEDEFF000000FF3939
+      39FF000000000000000000000000424242FFFFFFFFFF8C0000FFFFDEDEFFFFDE
+      DEFFFFDEDEFFFFDEDEFFFFDEDEFFFFDEDEFFFFFFFFFFDEDEDEFF000000FF2929
+      29FF000000000000000000000000393939FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF000000FF2929
+      29FF000000000000000000000000292929FF292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF292929FF292929FF2121
+      21FF00000000000000000000000000000000000000007B7B7BFF848484FF8484
+      84FF848484FF848484FF848484FF848484FF848484FF848484FF848484FF8484
+      84FF737373FF00000000000000000000000000000000848484FFDEF7F7FFDEF7
+      F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+      F7FF737373FF000000000000000000000000000000007B7B7BFFDEF7F7FFDEF7
+      F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+      F7FF6B6B6BFF000000000000000000000000000000007B7B7BFFD6EFEFFFD6EF
+      EFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EF
+      EFFF636363FF000000000000000000000000000000007B7B7BFFCEE7E7FFCEE7
+      E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7
+      E7FF5A5A5AFF000000000000000000000000000000006B6B6BFFC6DEDEFFC6DE
+      DEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+      DEFF525252FF00000000000000000000000000000000636363FFBDD6D6FFBDD6
+      D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6
+      D6FF4A4A4AFF000000000000000000000000000000005A5A5AFFB5CECEFFB5CE
+      CEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CE
+      CEFF4A4A4AFF000000000000000000000000000000005A5A5AFFADC6C6FFADC6
+      C6FFADC6C6FFADC6C6FFADC6C6FFADC6C6FFADC6C6FFDEF7F7FF7B9C9CFFADC6
+      C6FF424242FF00000000000000000000000000000000525252FFA5BDBDFFA5BD
+      BDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFF7B9C9CFF6B8484FFA5BD
+      BDFF424242FF00000000000000000000000000000000525252FF9CB5B5FF9CB5
+      B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5
+      B5FF393939FF000000000000000000000000000000004A4A4AFF94ADADFF94AD
+      ADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94AD
+      ADFF393939FF000000000000000000000000000000004A4A4AFF8CA5A5FF8CA5
+      A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+      A5FF393939FF00000000000000000000000000000000424242FF849C9CFF849C
+      9CFF849C9CFF849C9CFF849C9CFF849C9CFF849C9CFF849C9CFF849C9CFF849C
+      9CFF292929FF00000000000000000000000000000000393939FF7B9C9CFF7B9C
+      9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C
+      9CFF292929FF00000000000000000000000000000000292929FF292929FF2929
+      29FF292929FF292929FF292929FF292929FF292929FF292929FF292929FF2121
+      21FF292929FF000000000000000000000000737373FF737373FF737373FF7373
+      73FF7B7B7BFF7B7B7BFF7B7B7BFF848484FF848484FF848484FF848484FF8484
+      84FF000000000000000000000000000000006B6B6BFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCECECEFFFFFFFFFFB5D6
+      CEFF737373FF0000000000000000000000006B6B6BFFFFFFFFFFE7FFF7FFE7FF
+      F7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7F7FFB5B5B5FFFFFFFFFFD6F7
+      EFFFB5D6CEFF6B6B6BFF00000000000000006B6B6BFFFFFFFFFFE7FFF7FF4A4A
+      FFFF4A4AFFFFE7FFF7FFE7FFF7FFE7FFF7FFF7F7F7FFA5A5A5FFFFFFFFFFFFFF
+      FFFFFFFFFFFF5A5A5AFF4A4AFFFF000000006B6B6BFFFFFFFFFF4A4AFFFF4A4A
+      FFFF4A4AFFFFDEF7F7FFDEF7F7FFDEF7F7FFF7F7F7FF949494FF8C8C8CFF7373
+      73FF5A5A5AFF4A4AFFFF4A4AFFFF000000006B6B6BFFFFFFFFFFB5B5B5FF4A4A
+      FFFF4A4AFFFF4A4AFFFFDEF7F7FFDEF7F7FFF7F7F7FFD6D6D6FFC6C6C6FFB5B5
+      B5FF4A4AFFFF4A4AFFFF4A4AFFFF000000006B6B6BFFFFFFFFFFDEF7F7FFB5B5
+      B5FF4A4AFFFF4A4AFFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFCEEFE7FF4A4A
+      FFFF4A4AFFFF4A4AFFFF0000000000000000636363FFFFFFFFFFD6EFEFFFD6EF
+      EFFFB5B5B5FF4A4AFFFF4A4AFFFFD6EFEFFFD6EFEFFFD6EFEFFF4A4AFFFF4A4A
+      FFFF4A4AFFFF4A4A4AFF00000000000000005A5A5AFFFFFFFFFFD6EFE7FFD6EF
+      E7FFD6EFE7FF4A4AFFFF4A4AFFFF4A4AFFFFD6EFE7FF4A4AFFFF4A4AFFFF4A4A
+      FFFFB5B5B5FF424242FF00000000000000005A5A5AFFFFFFFFFFD6EFE7FFD6EF
+      E7FFD6EFE7FFB5B5B5FF4A4AFFFF4A4AFFFF4A4AFFFF4A4AFFFFB5B5B5FFB5B5
+      B5FFFFFFFFFF424242FF00000000000000004A4A4AFFFFFFFFFFCEE7E7FFCEE7
+      E7FFCEE7E7FFCEE7E7FF4A4AFFFF4A4AFFFF4A4AFFFFB5B5B5FFCEE7E7FFCEE7
+      E7FFFFFFFFFF393939FF00000000000000004A4A4AFFFFFFFFFFCEE7E7FFCEE7
+      E7FFCEE7E7FF4A4AFFFF4A4AFFFFB5B5B5FF4A4AFFFF4A4AFFFFCEE7E7FFCEE7
+      E7FFFFFFFFFF313131FF00000000000000004A4A4AFFFFFFFFFFBDDED6FFBDDE
+      D6FF4A4AFFFFB5B5B5FFB5B5B5FFBDDED6FFB5B5B5FF4A4AFFFF4A4AFFFFBDDE
+      D6FFFFFFFFFF313131FF0000000000000000424242FFFFFFFFFFC6DEDEFFC6DE
+      DEFFB5B5B5FFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFB5B5B5FF4A4AFFFF4A4A
+      FFFFFFFFFFFF313131FF0000000000000000424242FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5B5B5FF4A4A
+      FFFF4A4AFFFF292929FF00000000000000006B6B6BFF292929FF212121FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+      18FF4A4AFFFF4A4AFFFF00000000949494FF949494FF949494FF949494FF9494
+      94FF949494FF949494FF949494FF949494FF949494FF949494FF8C8C8CFF0000
+      0000000000000000000000000000949494FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF7B7B7BFF0000
+      0000000000000000000000000000949494FF8C8C8CFFD6D6D6FF949494FF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFFD6D6D6FF949494FF8C8C8CFF7B7B7BFF0000
+      0000000000000000000000000000949494FF8C8C8CFF949494FF424242FF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF949494FF424242FF8C8C8CFF7B7B7BFF0000
+      0000000000000000000000000000949494FF8C8C8CFF8C8C8CFF8C8C8CFF394A
+      7BFF394A7BFF394A7BFF394A7BFF394A7BFF213173FF213173FF394A7BFF394A
+      7BFF394A7BFF394A7BFF213173FF949494FF8C8C8CFF8C8C8CFF8C8C8CFF394A
+      7BFF213173FF213173FF213173FF213173FF10186BFF394A7BFF213173FF2131
+      73FF213173FF213173FF10186BFF949494FF8C8C8CFF8C8C8CFF8C8C8CFF394A
+      7BFF213173FF213173FF213173FF213173FF10186BFF394A7BFF213173FF2131
+      73FF213173FF213173FF10186BFF949494FF8C8C8CFF8C8C8CFF8C8C8CFF2131
+      73FF10186BFF10186BFF10186BFF10186BFF10186BFF10186BFF10186BFF1018
+      6BFF10186BFF10186BFF10186BFF949494FF8C8C8CFFD6D6D6FF949494FF2131
+      73FF394A7BFF394A7BFF394A7BFF394A7BFF394A7BFF394A7BFF394A7BFF394A
+      7BFF394A7BFF394A7BFF10186BFF949494FF8C8C8CFF949494FF424242FF394A
+      7BFF213173FF213173FF213173FF213173FF213173FF213173FF213173FF2131
+      73FF213173FF213173FF10186BFF949494FF8C8C8CFF8C8C8CFF8C8C8CFF394A
+      7BFF213173FF213173FF213173FF213173FF213173FF213173FF213173FF2131
+      73FF213173FF213173FF10186BFF8C8C8CFF7B7B7BFF7B7B7BFF7B7B7BFF2131
+      73FF10186BFF10186BFF10186BFF10186BFF10186BFF10186BFF10186BFF1018
+      6BFF10186BFF10186BFF10186BFF000000000000000000000000000000002131
+      73FF394A7BFF394A7BFF394A7BFF394A7BFF394A7BFF10186BFF394A7BFF394A
+      7BFF394A7BFF394A7BFF10186BFF00000000000000000000000000000000394A
+      7BFF213173FF213173FF213173FF213173FF213173FF10186BFF394A7BFF2131
+      73FF213173FF213173FF10186BFF00000000000000000000000000000000394A
+      7BFF213173FF213173FF213173FF213173FF213173FF10186BFF394A7BFF2131
+      73FF213173FF213173FF10186BFF000000000000000000000000000000002131
+      73FF10186BFF10186BFF10186BFF10186BFF10186BFF10186BFF10186BFF1018
+      6BFF10186BFF10186BFF10186BFF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5A
+      B5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF3139ADFF00000000000000000000
+      00000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF00000000000000000000
+      00000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF00000000000000000000
+      00000000000000000000000000004A5AB5FF3139ADFF3139ADFF5A736BFF5A73
+      6BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF4263
+      5AFF0000000000000000000000004A5AB5FF3139ADFF3139ADFF5A736BFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF294A
+      4AFF0000000000000000000000004A5AB5FF3139ADFF3139ADFF5A736BFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF294A
+      4AFF0000000000000000000000004A5AB5FF3139ADFF3139ADFF5A736BFF4263
+      5AFF42635AFF6B8484FF6B8484FF6B8484FF6B8484FF6B8484FF6B8484FF6B84
+      84FF6B8484FF6B8484FF5A7373FF4A5AB5FF3139ADFF3139ADFF5A736BFF4263
+      5AFF42635AFF6B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF4A5AB5FF3139ADFF3139ADFF5A736BFF4263
+      5AFF42635AFF6B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF3139ADFF10219CFF10219CFF5A736BFF4263
+      5AFF42635AFF6B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF0000000000000000000000005A736BFF4263
+      5AFF42635AFF6B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF0000000000000000000000005A736BFF4263
+      5AFF42635AFF6B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF00000000000000000000000042635AFF294A
+      4AFF294A4AFF6B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF000000000000000000000000000000000000
+      0000000000006B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF000000000000000000000000000000000000
+      0000000000006B8484FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF42635AFF000000000000000000000000000000000000
+      0000000000005A7373FF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+      5AFF42635AFF42635AFF42635AFF848484FF848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF848484FF848484FF525A5AFF4A5A52FF525A5AFF525A
+      5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A
+      5AFF4A5A52FF4A5A52FF737373FF7B7B7BFF394242FF394242FF394242FF3942
+      42FF394242FF394242FF394242FF394242FF394242FF394242FF394242FF3942
+      42FF394242FF394242FF6B6B6BFF7B7B7BFF313939FF313939FF313939FF3139
+      39FF313939FF313939FF313939FF313939FF313939FF313939FF313939FF3139
+      39FFC6C6C6FFC6C6C6FF636363FF7B7B7BFF212929FF212929FF212929FF2129
+      29FF212929FF212929FF212929FFFFFFFFFF212929FF212929FF212929FF2129
+      29FF212929FF212929FF5A5A5AFF6B6B6BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF182118FF182118FF182118FF1821
+      18FF182118FF182118FF525252FF636363FF081810FF081810FF081810FF0818
+      10FF081810FF081810FF081810FF081810FF081810FF081810FF081810FF0818
+      10FFC6C6C6FFC6C6C6FF4A4A4AFF5A5A5AFF080808FF080808FF080808FF0808
+      08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+      08FF080808FF080808FF4A4A4AFF5A5A5AFF080808FF080808FF080808FF0808
+      08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+      08FF080808FF080808FF424242FF525252FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF0000FFFFFFFFFF080808FF0808
+      08FFC6C6C6FFC6C6C6FF424242FF525252FFFFFFFFFFEF0000FFEF0000FFEF00
+      00FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFFFFFFFFF000000FF0000
+      00FF000000FF000000FF393939FF4A4A4AFFFFFFFFFFD60000FFD60000FFD600
+      00FFD60000FFD60000FFD60000FFD60000FFD60000FFFFFFFFFF000000FF0000
+      00FF000000FF000000FF393939FF4A4A4AFFFFFFFFFFBD0000FFBD0000FFBD00
+      00FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFFFFFFFFF000000FF0000
+      00FFC6C6C6FFC6C6C6FF393939FF424242FFFFFFFFFF8C0000FF8C0000FF8C00
+      00FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FFFFFFFFFF000000FF0000
+      00FF000000FF000000FF292929FF393939FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF0000
+      00FF000000FF000000FF292929FF292929FF292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF212121FF000000000000000000000000000000000000
+      00000000000031319CFF5A5ABDFF5A5ABDFF31319CFF00000000000000000000
+      0000000000000000000000000000000000004A4A4AFF5A5ABDFF6B6BCEFF6B6B
+      CEFF5252BDFF6B6BCEFF8C8CE7FF8C8CE7FF8C8CE7FF6B6BCEFF31319CFF7B7B
+      DEFF5A5ABDFF4A4A4AFF00000000212121FF6B6B6BFF5A5A5AFF8C8CE7FF9494
+      EFFF6B6BCEFF8C8CE7FFA5A5F7FFB5B5FFFFA5A5F7FF8C8CE7FF8C8CE7FF2929
+      8CFF5A5A5AFF6B6B6BFF212121FF212121FF5A5A5AFF212121FF5252BDFF6B6B
+      CEFF31319CFF6B6BCEFF8C8CE7FF8C8CE7FF8C8CE7FF6B6BCEFF6B6BCEFF0000
+      52FF212121FF5A5A5AFF212121FF212121FF4A4A4AFF212121FF181884FF6B6B
+      CEFF5252BDFF7373D6FF5A5ABDFF4A4AB5FF5A5ABDFF6B6BCEFF7373D6FF1818
+      7BFF212121FF4A4A4AFF212121FF00000000212121FF00005AFF101073FF8484
+      DEFF7B7BDEFF6B6BCEFF8484DEFF6B6BCEFF8484DEFF7B7BDEFF8C8CE7FF5252
+      BDFF212121FF212121FF00000000000000000000000031319CFF18187BFF3939
+      A5FFA5A5F7FFA5A5F7FF8C8CE7FF3939A5FF8C8CE7FFA5A5F7FF8C8CE7FF0000
+      5AFF31319CFF00000000000000000000000031319CFF6B6BCEFF31319CFF1818
+      7BFF00005AFF00005AFF00005AFF00004AFF18187BFF00005AFF000042FF6363
+      C6FF6B6BCEFF7B7BDEFF000000000000000021218CFF6B6BCEFF7B7BDEFF1010
+      73FF5A5ABDFF31319CFF6B6BCEFF5252BDFF6B6BCEFF31319CFF29298CFF3939
+      A5FF8C8CE7FF292994FF0000000000000000101073FF080863FF080863FF0000
+      42FF6B6BCEFF4A4AB5FF9494EFFF7B7BDEFF9494EFFF4A4AB5FF6B6BCEFF0000
+      00FF00005AFF000052FF0000000000000000000000000000000031319CFF0000
+      42FF7B7BDEFF6363C6FF31319CFF5A5ABDFF31319CFF6363C6FF7B7BDEFF0000
+      00FF31319CFF0000000000000000000000000000000000000000000000003131
+      9CFF29298CFF31319CFF000052FF000052FF000042FF4242ADFF31319CFF3131
+      9CFF000000000000000000000000000000000000000000000000000000000000
+      42FF9494EFFF000042FF31319CFF181884FF21218CFF00005AFF8484DEFF0000
+      42FF000000000000000000000000000000000000000000000000000000000000
+      42FF6B6B6BFF5A5ABDFF4A4AB5FF3939A5FF3939A5FF4A4AB5FF424242FF0000
+      42FF000000000000000000000000000000000000000000000000000000000000
+      42FF292994FF21218CFF393939FF393939FF292929FF292929FF4A4AB5FF0000
+      42FF000000000000000000000000000000000000000000000000000000000000
+      00000000000000005AFF00005AFF000042FF00004AFF292994FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00007BB5B5FF7BB5B5FF7BB5B5FF7BB5B5FF7BB5B5FF7BB5B5FF7BB5B5FF7BB5
+      B5FF5A8C8CFF0000000000000000000000000000000000000000000000000000
+      00007BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+      8CFF216B5AFF000000000000000000000000000000006BA59CFF6BA59CFF6BA5
+      9CFF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+      8CFF216B5AFF000000000000000000000000000000006BA59CFF427B73FF427B
+      73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+      8CFF216B5AFF000000000000000000000000000000006BA59CFF427B73FF427B
+      73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF000000FF000000FF5A8C8CFF5A8C
+      8CFF216B5AFF00000000000000005A8C84FF5A8C84FF6BA59CFF427B73FF427B
+      73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF000000FFF7F7F7FF000000FF5A8C
+      8CFF216B5AFF00000000000000005A8C84FF316B63FF6BA59CFF427B73FF427B
+      73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF000000FFF7F7EFFFFFFFFFFF0000
+      00FF216B5AFF00000000000000005A8C84FF316B63FF6BA59CFF427B73FF427B
+      73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF000000FFE7E7E7FFF7F7F7FFFFFF
+      FFFF000000FF00000000000000005A8C84FF316B63FF6BA59CFF427B73FF427B
+      73FF5A8C8CFF216B5AFF216B5AFF216B5AFF000000FFDEDEDEFFEFEFEFFFF7F7
+      F7FFFFFFFFFF000000FF000000005A8C84FF316B63FF6BA59CFF427B73FF427B
+      73FF427B73FF427B73FF427B73FF427B73FF000000FFCECECEFFDEDEDEFFEFEF
+      EFFFFFFFFFFFFFFFFFFF000000FF5A8C84FF316B63FF427B73FF10524AFF1052
+      4AFF10524AFF10524AFF10524AFF10524AFF000000FFC6C6C6FFD6D6D6FFE7E7
+      E7FF8C8C8CFF000000FF000000FF5A8C84FF316B63FF316B63FF316B63FF316B
+      63FF316B63FF316B63FF316B63FF004239FF000000FF9C9C9CFF8C8C8CFFCECE
+      CEFFDEDEDEFF000000FF000000005A8C84FF316B63FF316B63FF316B63FF316B
+      63FF316B63FF316B63FF316B63FF004239FF000000FF8C8C8CFF000000FFC6C6
+      C6FFD6D6D6FF000000FF00000000316B63FF004239FF004239FF004239FF0042
+      39FF004239FF004239FF004239FF004239FF000000FF000000FF000000000000
+      00FFB5B5B5FFCEC6CEFF000000FF000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00FFADADADFFBDBDBDFF000000FF000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000FF000000FF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000006B8484FF6B8484FF6B8484FF6B8484FF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00006B8484FF5A7373FF42635AFF42635AFF5A7373FF6B8484FF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000042635AFF42635AFF000000000000000042635AFF5A7373FF6B8484FF0000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000006B8484FF5A7373FF0000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000005A7373FF42635AFF0000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000006B8484FF6B8484FF42635AFF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000006B8484FF5A7373FF42635AFF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000042635AFF42635AFF0000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000006B8484FF6B8484FF0000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000042635AFF42635AFF0000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -778,1159 +1332,604 @@ object MainForm: TMainForm
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000002929290029292900292929002929
-      2900292929002929290029292900292929002929290029292900292929002929
-      2900292929002929290029292900292929002929290029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100212121000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000029292900FFFFFF00DEDEDE00C7C7
-      C700FFFFFF00FFFFFF00A2A2A200FFFFFF00DEDEDE00DEDEDE00FFFFFF00A2A2
-      A200A2A2A200BBBBBB00FFFFFF0029292900393939006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F543800292929000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000029292900FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF0029292900424242006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F543800292929000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000039393900FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00393939004A4A4A00372E2400372E2400372E
-      2400372E2400372E2400372E2400372E2400372E2400372E2400372E2400372E
-      24006F5438006F5438006F543800393939000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000039393900C2975C00C2975C00C297
-      5C00C2975C00C2975C00C2975C00C2975C00C2975C00C2975C00C2975C00C297
-      5C00C2975C00C2975C00C2975C00393939004A4A4A006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F543800372E
-      24006F5438006F5438006F543800393939000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000039393900C2975C00CAA67600CAA6
-      7600C2975C00C2975C00D2B48E00D2B48E00C2975C00C2975C00D2B48E00D2B4
-      8E00C2975C00C2975C00C2975C0039393900525252006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F543800372E
-      24006F5438006F5438006F543800393939000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000042424200C2975C00D2B48E00D2B4
-      8E00D2B48E00C2975C00E1CEB700DAC2A300E5D5C100E5D5C100DAC2A300E1CE
-      B700C2975C00C2975C00C2975C0042424200525252006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F543800372E
-      24006F5438006F5438006F543800424242000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000042424200C2975C00D2B48E00D6BB
-      9900E9DBCA00DEC8AE00E1CEB700C2975C00E1CEB700E1CEB700C2975C00E9DB
-      CA00E1CEB700E1CEB700C2975C00424242005A5A5A0071573C0071573C007157
-      3C0071573C0071573C0071573C0071573C0071573C0071573C0071573C00382F
-      250071573C0071573C0071573C00424242000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000004A4A4A00C2975C00D2B48E00F4ED
-      E500C69E6A00DAC2A300E5D5C100C2975C00DEC8AE00E1CEB700C2975C00E1CE
-      B700C2975C00E5D5C100C2975C004A4A4A005A5A5A00745B4000745B4000745B
-      4000745B4000745B4000745B4000745B4000745B4000745B4000745B40003930
-      2600745B4000745B4000745B40004A4A4A000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000004A4A4A00C2975C00CEAD8200D6BB
-      9900C2975C00C2975C00E1CEB700C2975C00CEAD8200CEAD8200C2975C00E1CE
-      B700E1CEB700DAC2A300C2975C004A4A4A0063636300775F4400775F4400775F
-      4400775F4400775F4400775F4400775F4400775F4400775F4400775F44003A32
-      2800775F4400775F4400775F44004A4A4A000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000052525200C2975C00C2975C00C297
-      5C00C2975C00C2975C00C2975C00C2975C00C2975C00C2975C00C2975C00C297
-      5C00C2975C00C2975C00C2975C00525252006B6B6B007A644A007A644A007A64
-      4A007A644A007A644A007A644A007A644A007A644A007A644A007A644A003B33
-      2A007A644A007A644A007A644A00525252000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000005A5A5A00C2975C00C2975C00C297
-      5C00C2975C00C2975C00C2975C00C2975C00C2975C00C2975C00C2975C00C297
-      5C00C2975C00C2975C00C2975C005A5A5A007B7B7B007E6950007E6950007E69
-      50007E6950007E6950007E6950007E6950007E6950007E6950007E6950003D35
-      2C007E6950007E6950007E6950005A5A5A000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000063636300FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00636363007B7B7B00826F5700826F5700826F
-      5700826F5700826F5700826F5700826F5700826F5700826F5700826F57003E37
-      2F00826F5700826F5700826F5700636363000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000006B6B6B00FFFFFF00E9E9E900E9E9
-      E900FFFFFF00FFFFFF00D3D3D300D3D3D300FFFFFF00FFFFFF00D3D3D300D3D3
-      D300FFFFFF00FFFFFF00FFFFFF006B6B6B007B7B7B0086765E0086765E008676
-      5E0086765E0086765E0086765E0086765E0086765E0086765E0086765E00403A
-      310086765E0086765E0086765E006B6B6B000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000073737300FFFFFF00D3D3D300D3D3
-      D300D3D3D300FFFFFF00A2A2A200BBBBBB009494940094949400BBBBBB00A2A2
-      A200FFFFFF00FFFFFF00FFFFFF0073737300848484008B7C65008B7C65008B7C
-      65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C6500413C
-      34008B7C65008B7C65008B7C6500737373000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C0084848400848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C0084848400848484000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000002929290029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100212121000000000000000000000000000000
-      000000000000000000003139AD0010219C0010219C0010219C0010219C001021
-      9C0010219C0010219C0010219C0010219C00000000006B6B6B00292929002121
-      2100181818001818180018181800181818001818180018181800181818001818
-      180018181800181818004A4A4A00000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000003939390000006300000063000000
-      63000000630000006B0000006300000063000000630000006B00000063000000
-      0000000000000000000000000000292929000000000000000000000000000000
-      000000000000000000004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C000000000042424200FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF0029292900000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000004242420000007300000073000000
-      7300000073000000730000007300000073000000730000007300000073000000
-      0000000000000000000000000000292929000000000000000000000000000000
-      000000000000000000004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C000000000042424200FFFFFF00C8E0
-      E000C8E0DF00C8E0E000C8E0E000C8E0DF00B5B5B500C8DFDF00C7DFDF00C8DF
-      E000C8E0DF00FFFFFF0031313100000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000004A4A4A0000008400000084000000
-      8400000084000000840000008400000084000000840000008400000084000000
-      0000000000000000840000008400393939000000000000000000000000004263
-      5A00294A4A00294A4A004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C00000000004A4A4A00FFFFFF00CAE2
-      E100CAE2E100CAE2E100CAE2E100B5B5B50072282800B5B5B500B5B5B500B5B5
-      B500B5B5B500B5B5B50018181800B5B5B5000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000004A4A4A0000009400000094000000
-      9400000094000000940000009400000094000000940000009400000094000000
-      0000000000000000000000000000393939000000000000000000000000005A73
-      6B0042635A0042635A004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C00000000004A4A4A00FFFFFF00CDE5
-      E300CCE5E300CDE5E300B5B5B500812D2D00812D2D00812D2D00812D2D00812D
-      2D00812D2D00812D2D00812D2D00812D2D004E63630042555500364545000000
-      0000000000004E636300425555003645450000000000000000004E6363004255
-      550036454500000000000000000000000000525252000000A5000000A5000000
-      A50000009C0000009C0000009C000000A5000000A5000000A5000000A5000000
-      0000000000000000000000000000393939000000000000000000000000005A73
-      6B0042635A0042635A004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C00000000004A4A4A00FFFFFF00D0E8
-      E500D0E8E600CFE8E50092333300923333009233330092333300923333009233
-      33009233330092333300923333009233330000000000788C8C005A7373004254
-      54000000000000000000788C8C005A737300425454000000000000000000788C
-      8C005A737300425454000000000000000000525252000000AD000000AD000000
-      AD000000AD000000AD000000AD000000AD000000AD000000AD000000AD000808
-      0800000000000000AD000000AD004242420039524A0029423900294239005A73
-      6B0042635A0042635A004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C00000000005A5A5A00FFFFFF00D3EB
-      E800D3EBE800A3393900A3393900A3393900A3393900A3393900A3393900A339
-      3900A3393900A3393900A3393900A33939000000000000000000788C8C005A73
-      7300425454000000000000000000788C8C005A73730042545400000000000000
-      0000788C8C005A73730042545400000000005A5A5A0008080800080808000808
-      0800080808000808080008080800080808000808080008080800080808000808
-      080000000000000000000000000042424200425A520039524A0039524A005A73
-      6B0042635A0042635A004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C00000000005A5A5A00FFFFFF00D7EE
-      EA00D7EEEB00D6EEEB00B23E3E00B23E3E00B23E3E00B23E3E00B33F3F00B23E
-      3E00B23E3E00B23E3E00B23E3E00B23E3E00000000000000000000000000788C
-      8C005A737300425454000000000000000000788C8C005A737300425454000000
-      000000000000788C8C005A737300425454005A5A5A0000080800000808000008
-      0800000808000008080000080800000808000008080000080800000808000008
-      08000008080000080800000808004A4A4A00425A520039524A0039524A005A73
-      6B0042635A0042635A004A5AB5003139AD003139AD003139AD003139AD003139
-      AD003139AD003139AD003139AD0010219C000000000063636300FFFFFF00DAF2
-      ED00DAF2ED00DAF2ED00DAF2ED00BD424200BD424200BD424200BD424200BD42
-      4200BD424200BD424200BD424200BD4242000000000000000000000000004254
-      54005A737300788C8C000000000000000000425454005A737300788C8C000000
-      000000000000425454005A737300788C8C006363630008100800081008000810
-      0800081008000810080008100800081008000810080008100800081008000810
-      0800081008002929AD002929AD004A4A4A00425A520039524A0039524A005A73
-      6B0042635A0042635A004A5AB5004A5AB5004A5AB5004A5AB5004A5AB5004A5A
-      B5004A5AB5004A5AB5004A5AB5003139AD00000000006B6B6B00FFFFFF00DEF6
-      F000DEF6F000DDF5F000DDF5EF00DDF5F000BD424200DDF5EF00DDF5F000DEF5
-      F000C6DEDE00DEDEDE0052525200000000000000000000000000425454005A73
-      7300788C8C000000000000000000425454005A737300788C8C00000000000000
-      0000425454005A737300788C8C00000000006B6B6B003939AD003939AD003939
-      AD003939AD003939AD003939AD003939AD003939AD0010181000101810001018
-      100010181000101810001018100052525200425A520039524A0039524A005A73
-      6B0042635A0042635A0042635A0042635A0042635A0042635A0042635A004263
-      5A00294A4A00000000000000000000000000000000006B6B6B00FFFFFF00E0F9
-      F200E1F9F200E0F8F200E0F8F200E0F8F200E1F9F200F7F7F700D6D6D600C6C6
-      C600B5B5B5009C9C9C00525252000000000000000000425454005A737300788C
-      8C000000000000000000425454005A737300788C8C0000000000000000004254
-      54005A737300788C8C0000000000000000007B7B7B0018212100182121001821
-      2100182121001821210018212100182121004A4AAD0018212100182121001821
-      21001821210018212100182121005A5A5A00425A520039524A0039524A005A73
-      6B0042635A0042635A0042635A0042635A0042635A0042635A0042635A004263
-      5A00294A4A00000000000000000000000000000000006B6B6B00FFFFFF00E3FB
-      F400E3FBF400E3FBF300E3FBF400E3FCF400E3FBF400F7F7F700949494008C8C
-      8C00737373005A5A5A005A5A5A0000000000687F7F00798D8D00879999000000
-      000000000000687F7F00798D8D00879999000000000000000000687F7F00798D
-      8D00879999000000000000000000000000007B7B7B0021292900212929002129
-      2900212929002129290021292900212929002129290021292900212929002129
-      2900212929005252AD005252AD0063636300425A520039524A0039524A005A73
-      6B005A736B005A736B005A736B005A736B005A736B005A736B005A736B005A73
-      6B0042635A00000000000000000000000000000000006B6B6B00FFFFFF00E5FE
-      F600E5FDF600E5FDF600E5FEF600E6FEF600E5FDF600F7F7F700A5A5A500FFFF
-      FF00FFFFFF00FFFFFF005A5A5A00000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000007B7B7B0029293100292931002929
-      3100292931002929310029293100292931002929310029293100292931002929
-      31002929310029293100292931006B6B6B00425A520039524A0039524A003952
-      4A0039524A0039524A0039524A0039524A0039524A0029423900000000000000
-      000000000000000000000000000000000000000000006B6B6B00FFFFFF00E7FF
-      F700E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700F7F7F700B5B5B500FFFF
-      FF00D6F7EF00B5D6CE006B6B6B00000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000084848400525A5A004A5A5200525A
-      5A00525A5A00525A5A00525A5A00525A5A00525A5A00525A5A00525A5A00525A
-      5A00525A5A004A5A52004A5A520073737300425A520039524A0039524A003952
-      4A0039524A0039524A0039524A0039524A0039524A0029423900000000000000
-      000000000000000000000000000000000000000000006B6B6B00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CECECE00FFFF
-      FF00B5D6CE007373730000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000084848400848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C008484840084848400425A5200425A5200425A5200425A
-      5200425A5200425A5200425A5200425A5200425A520039524A00000000000000
-      0000000000000000000000000000000000000000000073737300737373007373
-      7300737373007B7B7B007B7B7B007B7B7B008484840084848400848484008484
-      8400848484000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000002929290029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100212121000000000029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100000000000000000029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000393939006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F54380029292900393939007B9494007B9494006363
-      6300E7E7E700FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7E700D6D6D600E7E7
-      E7005A5A5A007B9494007B94940029292900393939007B9494007B9494006363
-      6300E7E7E700FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7E700D6D6D600E7E7
-      E7005A5A5A007B9494007B949400292929000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000424242006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F54380029292900424242007B9494007B9494006B6B
-      6B00FFFFFF00E7E7E700A5BDB500FFFFFF00FFFFFF00EFEFEF00E7E7E700E7E7
-      E7006B6B6B007B9494007B94940029292900424242007B9494007B9494006B6B
-      6B00FFFFFF00E7E7E700A5BDB500FFFFFF00FFFFFF00EFEFEF00E7E7E700E7E7
-      E7006B6B6B007B9494007B949400292929000000000000000000000000000000
-      0000C6CED600ADB5B500ADB5B500ADB5B500ADB5B500C6CED600000000000000
-      0000000000000000000000000000000000004A4A4A006F5438006F5438006F54
-      3800393939006F5438006F5438006F543800393939006F5438006F5438006F54
-      3800393939006F5438006F543800393939004A4A4A0094ADA5008CA5A5007B7B
-      7B00FFFFFF005A736B008CA5A500FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7006B6B6B00849C9C00849C9C00393939004A4A4A0094ADA5008CA5A5007B7B
-      7B00FFFFFF005A736B008CA5A500FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7006B6B6B00849C9C00849C9C0039393900000000000000000000000000BDC6
-      C600848C8C00424242003939390039393900394242007B848400BDC6CE00C6CE
-      D600000000000000000000000000000000004A4A4A006F5438006F543800FFFF
-      FF006F5438006F5438006F543800FFFFFF006F5438006F5438006F543800FFFF
-      FF006F5438006F5438006F543800393939004A4A4A0094ADA5008CA5A5007B7B
-      7B00FFFFFF005A736B008CA5A500FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7006B6B6B00849C9C00849C9C00393939004A4A4A0094ADA5008CA5A5007B7B
-      7B00FFFFFF005A736B008CA5A500FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7006B6B6B00849C9C00849C9C00393939000000000000000000C6CED6002929
-      2900636B6B009C9CA500ADB5B500ADB5B500BDC6C600737B7B0018181800848C
-      8C00C6CED600000000000000000000000000525252006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F54380039393900525252009CB5B5009CB5AD009C9C
-      9C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7007B7B7B00849C9C00849C9C0039393900525252009CB5B5009CB5AD009C9C
-      9C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7007B7B7B00849C9C00849C9C00393939000000000000000000C6CECE00ADB5
-      BD00C6CED60039424200000000000000000018181800ADB5B500ADB5B5001010
-      10007B7B8400000000000000000000000000525252006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F5438004242420052525200A5BDB500A5BDB500A5BD
-      B50094B5AD008CADA5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5
-      A5008CA5A5008CA5A5008CA5A5004242420052525200A5BDB500A5BDB500A5BD
-      B50094B5AD008CADA5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5
-      A5008CA5A5008CA5A5008CA5A5004242420000000000000000009CA5AD009CA5
-      AD0021292900000000000000000000000000000000000000000094949C00848C
-      8C00182121000000000000000000000000005A5A5A0071573C0071573C007157
-      3C003939390071573C0071573C0071573C003939390071573C0071573C007157
-      3C003939390071573C0071573C00424242005A5A5A00A5C6BD008CA59C008CA5
-      A500849C9C007B948C00738C8400738C8400738C8400738C8C00738C8C00738C
-      8C00738C8C006B8484008CADA500424242005A5A5A00A5C6BD008CA59C008CA5
-      A500849C9C007B948C00738C8400738C8400738C8400738C8C00738C8C00738C
-      8C00738C8C006B8484008CADA5004242420000000000000000005A5A6300848C
-      8C000000000042424200C6CECE0000000000000000000000000084848C003139
-      390029313100B5BDBD0000000000000000005A5A5A00745B4000745B4000FFFF
-      FF00745B4000745B4000745B4000FFFFFF00745B4000745B4000745B4000FFFF
-      FF00745B4000745B4000745B40004A4A4A005A5A5A00ADC6BD0094ADA500E7E7
-      E700F7F7F700F7F7F700EFEFEF00EFEFEF00EFEFEF00EFEFEF00F7F7F700EFEF
-      EF00DEDEDE0073948C0094ADAD004A4A4A005A5A5A00ADC6BD0094ADA500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000
-      00000000000073948C0094ADAD004A4A4A000000000000000000949C9C002121
-      2100000000000000000029292900080808000000000000000000393939002129
-      29007B8484008C8C8C00000000000000000063636300775F4400775F4400775F
-      4400775F4400775F4400775F4400775F4400775F4400775F4400775F4400775F
-      4400775F4400775F4400775F44004A4A4A0063636300ADC6C60094ADAD00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF006B6B6B006B6B6B00FFFFFF00FFFFFF00FFFF
-      FF00F7F7F7007B94940094ADAD004A4A4A0063636300ADC6C60094ADAD00FFFF
-      FF008C0000008C0000008C0000008C0000008C000000FFFFFF00000000000000
-      0000C6C6C6007B94940094ADAD004A4A4A0000000000000000004A5252008484
-      8C0073737B0042424A00101010001818180010101000525252005A6363008C8C
-      940042424200949C9C0000000000000000006B6B6B007A644A007A644A007A64
-      4A007A644A007A644A007A644A007A644A007A644A007A644A007A644A007A64
-      4A007A644A007A644A007A644A00525252006B6B6B00ADCEC6009CB5AD00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00DEDEDE00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00F7F7F7007B9C94009CB5B500525252006B6B6B00ADCEC6009CB5AD00FFFF
-      FF00EF000000EF000000EF000000EF000000EF000000FFFFFF00000000000000
-      0000000000007B9C94009CB5B500525252000000000000000000949C9C004A4A
-      4A00737B7B00737B7B00949C9C0094949C0094949C007B8484006B6B73005252
-      5200A5A5AD000000000000000000000000007B7B7B007E6950007E6950007E69
-      5000393939007E6950007E6950007E695000393939007E6950007E6950007E69
-      5000393939007E6950007E6950005A5A5A007B7B7B00CEE7DE00A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF006B6B6B006B6B6B00DEDEDE00FFFFFF00FFFF
-      FF00FFFFFF008CA5A500ADC6C6005A5A5A007B7B7B00CEE7DE00A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FF000000FF000000FFFFFF00080808000808
-      0800C6C6C6008CA5A500ADC6C6005A5A5A000000000000000000C6CED600BDC6
-      C60084848C00737B7B005252520052525200525252006B737300848C8C00BDBD
-      C600000000000000000000000000000000007B7B7B00826F5700826F5700FFFF
-      FF00826F5700826F5700826F5700FFFFFF00826F5700826F5700826F5700FFFF
-      FF00826F5700826F5700826F5700636363007B7B7B00D6EFE700A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00DEDEDE006B6B6B00FFFFFF00FFFF
-      FF00FFFFFF0094ADAD00ADC6C600636363007B7B7B00D6EFE700A5BDB5000818
-      1000081810000818100008181000081810000818100008181000081810000818
-      10000818100094ADAD00ADC6C600636363000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000007B7B7B0086765E0086765E008676
-      5E0086765E0086765E0086765E0086765E0086765E0086765E0086765E008676
-      5E0086765E0086765E0086765E006B6B6B007B7B7B00D6F7EF00A5BDB500FFFF
-      FF00FFFFFF00FFFFFF008C8C8C006B6B6B006B6B6B00DEDEDE00FFFFFF00FFFF
-      FF00FFFFFF0094ADA500ADCEC6006B6B6B007B7B7B00D6F7EF00A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0018211800182118001821
-      1800C6C6C60094ADA500ADCEC6006B6B6B000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000848484008B7C65008B7C65008B7C
-      65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C
-      65008B7C65008B7C65008B7C65007373730084848400DEF7F700A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00F7F7F7009CB5AD00B5CECE007373730084848400DEF7F700A5BDB5002129
-      290021292900212929002129290021292900FFFFFF0021292900212929002129
-      2900212929009CB5AD00B5CECE00737373000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000084848400848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C00848484008484840000000000848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C00848484000000000000000000848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C0084848400000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000002929290029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100212121000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000ADADAD00BDBDBD00000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000393939006F5438006F5438006F54
-      38006F5438006F5438006F5438006F543800393939006F5438006F5438006F54
-      38006F5438006F5438003939390029292900316B630000423900004239000042
-      3900004239000042390000423900004239000042390000000000000000000000
-      000000000000B5B5B500CEC6CE00000000000000000000000000000000000000
-      000000000000000000000000000042635A0042635A0000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000010219C00000000000000000000000000000000000000
-      000000000000000000000000000000000000424242006F5438006F5438006F54
-      38006F5438006F5438006F543800FFFFFF006F5438006F5438006F5438006F54
-      38006F543800FFFFFF006F543800292929005A8C8400316B6300316B6300316B
-      6300316B6300316B6300316B6300316B630000423900000000008C8C8C000000
-      0000C6C6C600D6D6D60000000000000000000000000000000000000000000000
-      00000000000000000000000000006B8484006B84840000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000010219C003139AD0010219C000000000000000000000000000000
-      0000000000000000000000000000000000004A4A4A006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F543800393939005A8C8400316B6300316B6300316B
-      6300316B6300316B6300316B6300316B630000423900000000009C9C9C008C8C
-      8C00CECECE00DEDEDE0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000003139AD004A5AB5003139AD000000000000000000000000000000
-      0000000000000000000000000000000000004A4A4A006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F543800393939005A8C8400316B6300427B73001052
-      4A0010524A0010524A0010524A0010524A0010524A0000000000C6C6C600D6D6
-      D600E7E7E7008C8C8C0000000000000000000000000000000000000000000000
-      000000000000000000000000000042635A0042635A0000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000010219C003139AD00000000003139AD0010219C0000000000000000000000
-      000000000000000000000000000000000000525252006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F543800393939005A8C8400316B63006BA59C00427B
-      7300427B7300427B7300427B7300427B7300427B730000000000CECECE00DEDE
-      DE00EFEFEF00FFFFFF00FFFFFF00000000000000000000000000000000000000
-      00000000000000000000000000006B8484005A73730042635A00000000000000
+      0000000000000000000000000000000000000000000000000000000000004A5A
+      B5FF4A5AB5FF0000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000004A5AB5FF4A5AB5FF3139
+      ADFF3139ADFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF1021
+      9CFF10219CFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000003139ADFF10219CFF10219CFF0000
+      00000000000000000000000000000000000000000000000000004A5AB5FF0000
+      00000000000000000000000000004A5AB5FF3139ADFF00000000000000000000
+      00000000000000000000000000000000000000000000000000003139ADFF4A5A
+      B5FF0000000000000000000000003139ADFF10219CFF00000000000000000000
+      000000000000000000000000000000000000000000000000000010219CFF3139
+      ADFF4A5AB5FF000000004A5AB5FF3139ADFF0000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000001021
-      9C003139AD004A5AB500000000004A5AB5003139AD0000000000000000000000
-      000000000000000000000000000000000000525252006F5438006F5438006F54
-      38006F5438006F5438006F5438006F5438006F5438006F5438006F5438006F54
-      38006F5438006F5438006F543800424242005A8C8400316B63006BA59C00427B
-      7300427B73005A8C8C00216B5A00216B5A00216B5A0000000000DEDEDE00EFEF
-      EF00F7F7F700FFFFFF0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000006B8484006B84840042635A000000
-      0000000000000000000000000000000000000000000000000000000000003139
-      AD004A5AB5000000000000000000000000003139AD0010219C00000000000000
-      0000000000000000000000000000000000005A5A5A0071573C0071573C007157
-      3C0071573C0071573C0071573C0071573C003939390071573C0071573C007157
-      3C0071573C0071573C0039393900424242005A8C8400316B63006BA59C00427B
-      7300427B73007BB5B5005A8C8C005A8C8C005A8C8C0000000000E7E7E700F7F7
-      F700FFFFFF000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000000000005A7373004263
-      5A00000000000000000000000000000000000000000000000000000000004A5A
-      B500000000000000000000000000000000004A5AB5003139AD00000000000000
-      0000000000000000000000000000000000005A5A5A00745B4000745B4000745B
-      4000745B4000745B4000745B4000FFFFFF00745B4000745B4000745B4000745B
-      4000745B4000FFFFFF00745B40004A4A4A005A8C8400316B63006BA59C00427B
-      7300427B73007BB5B5005A8C8C005A8C8C005A8C8C0000000000F7F7EF00FFFF
-      FF0000000000216B5A0000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000000000006B8484005A73
-      7300000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000003139AD0010219C001021
-      9C000000000000000000000000000000000063636300775F4400775F44003939
-      3900775F4400775F440039393900775F4400775F4400775F4400775F4400775F
-      4400775F4400775F4400775F44004A4A4A005A8C84005A8C84006BA59C00427B
-      7300427B73007BB5B5005A8C8C005A8C8C005A8C8C0000000000F7F7F7000000
-      00005A8C8C00216B5A0000000000000000000000000000000000000000000000
-      00000000000042635A0042635A00000000000000000042635A005A7373006B84
-      8400000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD0010219C0010219C0000000000000000006B6B6B007A644A00FFFFFF007A64
-      4A007A644A00FFFFFF007A644A007A644A007A644A007A644A007A644A007A64
-      4A007A644A007A644A007A644A005252520000000000000000006BA59C00427B
-      7300427B73007BB5B5005A8C8C005A8C8C005A8C8C0000000000000000005A8C
-      8C005A8C8C00216B5A0000000000000000000000000000000000000000000000
-      0000000000006B8484005A73730042635A0042635A005A7373006B8484000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000000000004A5AB5004A5A
-      B5003139AD003139AD0000000000000000007B7B7B007E6950007E6950007E69
-      50007E6950007E6950007E6950007E6950007E6950007E6950007E6950007E69
-      50007E6950007E6950007E6950005A5A5A0000000000000000006BA59C00427B
-      7300427B73007BB5B5005A8C8C005A8C8C005A8C8C005A8C8C005A8C8C005A8C
-      8C005A8C8C00216B5A0000000000000000000000000000000000000000000000
-      000000000000000000006B8484006B8484006B8484006B848400000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00004A5AB5004A5AB50000000000000000007B7B7B00826F5700826F57003939
-      3900826F5700826F570039393900826F5700826F5700826F5700826F5700826F
-      5700826F5700826F5700826F57006363630000000000000000006BA59C006BA5
-      9C006BA59C007BB5B5005A8C8C005A8C8C005A8C8C005A8C8C005A8C8C005A8C
-      8C005A8C8C00216B5A0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000007B7B7B0086765E00FFFFFF008676
-      5E0086765E00FFFFFF0086765E0086765E0086765E0086765E0086765E008676
-      5E0086765E0086765E0086765E006B6B6B000000000000000000000000000000
-      0000000000007BB5B5005A8C8C005A8C8C005A8C8C005A8C8C005A8C8C005A8C
-      8C005A8C8C00216B5A0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000848484008B7C65008B7C65008B7C
-      65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C65008B7C
-      65008B7C65008B7C65008B7C6500737373000000000000000000000000000000
-      0000000000007BB5B5007BB5B5007BB5B5007BB5B5007BB5B5007BB5B5007BB5
-      B5007BB5B5005A8C8C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000084848400848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C0084848400848484000000000000000000000000000000
-      00002131730010186B0010186B0010186B0010186B0010186B0010186B001018
-      6B0010186B0010186B0010186B0010186B000000000000000000000000000000
-      000000000000000000005A73730042635A0042635A0042635A0042635A004263
-      5A0042635A0042635A0042635A0042635A002929290029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100212121000000000000000000000000000000
-      0000000000000000000000005A0000005A000000420000004A00292994000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000394A7B00213173002131730021317300213173002131730010186B00394A
-      7B0021317300213173002131730010186B000000000000000000000000000000
-      000000000000000000006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A0039393900FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000
-      0000000000000000000000000000292929000000000000000000000000000000
-      0000000042002929940021218C00393939003939390029292900292929004A4A
-      B500000042000000000000000000000000000000000000000000000000000000
-      0000394A7B00213173002131730021317300213173002131730010186B00394A
-      7B0021317300213173002131730010186B000000000000000000000000000000
-      000000000000000000006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A0042424200FFFFFF008C0000008C00
-      00008C0000008C0000008C0000008C0000008C0000008C000000FFFFFF000000
-      0000000000000000000000000000292929000000000000000000000000000000
-      0000000042006B6B6B005A5ABD004A4AB5003939A5003939A5004A4AB5004242
-      4200000042000000000000000000000000000000000000000000000000000000
-      000021317300394A7B00394A7B00394A7B00394A7B00394A7B0010186B00394A
-      7B00394A7B00394A7B00394A7B0010186B000000000000000000000000004263
-      5A00294A4A00294A4A006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A004A4A4A00FFFFFF00BD000000BD00
-      0000BD000000BD000000BD000000BD000000BD000000BD000000FFFFFF000000
-      000000000000C6C6C600C6C6C600393939000000000000000000000000000000
-      0000000042009494EF000000420031319C001818840021218C0000005A008484
-      DE00000042000000000000000000000000008C8C8C007B7B7B007B7B7B007B7B
-      7B002131730010186B0010186B0010186B0010186B0010186B0010186B001018
-      6B0010186B0010186B0010186B0010186B000000000000000000000000005A73
-      6B0042635A0042635A006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A004A4A4A00FFFFFF00D6000000D600
-      0000D6000000D6000000D6000000D6000000D6000000D6000000FFFFFF000000
-      0000000000000000000000000000393939000000000000000000000000000000
-      000031319C0029298C0031319C000000520000005200000042004242AD003131
-      9C0031319C00000000000000000000000000949494008C8C8C008C8C8C008C8C
-      8C00394A7B002131730021317300213173002131730021317300213173002131
-      730021317300213173002131730010186B000000000000000000000000005A73
-      6B0042635A0042635A006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A0052525200FFFFFF00EF000000EF00
-      0000EF000000EF000000EF000000EF000000EF000000EF000000FFFFFF000000
-      0000000000000000000000000000393939000000000000000000000000003131
-      9C00000042007B7BDE006363C60031319C005A5ABD0031319C006363C6007B7B
-      DE000000000031319C000000000000000000949494008C8C8C00949494004242
-      4200394A7B002131730021317300213173002131730021317300213173002131
-      730021317300213173002131730010186B003139AD0010219C0010219C005A73
-      6B0042635A0042635A006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A0052525200FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FF000000FF000000FF000000FFFFFF000808
-      080008080800C6C6C600C6C6C600424242000000000010107300080863000808
-      6300000042006B6BCE004A4AB5009494EF007B7BDE009494EF004A4AB5006B6B
-      CE000000000000005A000000520000000000949494008C8C8C00D6D6D6009494
-      940021317300394A7B00394A7B00394A7B00394A7B00394A7B00394A7B00394A
-      7B00394A7B00394A7B00394A7B0010186B004A5AB5003139AD003139AD005A73
-      6B0042635A0042635A006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A005A5A5A0008080800080808000808
-      0800080808000808080008080800080808000808080008080800080808000808
-      0800080808000808080008080800424242000000000021218C006B6BCE007B7B
-      DE00101073005A5ABD0031319C006B6BCE005252BD006B6BCE0031319C002929
-      8C003939A5008C8CE7002929940000000000949494008C8C8C008C8C8C008C8C
-      8C002131730010186B0010186B0010186B0010186B0010186B0010186B001018
-      6B0010186B0010186B0010186B0010186B004A5AB5003139AD003139AD005A73
-      6B0042635A0042635A006B8484005A7373005A7373005A7373005A7373005A73
-      73005A7373005A7373005A73730042635A005A5A5A0008080800080808000808
-      0800080808000808080008080800080808000808080008080800080808000808
-      08000808080008080800080808004A4A4A000000000031319C006B6BCE003131
-      9C0018187B0000005A0000005A0000005A0000004A0018187B0000005A000000
-      42006363C6006B6BCE007B7BDE0000000000949494008C8C8C008C8C8C008C8C
-      8C00394A7B002131730021317300213173002131730010186B00394A7B002131
-      730021317300213173002131730010186B004A5AB5003139AD003139AD005A73
-      6B0042635A0042635A006B8484006B8484006B8484006B8484006B8484006B84
-      84006B8484006B8484006B8484005A7373006363630008181000081810000818
-      1000081810000818100008181000081810000818100008181000081810000818
-      100008181000C6C6C600C6C6C6004A4A4A00000000000000000031319C001818
-      7B003939A500A5A5F700A5A5F7008C8CE7003939A5008C8CE700A5A5F7008C8C
-      E70000005A0031319C000000000000000000949494008C8C8C008C8C8C008C8C
-      8C00394A7B002131730021317300213173002131730010186B00394A7B002131
-      730021317300213173002131730010186B004A5AB5003139AD003139AD005A73
-      6B0042635A0042635A0042635A0042635A0042635A0042635A0042635A004263
-      5A00294A4A000000000000000000000000006B6B6B00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0018211800182118001821
-      180018211800182118001821180052525200000000002121210000005A001010
-      73008484DE007B7BDE006B6BCE008484DE006B6BCE008484DE007B7BDE008C8C
-      E7005252BD00212121002121210000000000949494008C8C8C008C8C8C008C8C
-      8C00394A7B00394A7B00394A7B00394A7B00394A7B002131730021317300394A
-      7B00394A7B00394A7B00394A7B00213173004A5AB5003139AD003139AD005A73
-      6B0042635A0042635A0042635A0042635A0042635A0042635A0042635A004263
-      5A00294A4A000000000000000000000000007B7B7B0021292900212929002129
-      290021292900212929002129290021292900FFFFFF0021292900212929002129
-      29002129290021292900212929005A5A5A00212121004A4A4A00212121001818
-      84006B6BCE005252BD007373D6005A5ABD004A4AB5005A5ABD006B6BCE007373
-      D60018187B00212121004A4A4A0021212100949494008C8C8C00949494004242
-      42008C8C8C008C8C8C008C8C8C008C8C8C0094949400424242008C8C8C007B7B
-      7B00000000000000000000000000000000004A5AB5003139AD003139AD005A73
-      6B005A736B005A736B005A736B005A736B005A736B005A736B005A736B005A73
-      6B0042635A000000000000000000000000007B7B7B0031393900313939003139
-      3900313939003139390031393900313939003139390031393900313939003139
-      390031393900C6C6C600C6C6C60063636300212121005A5A5A00212121005252
-      BD006B6BCE0031319C006B6BCE008C8CE7008C8CE7008C8CE7006B6BCE006B6B
-      CE0000005200212121005A5A5A0021212100949494008C8C8C00D6D6D6009494
-      94008C8C8C008C8C8C008C8C8C008C8C8C00D6D6D600949494008C8C8C007B7B
-      7B00000000000000000000000000000000004A5AB5003139AD003139AD003139
-      AD003139AD003139AD003139AD003139AD003139AD0010219C00000000000000
-      0000000000000000000000000000000000007B7B7B0039424200394242003942
-      4200394242003942420039424200394242003942420039424200394242003942
-      42003942420039424200394242006B6B6B00212121006B6B6B005A5A5A008C8C
-      E7009494EF006B6BCE008C8CE700A5A5F700B5B5FF00A5A5F7008C8CE7008C8C
-      E70029298C005A5A5A006B6B6B0021212100949494008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C007B7B
-      7B00000000000000000000000000000000004A5AB5003139AD003139AD003139
-      AD003139AD003139AD003139AD003139AD003139AD0010219C00000000000000
-      00000000000000000000000000000000000084848400525A5A004A5A5200525A
-      5A00525A5A00525A5A00525A5A00525A5A00525A5A00525A5A00525A5A00525A
-      5A00525A5A004A5A52004A5A520073737300000000004A4A4A005A5ABD006B6B
-      CE006B6BCE005252BD006B6BCE008C8CE7008C8CE7008C8CE7006B6BCE003131
-      9C007B7BDE005A5ABD004A4A4A00000000009494940094949400949494009494
-      9400949494009494940094949400949494009494940094949400949494008C8C
-      8C00000000000000000000000000000000004A5AB5004A5AB5004A5AB5004A5A
-      B5004A5AB5004A5AB5004A5AB5004A5AB5004A5AB5003139AD00000000000000
-      00000000000000000000000000000000000084848400848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C0084848400848484000000000000000000000000000000
-      0000000000000000000031319C005A5ABD005A5ABD0031319C00000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000002929290029292900212121001818
-      1800181818001818180018181800181818001818180018181800292929002929
-      2900212121000000000000000000000000000000000000000000292929002929
-      2900292929002929290029292900292929002929290029292900292929002929
-      290021212100292929000000000000000000000000006B6B6B00292929002121
-      2100181818001818180018181800181818001818180018181800181818001818
-      1800181818004A4AFF004A4AFF00000000000000000000000000000000000000
-      000000000000000000006B6B6B00292929002121210018181800181818001818
-      18001818180018181800181818004A4A4A0039393900FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000
-      0000292929000000000000000000000000000000000000000000393939007B9C
-      9C007B9C9C007B9C9C007B9C9C007B9C9C007B9C9C007B9C9C007B9C9C007B9C
-      9C007B9C9C002929290000000000000000000000000042424200FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B5B5
-      B5004A4AFF004A4AFF0029292900000000000000000000000000000000000000
-      0000000000000000000042424200FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF002929290042424200FFFFFF008C000000FFDE
-      DE00FFDEDE00FFDEDE00FFDEDE00FFDEDE00FFDEDE00FFFFFF00DEDEDE000000
-      000029292900000000000000000000000000000000000000000042424200849C
-      9C00849C9C00849C9C00849C9C00849C9C00849C9C00849C9C00849C9C00849C
-      9C00849C9C002929290000000000000000000000000042424200FFFFFF00C6DE
-      DE00C6DEDE00B5B5B500C6DEDE00C6DEDE00C6DEDE00C6DEDE00B5B5B5004A4A
-      FF004A4AFF00FFFFFF0031313100000000006B6B6B0029292900212121001818
-      1800181818001818180042424200FFFFFF00E7C6C600E7C6C600E7C6C600E7C6
-      C600E7C6C600E7C6C600FFFFFF00313131004A4A4A00FFFFFF00BD000000FFDE
-      DE004A63520042635A0042635A0042635A0042635A0042635A00DEDEDE000000
-      00003939390000000000000000000000000000000000000000004A4A4A008CA5
-      A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5
-      A5008CA5A500393939000000000000000000000000004A4A4A00FFFFFF00BDDE
-      D600BDDED6004A4AFF00B5B5B500B5B5B500BDDED600B5B5B5004A4AFF004A4A
-      FF00BDDED600FFFFFF00313131000000000042424200FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF004A4A4A00FFFFFF00EFCECE00EFCECE00EFCECE00EFCE
-      CE00EFCECE00EFCECE00FFFFFF00313131004A4A4A00FFFFFF00D6000000FFDE
-      DE006B8484005A7373005A7373005A73730042635A00FFFFFF00000000000000
-      00003939390000000000000000000000000000000000000000004A4A4A0094AD
-      AD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094AD
-      AD0094ADAD00393939000000000000000000000000004A4A4A00FFFFFF00CEE7
-      E700CEE7E700CEE7E7004A4AFF004A4AFF00B5B5B5004A4AFF004A4AFF00CEE7
-      E700CEE7E700FFFFFF00313131000000000042424200FFFFFF00C6DEDE00C6DE
-      DE00C6DEDE00C6DEDE005A5A5A00FFFFFF00F7D6DE00F7D6DE00F7D6DE00F7D6
-      DE00F7D6DE00F7D6DE00FFFFFF004242420052525200FFFFFF00EF000000FFDE
-      DE006B8484005A7373005A73730042635A0042635A00FFFFFF00000000000000
-      0000393939000000000000000000000000000000000000000000525252009CB5
-      B5009CB5B5009CB5B5009CB5B5009CB5B5009CB5B5009CB5B5009CB5B5009CB5
-      B5009CB5B500393939000000000000000000000000004A4A4A00FFFFFF00CEE7
-      E700CEE7E700CEE7E700CEE7E7004A4AFF004A4AFF004A4AFF00B5B5B500CEE7
-      E700CEE7E700FFFFFF0039393900000000004A4A4A00FFFFFF00CEE7E700CEE7
-      E700CEE7E700CEE7E7005A5A5A00FFFFFF00F7D6DE00F7D6DE00F7D6DE00F7D6
-      DE00F7D6DE00F7D6DE00FFFFFF004242420052525200FFFFFF00FFFFFF00FFFF
-      FF006B8484005A7373006B8484005A73730042635A0042635A00DEDEDE000808
-      080042424200000000000000000000000000000000000000000052525200A5BD
-      BD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BDBD007B9C9C006B84
-      8400A5BDBD00424242000000000000000000000000005A5A5A00FFFFFF00D6EF
-      E700D6EFE700D6EFE700B5B5B5004A4AFF004A4AFF004A4AFF004A4AFF00B5B5
-      B500B5B5B500FFFFFF0042424200000000005A5A5A00FFFFFF00D6EFE700D6EF
-      E700D6EFE700D6EFE7006B6B6B00FFFFFF00FFDEDE00FFDEDE00FFDEDE00FFDE
-      DE00FFDEDE00E7C6C600DEDEDE00525252005A5A5A000808080008080800DEDE
-      DE006B8484006B8484006B8484006B8484005A73730042635A0042635A00EFEF
-      EF001818180018181800181818004A4A4A0000000000000000005A5A5A00ADC6
-      C600ADC6C600ADC6C600ADC6C600ADC6C600ADC6C600ADC6C600DEF7F7007B9C
-      9C00ADC6C600424242000000000000000000000000005A5A5A00FFFFFF00D6EF
-      E700D6EFE700D6EFE7004A4AFF004A4AFF004A4AFF00D6EFE7004A4AFF004A4A
-      FF004A4AFF00B5B5B50042424200000000005A5A5A00FFFFFF00D6EFE700D6EF
-      E700D6EFE700D6EFE7006B6B6B00FFFFFF00FFDEDE00FFDEDE00FFDEDE00F7F7
-      F700D6D6D600B5B5B5009C9C9C00525252005A5A5A000808080021292900DEE7
-      E7006B848400DEE7E700F7F7F7006B8484006B8484005A73730042635A004263
-      5A00FFFFFF00FFFFFF00FFFFFF002929290000000000000000005A5A5A00B5CE
-      CE00B5CECE00B5CECE00B5CECE00B5CECE00B5CECE00B5CECE00B5CECE00B5CE
-      CE00B5CECE004A4A4A0000000000000000000000000063636300FFFFFF00D6EF
-      EF00D6EFEF00B5B5B5004A4AFF004A4AFF00D6EFEF00D6EFEF00D6EFEF004A4A
-      FF004A4AFF004A4AFF004A4A4A00000000006B6B6B00FFFFFF00DEF7F700DEF7
-      F700DEF7F700DEF7F7006B6B6B00FFFFFF00FFDEDE00FFDEDE00FFDEDE00F7F7
-      F70094949400737373005A5A5A005A5A5A007B7B7B002129290021292900F7F7
-      F700F7F7F700F7F7F70021292900F7F7F7006B8484006B8484005A7373004263
-      5A0042635A00FFFFFF00FFFFFF0031313100000000000000000063636300BDD6
-      D600BDD6D600BDD6D600BDD6D600BDD6D600BDD6D600BDD6D600BDD6D600BDD6
-      D600BDD6D6004A4A4A000000000000000000000000006B6B6B00FFFFFF00DEF7
-      F700B5B5B5004A4AFF004A4AFF00DEF7F700DEF7F700DEF7F700DEF7F700CEEF
-      E7004A4AFF004A4AFF004A4AFF00000000006B6B6B00FFFFFF00DEF7F700DEF7
-      F700DEF7F700F7F7F7006B6B6B00FFFFFF00FFE7EF00FFE7EF00FFE7EF00F7F7
-      F700A5A5A500FFFFFF00FFFFFF005A5A5A005A5A5A0031393900313939003139
-      390031393900313939003139390031393900FFFFFF006B8484006B8484004263
-      5A00FFFFFF00FFFFFF00DEDEDE005252520000000000000000006B6B6B00C6DE
-      DE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DE
-      DE00C6DEDE00525252000000000000000000000000006B6B6B00FFFFFF00B5B5
-      B5004A4AFF004A4AFF004A4AFF00DEF7F700DEF7F700F7F7F700D6D6D600C6C6
-      C600B5B5B5004A4AFF004A4AFF004A4AFF006B6B6B00FFFFFF00DEF7F700DEF7
-      F700DEF7F700F7F7F7006B6B6B00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00CECECE00DEB5BD0073737300000000007B7B7B0039424200394242003942
-      4200394242003942420039424200394242006B6B6B00FFFFFF006B848400FFFF
-      FF00FFFFFF00B5B5B5009C9C9C005252520000000000000000007B7B7B00CEE7
-      E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7
-      E700CEE7E7005A5A5A000000000000000000000000006B6B6B00FFFFFF004A4A
-      FF004A4AFF004A4AFF00DEF7F700DEF7F700DEF7F700F7F7F700949494008C8C
-      8C00737373005A5A5A004A4AFF004A4AFF006B6B6B00FFFFFF00E7FFF700E7FF
-      F700E7FFF700F7F7F700737373007373730073737300737373007B7B7B008484
-      84008484840084848400000000000000000084848400525A5A004A5A5200525A
-      5A00525A5A00525A5A00525A5A00525A5A006B6B6B00FFFFFF00FFFFFF00FFFF
-      FF0094949400737373005A5A5A005A5A5A0000000000000000007B7B7B00D6EF
-      EF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EF
-      EF00D6EFEF00636363000000000000000000000000006B6B6B00FFFFFF00E7FF
-      F7004A4AFF004A4AFF00E7FFF700E7FFF700E7FFF700F7F7F700A5A5A500FFFF
-      FF00FFFFFF00FFFFFF005A5A5A004A4AFF006B6B6B00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00CECECE00B5D6CE007373730000000000000000000000
-      00000000000000000000000000000000000084848400848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C006B6B6B00FFFFFF00FFE7EF00F7F7
-      F700A5A5A500FFFFFF00FFFFFF005A5A5A0000000000000000007B7B7B00DEF7
-      F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7
-      F700DEF7F7006B6B6B000000000000000000000000006B6B6B00FFFFFF00E7FF
-      F700E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700F7F7F700B5B5B500FFFF
-      FF00D6F7EF00B5D6CE006B6B6B00000000007373730073737300737373007373
-      73007B7B7B008484840084848400848484000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000006B6B6B00FFFFFF00FFFFFF00FFFF
-      FF00CECECE00DEB5BD007373730000000000000000000000000084848400DEF7
-      F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7
-      F700DEF7F700737373000000000000000000000000006B6B6B00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CECECE00FFFF
-      FF00B5D6CE007373730000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000007373730073737300737373008484
-      84008484840084848400000000000000000000000000000000007B7B7B008484
-      8400848484008484840084848400848484008484840084848400848484008484
-      8400848484007373730000000000000000000000000073737300737373007373
-      7300737373007B7B7B007B7B7B007B7B7B008484840084848400848484008484
-      8400848484000000000000000000000000000000000000000000000000000000
-      0000000000004A3939004A3939004A3939004A3939004A3939004A3939000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000800
-      00003921210021000000520000006B0808006B0808005A000000290000002910
-      1000080000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000042424200393939003939
-      3900424242004242420042424200313131003939390042424200424242003939
-      3900393939002929290039393900000000000000000000000000000000002952
-      3900315A4A00295239000000000000000000000000002952390031634A00214A
-      3100000000000000000000000000000000000000000000000000080000001000
-      00006B00000084000000AD000000EF101000EF181800BD0000008C0000007300
-      0000310000000800000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007B7B7B00636363006363
-      63006B6B6B006B6B6B006B6B6B005A5A5A00636363006B6B6B007B7B7B006B6B
-      6B005A5A5A005A5A5A0042424200000000000000000000000000315242005284
-      6B00528C6B005A8C73004A6B5A0000000000426B5A005A8473005A9473006394
-      7300214A31000000000000000000000000000000000008000000210000006300
-      0000CE000000AD0000006300000042000000420000005A0000009C000000BD00
-      0000940000002900000008000000000000000000000000000000294A4A00294A
-      4A00294A4A00294A4A00294A4A00000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000848484006B6B6B006363
-      6300737373007373730073737300636363006B6B6B0073737300848484006B6B
-      6B00636363006363630042424200000000000000000000000000294231004A7B
-      63000000000000000000637B7300396352005A7B6B000000000000000000527B
-      6300395A4200000000000000000000000000000000000000000000000000AD00
-      0000F7101000C61010005A000000080000000800000042000000B5000000F708
-      0800C60000006B000000421818000000000000000000000000006B8484004263
-      5A00294A4A00294A4A0000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000008C8C8C006B6B6B006B6B
-      6B007B7B7B007B7B7B007B7B7B006B6B6B006B6B6B007B7B7B00848484007373
-      730063636300636363004A4A4A00000000000000000000000000000000004A6B
-      5A00000000000000000000000000426B5A00000000000000000000000000527B
-      6300000000000000000000000000000000004A31310029000000CE000000CE00
-      0000DE000000CE000000CE000000B5101000B5101000CE000000BD000000DE00
-      0000BD000000AD000000630000003108080000000000000000006B8484004263
-      5A0042635A00294A4A0000000000000000000000000000000000000000000000
-      000000000000294A4A0000000000000000000000000094949400737373007B7B
-      7B008484840084848400848484006B6B6B007373730084848400949494007B7B
-      7B00737373006B6B6B004A4A4A00000000000000000000000000000000004A6B
-      5A005273630000000000315A4A004A7B6B00295A4A00000000004A7363004A6B
-      5A00000000000000000000000000000000004A313100840000009C000000CE00
-      0000E7000000EF000000DE000000AD101000A5181800CE000000D6000000EF00
-      0000DE000000B5000000840000003108080000000000000000006B8484006B84
-      840042635A00294A4A00294A4A00000000000000000000000000000000000000
-      00000000000042635A00294A4A0000000000000000009C9C9C007B7B7B006363
-      6300424242006B6B6B008C8C8C00737373007B7B7B008C8C8C006B6B6B003939
-      39005A5A5A007373730052525200000000000000000000000000000000000000
-      00004A6B5A006B8C7B0052846B006B9C8C006B9C8C0052736300526B63000000
-      00000000000000000000000000000000000052313100940000009C000000E700
-      0000F7212100F7181800EF000000B50000009C080800E7000000F7101000F729
-      2900DE000000B5000000940000004210100000000000000000006B8484000000
-      00006B84840042635A00294A4A00294A4A000000000000000000000000000000
-      0000294A4A0042635A006B84840000000000000000009C9C9C007B7B7B008C8C
-      8C00424242008C8C8C008C8C8C0073737300737373008C8C8C00949494003131
-      310073737300737373005A5A5A00000000000000000000000000000000000000
-      000000000000000000004A4A4A004A4A4A004A4A4A0000000000000000000000
-      0000000000000000000000000000000000004A3939009C000000A5000000BD00
-      0000A5000000CE101000E7000000E7080800E7101000C6000000DE080800C608
-      080094000000A50000009C000000421010000000000000000000000000000000
-      00000000000042635A0042635A00294A4A00294A4A00294A4A00294A4A00294A
-      4A0042635A0042635A00000000000000000000000000A5A5A500848484004A6B
-      630039393900636363004A4A4A003939390031313100424242005A5A5A002121
-      21004A6B63007B7B7B005A5A5A00000000000000000000000000000000000000
-      0000000000004A4A4A006B6B6B004A4A4A006B6B6B004A4A4A00000000000000
-      000000000000000000000000000000000000423131008400000084000000CE00
-      0000CE101000F7393900A5080800840000008C00000063000000D6424200F731
-      3100AD0000009400000073000000290808000000000000000000000000000000
-      0000000000006B84840042635A0042635A0042635A0042635A0042635A004263
-      5A0042635A006B8484000000000000000000000000009C9C9C007B7B7B006B6B
-      6B00525252004A4A4A0063636300212121001010100063636300525252005252
-      52006B6B6B007373730052525200000000000000000000000000000000000000
-      0000000000006B6B6B00848484004A4A4A00848484006B6B6B00000000000000
-      0000000000000000000000000000000000004A3939001000000084000000A500
-      0000DE101000FF4A4A00C6181800CE000000DE000000940000008C000000C608
-      0800BD0000009400000042000000421010000000000000000000000000000000
-      000000000000000000006B84840042635A0042635A0042635A0042635A004263
-      5A006B8484000000000000000000000000000000000094949400737373006B6B
-      6B008C8C8C008C8C8C008C8C8C00212121001010100084848400949494007B7B
-      7B006B6B6B006B6B6B004A4A4A00000000000000000000000000000000000000
-      00004A4A4A006B6B6B00A5A5A50000000000A5A5A5006B6B6B004A4A4A000000
-      0000000000000000000000000000000000000000000000000000840000008400
-      0000FF4A4A00FF9C9C00FF525200FF4A4A00FF636300FF313100E7000000DE00
-      0000AD0000009400000000000000000000000000000000000000000000000000
-      00000000000000000000000000006B8484006B8484006B8484006B8484006B84
-      8400000000000000000000000000000000000000000094949400737373006B6B
-      6B0084848400848484008484840029292900212121007B7B7B008C8C8C007B7B
-      7B006B6B6B006B6B6B004A4A4A00000000000000000000000000000000000000
-      00006B6B6B0084848400A5A5A50000000000A5A5A500848484006B6B6B000000
-      0000000000000000000000000000000000000000000008000000080000001800
-      0000BD181800F74A4A00F7393900F7424200F7424200FF393900F7080800C600
-      0000520000002100000008000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000848484006B6B6B006B6B
-      6B007B7B7B007B7B7B007B7B7B0042424200424242007B7B7B008C8C8C007373
-      7300636363006B6B6B004A4A4A00000000000000000000000000000000000000
-      000084848400A5A5A500000000000000000000000000A5A5A500848484000000
-      0000000000000000000000000000000000000000000000000000080000000800
-      000010000000520000009C0000009C0000009C0000009C000000730000004A00
-      0000180000000800000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007B7B7B006B6B6B006363
-      6300737373007373730073737300636363006B6B6B0073737300848484006B6B
-      6B00636363006363630042424200000000000000000000000000000000000000
-      000084848400A5A5A500000000000000000000000000A5A5A500848484000000
-      0000000000000000000000000000000000000000000000000000000000000800
-      0000211818000000000018000000180000002100000021000000100000002108
-      0800080000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000094949400848484007B7B
-      7B009C9C9C009C9C9C009C9C9C007B7B7B008C8C8C009C9C9C00A5A5A5008C8C
-      8C007B7B7B007B7B7B005A5A5A00000000000000000000000000000000000000
-      0000A5A5A500A5A5A500000000000000000000000000A5A5A500A5A5A5000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000004A3939004A3939004A3939004A3939004A3939004A3939000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000006B6B6B00292929002121
-      2100181818001818180018181800181818001818180018181800181818001818
-      180018181800181818004A4A4A0000000000000000004A4A52004A4A52004A4A
-      52004A4A52004A4A52004A4A52004A4A52004A4A52004A4A52004A4A52004A4A
-      52004A4A52007B94940000000000000000000000000029292900212121001818
-      1800181818001818180018181800181818001818180018181800181818002929
-      2900292929002121210021212100000000000000000031528400315284000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000042424200FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00292929000000000000000000393939007B8C8C00849C
-      94007B9494007B9494007B9494007B9494007B9494007B9494007B9494007B94
-      94007B9494007B9494000000000000000000393939007B9494007B9494006363
-      6300E7E7E700FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7E700D6D6D600E7E7
-      E7005A5A5A007B9494007B9494002929290000000000849CB500315284000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000042424200FFFFFF00C6DE
-      DE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DE
-      DE00C6DEDE00FFFFFF00313131000000000000000000393939007B94940094AD
-      AD0094ADA50094ADA50094ADA50094ADA50094ADA50094ADA50094ADAD0094B5
-      AD0094B5B5007B9494000000000000000000424242007B9494007B9494006B6B
-      6B00FFFFFF00E7E7E700A5BDB500FFFFFF00FFFFFF00EFEFEF00E7E7E700E7E7
-      E7006B6B6B007B9494007B9494002929290000000000849CB500315284000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004A4A4A00FFFFFF00BDDE
-      D600BDDED600BDDED600BDDED600BDDED600BDDED600BDDED600BDDED600BDDE
-      D600BDDED600FFFFFF00313131000000000000000000424242005A6363009CB5
-      AD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD009CB5
-      B5009CBDB500A5BDBD007B949400000000004A4A4A0094ADA5008CA5A5007B7B
-      7B00FFFFFF005A736B008CA5A500FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7006B6B6B00849C9C00849C9C003939390000000000849CB500315284000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004A4A4A00FFFFFF00CEE7
-      E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7
-      E700CEE7E700FFFFFF003131310000000000000000004A4A4A005A5A5A0094B5
-      AD00A5BDB500A5BDB500A5BDB500A5BDB500A5BDB500A5BDB500A5BDB500A5BD
-      B500A5BDBD00ADCEC6007B949400000000004A4A4A0094ADA5008CA5A5007B7B
-      7B00FFFFFF005A736B008CA5A500FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7006B6B6B00849C9C00849C9C003939390000000000849CB500315284000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004A4A4A00FFFFFF00CEE7
-      E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7
-      E700CEE7E700FFFFFF00393939000000000000000000525252005A5A5A007B8C
-      8C00ADC6C600A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BD
-      BD00ADC6C600BDD6CE007B94940000000000525252009CB5B5009CB5AD009C9C
-      9C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E7E7
-      E7007B7B7B00849C9C00849C9C003939390000000000849CB500315284000000
-      0000000000000000000000000000000000000000520000005200000052000000
-      520000005200000052000000000000000000000000005A5A5A00FFFFFF00D6EF
-      E700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EF
-      E700D6EFE700FFFFFF004242420000000000000000005A5A5A005A5A5A00737B
-      7B00B5CEC600ADC6BD00ADC6BD00ADC6BD00ADC6C600ADC6BD00ADC6BD00B5CE
-      C600B5CECE00BDDED6007B9494000000000052525200A5BDB500A5BDB500A5BD
-      B50094B5AD008CADA5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5
-      A5008CA5A5008CA5A5008CA5A5004242420000000000849CB500315284000000
-      52000000520000005200000052000000520008008C0008008C0008008C000800
-      8C0000005200000000000000000000000000000000005A5A5A00FFFFFF00D6EF
-      E700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EF
-      E700D6EFE700FFFFFF00424242000000000000000000636363006B6B6B006363
-      6300A5B5B500BDD6D600BDD6D600B5D6CE00B5D6CE00B5CECE00B5CECE00B5CE
-      CE00B5D6CE00BDD6D600C6DEDE007B9494005A5A5A00A5C6BD008CA59C008CA5
-      A500849C9C007B948C00738C8400738C8400738C8400738C8C00738C8C00738C
-      8C00738C8C006B8484008CADA5004242420000000000849CB500315284000800
-      8C0008008C0008008C000800C6000800C60008008C000800A5000800A5000000
-      5200000000000000000000000000000000000000000063636300FFFFFF00D6EF
-      EF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EF
-      EF00D6EFEF00FFFFFF004A4A4A0000000000000000006B6B6B007B7373006B6B
-      6B007B848400B5CECE00B5CECE00BDD6D600BDD6D600BDD6D600BDD6D600BDD6
-      D600BDD6D600BDDED600CEE7DE007B9494005A5A5A00ADC6BD0094ADA500E7E7
-      E700F7F7F700F7F7F700EFEFEF00EFEFEF00EFEFEF00EFEFEF00F7F7F700EFEF
-      EF00DEDEDE0073948C0094ADAD004A4A4A0000000000849CB500315284000800
-      A5000800A5000800A50008008C000800C60008008C0008008C00000052000000
-      000000000000000000000000000000000000000000006B6B6B00FFFFFF00DEF7
-      F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700CEEF
-      E700C6DEDE00DEDEDE0052525200000000000000000073737300847B7B007B7B
-      7B006B6B6B007373730073737300737373006B736B00ADC6BD00CEE7E700C6DE
-      D600C6DED600C6DED600C6E7DE007B94940063636300ADC6C60094ADAD00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00F7F7F7007B94940094ADAD004A4A4A0000000000849CB500315284000800
-      A5000800A50008008C000800C6000800C60008008C000800A500000052000000
-      000000000000000000000000000000000000000000006B6B6B00FFFFFF00DEF7
-      F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700F7F7F700D6D6D600C6C6
-      C600B5B5B5009C9C9C005252520000000000000000007B7B7B00848484008484
-      8400848484008484840084848400848484007B7B7B00848C8400D6EFE700DEF7
-      F700DEF7F700DEF7F700E7F7F7007B9494006B6B6B00ADCEC6009CB5AD00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00F7F7F7007B9C94009CB5B5005252520000000000849CB500315284000800
-      A5000800A5000800A50008008C000800C60008008C0008008C000800A5000000
-      520000000000000000000000000000000000000000006B6B6B00FFFFFF00DEF7
-      F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700F7F7F700949494008C8C
-      8C00737373005A5A5A005A5A5A000000000000000000848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008484840084848400848C
-      8400848C8400848C840084848400000000007B7B7B00CEE7DE00A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF008CA5A500ADC6C6005A5A5A0000000000849CB500315284000800
-      A5000800A50008008C000800C6000800C60008008C000800A5000800A5000800
-      A50000005200000000000000000000000000000000006B6B6B00FFFFFF00E7FF
-      F700E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700F7F7F700A5A5A500FFFF
-      FF00FFFFFF00FFFFFF005A5A5A0000000000000000008C8C8C00949494008C94
-      8C008C94940094949400949494008C8C8C007B7B7B007B7B7B00737373007373
-      7300737373007373730000000000000000007B7B7B00D6EFE700A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF0094ADAD00ADC6C6006363630000000000849CB500315284000800
-      A5000800A5000800A50008008C000800C6000000520000005200000052000000
-      520000005200000052000000000000000000000000006B6B6B00FFFFFF00E7FF
-      F700E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700F7F7F700B5B5B500FFFF
-      FF00D6F7EF00B5D6CE006B6B6B000000000000000000949494009C9C9C009C9C
-      9C009C9C9C009C9C9C009C9C9C00949494000000000000000000000000000000
-      0000000000000000000000000000000000007B7B7B00D6F7EF00A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF0094ADA500ADCEC6006B6B6B0000000000849CB500315284000000
-      5200000052000000520000005200000052000000000000000000000000000000
-      000000000000000000000000000000000000000000006B6B6B00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CECECE00FFFF
-      FF00B5D6CE0073737300000000000000000000000000000000008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C00000000000000000000000000000000000000
-      00000000000000000000000000000000000084848400DEF7F700A5BDB500FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00F7F7F7009CB5AD00B5CECE007373730000000000849CB500849CB5000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000073737300737373007373
-      7300737373007B7B7B007B7B7B007B7B7B008484840084848400848484008484
-      8400848484000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000848484008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C0084848400000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000424D3E000000000000003E000000
-      2800000040000000900000000100010000000000800400000000000000000000
-      000000000000000000000000FFFFFF0000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000FC008001FFFF0000FC008001FFFF
-      0000FC008001FFFF0000E0008000FFFF0000E000800018C70000E00080008C63
-      000000008000C631000000008000E318000000008000E318000000008001C631
-      0000000780018C6300000007800118C7000000078001FFFF0000003F8001FFFF
-      0000003F8003FFFF0000003F8007FFFF000080018001FFFF000000000000FFFF
-      000000000000F03F000000000000E00F000000000000C007000000000000C007
-      000000000000C007000000000000C003000000000000C003000000000000C003
-      000000000000C007000000000000C00F000000000000FFFF000000000000FFFF
-      000000000000FFFF000080018001FFFFFFF9FFFFFFFF0000FFF0FFFFFFFF0000
-      0010FE7FFDFF00000001FE7FF8FF00000001FFFFF8FF00000000FE7FF27F0000
-      0000FE3FE27F00000001FF1FE73F00000003FFCFEF3F00000003FFCFFF8F0000
-      0003F98FFF830000C003F81FFFC30000C003FC3FFFF30000C003FFFFFFFF0000
-      F803FFFFFFFF0000F803FFFFFFFF0000F000FC000000FC1FF000FC000000F007
-      F000FC000000F007F000E0000000F0070000E0000000F0070000E0000000E003
-      000000000000800100000000000080010000000000008001000000000000C003
-      00000007000080010000000700000000000F000700000000000F003F00000000
-      000F003F00008001000F003F0000FC3FFFFF0007C0038001FC000007C0038001
-      FC000007C003800100000007C003800100000007C003800100000007C0038001
-      00000007C003800100000000C003800100000000C003800100000000C0038001
-      00000000C003800000010000C003800000030000C0038000007F0000C0038001
-      00FFFF01C0038003FFFFFF03C0038007F81FFFFFFFFFFFFFE007FFFF8001E38F
-      C003FFFF8001C1078001C1FF8001CC678001C3FF8001EEEF0000C3FB8001E44F
-      0000C1F98001F01F0000D0F18001FC7F0000F8038001F83F0000F8038001F83F
-      0000FC078001F11F8001FE0F8001F11F8001FFFF8001F39FC003FFFF8001F39F
-      E007FFFF8001F39FF81FFFFFFFFFFFFF8001800380019FFF8001800300009FFF
-      8001800300009FFF8001800100009FFF8001800100009FFF8001800100009F03
-      8001800100008007800180000000800F800180000000801F800180000000801F
-      800180000000800F80018001000080078001800300008003800180FF000080FF
-      8003C1FF00009FFF8007FFFF8001FFFF00000000000000000000000000000000
-      000000000000}
+      9CFF3139ADFF000000003139ADFF10219CFF0000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00003139ADFF4A5AB5FF3139ADFF000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000010219CFF3139ADFF10219CFF000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000010219CFF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000848484FF848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF848484FF848484FF8B7C65FF8B7C65FF8B7C65FF8B7C
+      65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C
+      65FF8B7C65FF8B7C65FF737373FF7B7B7BFF86765EFFFFFFFFFF86765EFF8676
+      5EFFFFFFFFFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF8676
+      5EFF86765EFF86765EFF6B6B6BFF7B7B7BFF826F57FF826F57FF393939FF826F
+      57FF826F57FF393939FF826F57FF826F57FF826F57FF826F57FF826F57FF826F
+      57FF826F57FF826F57FF636363FF7B7B7BFF7E6950FF7E6950FF7E6950FF7E69
+      50FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E69
+      50FF7E6950FF7E6950FF5A5A5AFF6B6B6BFF7A644AFFFFFFFFFF7A644AFF7A64
+      4AFFFFFFFFFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A64
+      4AFF7A644AFF7A644AFF525252FF636363FF775F44FF775F44FF393939FF775F
+      44FF775F44FF393939FF775F44FF775F44FF775F44FF775F44FF775F44FF775F
+      44FF775F44FF775F44FF4A4A4AFF5A5A5AFF745B40FF745B40FF745B40FF745B
+      40FF745B40FF745B40FFFFFFFFFF745B40FF745B40FF745B40FF745B40FF745B
+      40FFFFFFFFFF745B40FF4A4A4AFF5A5A5AFF71573CFF71573CFF71573CFF7157
+      3CFF71573CFF71573CFF71573CFF393939FF71573CFF71573CFF71573CFF7157
+      3CFF71573CFF393939FF424242FF525252FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF424242FF525252FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF393939FF4A4A4AFF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF393939FF4A4A4AFF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF393939FF424242FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FFFFFFFFFF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FFFFFFFFFF6F5438FF292929FF393939FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF393939FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF393939FF292929FF292929FF292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF212121FF848484FF848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF848484FF848484FF8B7C65FF8B7C65FF8B7C65FF8B7C
+      65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C
+      65FF8B7C65FF8B7C65FF737373FF7B7B7BFF86765EFF86765EFF86765EFF8676
+      5EFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF8676
+      5EFF86765EFF86765EFF6B6B6BFF7B7B7BFF826F57FF826F57FFFFFFFFFF826F
+      57FF826F57FF826F57FFFFFFFFFF826F57FF826F57FF826F57FFFFFFFFFF826F
+      57FF826F57FF826F57FF636363FF7B7B7BFF7E6950FF7E6950FF7E6950FF3939
+      39FF7E6950FF7E6950FF7E6950FF393939FF7E6950FF7E6950FF7E6950FF3939
+      39FF7E6950FF7E6950FF5A5A5AFF6B6B6BFF7A644AFF7A644AFF7A644AFF7A64
+      4AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A64
+      4AFF7A644AFF7A644AFF525252FF636363FF775F44FF775F44FF775F44FF775F
+      44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F
+      44FF775F44FF775F44FF4A4A4AFF5A5A5AFF745B40FF745B40FFFFFFFFFF745B
+      40FF745B40FF745B40FFFFFFFFFF745B40FF745B40FF745B40FFFFFFFFFF745B
+      40FF745B40FF745B40FF4A4A4AFF5A5A5AFF71573CFF71573CFF71573CFF3939
+      39FF71573CFF71573CFF71573CFF393939FF71573CFF71573CFF71573CFF3939
+      39FF71573CFF71573CFF424242FF525252FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF424242FF525252FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF393939FF4A4A4AFF6F5438FF6F5438FFFFFFFFFF6F54
+      38FF6F5438FF6F5438FFFFFFFFFF6F5438FF6F5438FF6F5438FFFFFFFFFF6F54
+      38FF6F5438FF6F5438FF393939FF4A4A4AFF6F5438FF6F5438FF6F5438FF3939
+      39FF6F5438FF6F5438FF6F5438FF393939FF6F5438FF6F5438FF6F5438FF3939
+      39FF6F5438FF6F5438FF393939FF424242FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF292929FF393939FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF292929FF292929FF292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF212121FF00000000848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF00000000848484FFDEF7F7FFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7
+      F7FF9CB5ADFFB5CECEFF737373FF7B7B7BFFD6F7EFFFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFF8C8C8CFF6B6B6BFF6B6B6BFFDEDEDEFFFFFFFFFFFFFFFFFFFFFF
+      FFFF94ADA5FFADCEC6FF6B6B6BFF7B7B7BFFD6EFE7FFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFDEDEDEFF6B6B6BFFFFFFFFFFFFFFFFFFFFFF
+      FFFF94ADADFFADC6C6FF636363FF7B7B7BFFCEE7DEFFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFF6B6B6BFF6B6B6BFFDEDEDEFFFFFFFFFFFFFFFFFFFFFF
+      FFFF8CA5A5FFADC6C6FF5A5A5AFF6B6B6BFFADCEC6FF9CB5ADFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFDEDEDEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7
+      F7FF7B9C94FF9CB5B5FF525252FF636363FFADC6C6FF94ADADFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFF6B6B6BFF6B6B6BFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7
+      F7FF7B9494FF94ADADFF4A4A4AFF5A5A5AFFADC6BDFF94ADA5FFE7E7E7FFF7F7
+      F7FFF7F7F7FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFF7F7F7FFEFEFEFFFDEDE
+      DEFF73948CFF94ADADFF4A4A4AFF5A5A5AFFA5C6BDFF8CA59CFF8CA5A5FF849C
+      9CFF7B948CFF738C84FF738C84FF738C84FF738C8CFF738C8CFF738C8CFF738C
+      8CFF6B8484FF8CADA5FF424242FF525252FFA5BDB5FFA5BDB5FFA5BDB5FF94B5
+      ADFF8CADA5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+      A5FF8CA5A5FF8CA5A5FF424242FF525252FF9CB5B5FF9CB5ADFF9C9C9CFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF7B7B
+      7BFF849C9CFF849C9CFF393939FF4A4A4AFF94ADA5FF8CA5A5FF7B7B7BFFFFFF
+      FFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF6B6B
+      6BFF849C9CFF849C9CFF393939FF4A4A4AFF94ADA5FF8CA5A5FF7B7B7BFFFFFF
+      FFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF6B6B
+      6BFF849C9CFF849C9CFF393939FF424242FF7B9494FF7B9494FF6B6B6BFFFFFF
+      FFFFE7E7E7FFA5BDB5FFFFFFFFFFFFFFFFFFEFEFEFFFE7E7E7FFE7E7E7FF6B6B
+      6BFF7B9494FF7B9494FF292929FF393939FF7B9494FF7B9494FF636363FFE7E7
+      E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FFD6D6D6FFE7E7E7FF5A5A
+      5AFF7B9494FF7B9494FF292929FF00000000292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF0000000000000000848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF00000000848484FFDEF7F7FFA5BDB5FF212929FF2129
+      29FF212929FF212929FF212929FFFFFFFFFF212929FF212929FF212929FF2129
+      29FF9CB5ADFFB5CECEFF737373FF7B7B7BFFD6F7EFFFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF182118FF182118FF182118FFC6C6
+      C6FF94ADA5FFADCEC6FF6B6B6BFF7B7B7BFFD6EFE7FFA5BDB5FF081810FF0818
+      10FF081810FF081810FF081810FF081810FF081810FF081810FF081810FF0818
+      10FF94ADADFFADC6C6FF636363FF7B7B7BFFCEE7DEFFA5BDB5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFFFFFFFF080808FF080808FFC6C6
+      C6FF8CA5A5FFADC6C6FF5A5A5AFF6B6B6BFFADCEC6FF9CB5ADFFFFFFFFFFEF00
+      00FFEF0000FFEF0000FFEF0000FFEF0000FFFFFFFFFF000000FF000000FF0000
+      00FF7B9C94FF9CB5B5FF525252FF636363FFADC6C6FF94ADADFFFFFFFFFF8C00
+      00FF8C0000FF8C0000FF8C0000FF8C0000FFFFFFFFFF000000FF000000FFC6C6
+      C6FF7B9494FF94ADADFF4A4A4AFF5A5A5AFFADC6BDFF94ADA5FFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF000000FF0000
+      00FF73948CFF94ADADFF4A4A4AFF5A5A5AFFA5C6BDFF8CA59CFF8CA5A5FF849C
+      9CFF7B948CFF738C84FF738C84FF738C84FF738C8CFF738C8CFF738C8CFF738C
+      8CFF6B8484FF8CADA5FF424242FF525252FFA5BDB5FFA5BDB5FFA5BDB5FF94B5
+      ADFF8CADA5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+      A5FF8CA5A5FF8CA5A5FF424242FF525252FF9CB5B5FF9CB5ADFF9C9C9CFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF7B7B
+      7BFF849C9CFF849C9CFF393939FF4A4A4AFF94ADA5FF8CA5A5FF7B7B7BFFFFFF
+      FFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF6B6B
+      6BFF849C9CFF849C9CFF393939FF4A4A4AFF94ADA5FF8CA5A5FF7B7B7BFFFFFF
+      FFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FF6B6B
+      6BFF849C9CFF849C9CFF393939FF424242FF7B9494FF7B9494FF6B6B6BFFFFFF
+      FFFFE7E7E7FFA5BDB5FFFFFFFFFFFFFFFFFFEFEFEFFFE7E7E7FFE7E7E7FF6B6B
+      6BFF7B9494FF7B9494FF292929FF393939FF7B9494FF7B9494FF636363FFE7E7
+      E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7E7FFD6D6D6FFE7E7E7FF5A5A
+      5AFF7B9494FF7B9494FF292929FF00000000292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000C6CED6FFBDC6C6FF8484
+      8CFF737B7BFF525252FF525252FF525252FF6B7373FF848C8CFFBDBDC6FF0000
+      00000000000000000000000000000000000000000000949C9CFF4A4A4AFF737B
+      7BFF737B7BFF949C9CFF94949CFF94949CFF7B8484FF6B6B73FF525252FFA5A5
+      ADFF00000000000000000000000000000000000000004A5252FF84848CFF7373
+      7BFF42424AFF101010FF181818FF101010FF525252FF5A6363FF8C8C94FF4242
+      42FF949C9CFF00000000000000000000000000000000949C9CFF212121FF0000
+      00FF000000FF292929FF080808FF000000FF000000FF393939FF212929FF7B84
+      84FF8C8C8CFF000000000000000000000000000000005A5A63FF848C8CFF0000
+      00FF424242FFC6CECEFF000000FF000000FF000000FF84848CFF313939FF2931
+      31FFB5BDBDFF000000000000000000000000000000009CA5ADFF9CA5ADFF2129
+      29FF000000FF000000FF000000FF000000FF000000FF94949CFF848C8CFF1821
+      21FF0000000000000000000000000000000000000000C6CECEFFADB5BDFFC6CE
+      D6FF394242FF000000FF000000FF181818FFADB5B5FFADB5B5FF101010FF7B7B
+      84FF0000000000000000000000000000000000000000C6CED6FF292929FF636B
+      6BFF9C9CA5FFADB5B5FFADB5B5FFBDC6C6FF737B7BFF181818FF848C8CFFC6CE
+      D6FF000000000000000000000000000000000000000000000000BDC6C6FF848C
+      8CFF424242FF393939FF393939FF394242FF7B8484FFBDC6CEFFC6CED6FF0000
+      000000000000000000000000000000000000000000000000000000000000C6CE
+      D6FFADB5B5FFADB5B5FFADB5B5FFADB5B5FFC6CED6FF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000848484FF848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF848484FF848484FF525A5AFF4A5A52FF525A5AFF525A
+      5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A
+      5AFF4A5A52FF4A5A52FF737373FF7B7B7BFF292931FF292931FF292931FF2929
+      31FF292931FF292931FF292931FF292931FF292931FF292931FF292931FF2929
+      31FF292931FF292931FF6B6B6BFF7B7B7BFF212929FF212929FF212929FF2129
+      29FF212929FF212929FF212929FF212929FF212929FF212929FF212929FF2129
+      29FF5252ADFF5252ADFF636363FF7B7B7BFF182121FF182121FF182121FF1821
+      21FF182121FF182121FF182121FF4A4AADFF182121FF182121FF182121FF1821
+      21FF182121FF182121FF5A5A5AFF6B6B6BFF3939ADFF3939ADFF3939ADFF3939
+      ADFF3939ADFF3939ADFF3939ADFF3939ADFF101810FF101810FF101810FF1018
+      10FF101810FF101810FF525252FF636363FF081008FF081008FF081008FF0810
+      08FF081008FF081008FF081008FF081008FF081008FF081008FF081008FF0810
+      08FF2929ADFF2929ADFF4A4A4AFF5A5A5AFF000808FF000808FF000808FF0008
+      08FF000808FF000808FF000808FF000808FF000808FF000808FF000808FF0008
+      08FF000808FF000808FF4A4A4AFF5A5A5AFF080808FF080808FF080808FF0808
+      08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0000
+      00FF000000FF000000FF424242FF525252FF0000ADFF0000ADFF0000ADFF0000
+      ADFF0000ADFF0000ADFF0000ADFF0000ADFF0000ADFF0000ADFF080808FF0000
+      00FF0000ADFF0000ADFF424242FF525252FF0000A5FF0000A5FF0000A5FF0000
+      9CFF00009CFF00009CFF0000A5FF0000A5FF0000A5FF0000A5FF000000FF0000
+      00FF000000FF000000FF393939FF4A4A4AFF000094FF000094FF000094FF0000
+      94FF000094FF000094FF000094FF000094FF000094FF000094FF000000FF0000
+      00FF000000FF000000FF393939FF4A4A4AFF000084FF000084FF000084FF0000
+      84FF000084FF000084FF000084FF000084FF000084FF000084FF000000FF0000
+      00FF000084FF000084FF393939FF424242FF000073FF000073FF000073FF0000
+      73FF000073FF000073FF000073FF000073FF000073FF000073FF000000FF0000
+      00FF000000FF000000FF292929FF393939FF000063FF000063FF000063FF0000
+      63FF00006BFF000063FF000063FF000063FF00006BFF000063FF000000FF0000
+      00FF000000FF000000FF292929FF292929FF292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF212121FF425A52FF425A52FF425A52FF425A52FF425A
+      52FF425A52FF425A52FF425A52FF425A52FF39524AFF00000000000000000000
+      0000000000000000000000000000425A52FF39524AFF39524AFF39524AFF3952
+      4AFF39524AFF39524AFF39524AFF39524AFF294239FF00000000000000000000
+      0000000000000000000000000000425A52FF39524AFF39524AFF39524AFF3952
+      4AFF39524AFF39524AFF39524AFF39524AFF294239FF00000000000000000000
+      0000000000000000000000000000425A52FF39524AFF39524AFF5A736BFF5A73
+      6BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF4263
+      5AFF000000000000000000000000425A52FF39524AFF39524AFF5A736BFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF294A
+      4AFF000000000000000000000000425A52FF39524AFF39524AFF5A736BFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF294A
+      4AFF000000000000000000000000425A52FF39524AFF39524AFF5A736BFF4263
+      5AFF42635AFF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5A
+      B5FF4A5AB5FF4A5AB5FF3139ADFF425A52FF39524AFF39524AFF5A736BFF4263
+      5AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF425A52FF39524AFF39524AFF5A736BFF4263
+      5AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF39524AFF294239FF294239FF5A736BFF4263
+      5AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF0000000000000000000000005A736BFF4263
+      5AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF0000000000000000000000005A736BFF4263
+      5AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF00000000000000000000000042635AFF294A
+      4AFF294A4AFF4A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF000000000000000000000000000000000000
+      0000000000004A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF000000000000000000000000000000000000
+      0000000000004A5AB5FF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF10219CFF000000000000000000000000000000000000
+      0000000000003139ADFF10219CFF10219CFF10219CFF10219CFF10219CFF1021
+      9CFF10219CFF10219CFF10219CFF00000000737373FF737373FF737373FF7373
+      73FF7B7B7BFF7B7B7BFF7B7B7BFF848484FF848484FF848484FF848484FF8484
+      84FF000000000000000000000000000000006B6B6BFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCECECEFFFFFFFFFFB5D6
+      CEFF737373FF0000000000000000000000006B6B6BFFFFFFFFFFE7FFF7FFE7FF
+      F7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7F7FFB5B5B5FFFFFFFFFFD6F7
+      EFFFB5D6CEFF6B6B6BFF00000000000000006B6B6BFFFFFFFFFFE5FEF6FFE5FD
+      F6FFE5FDF6FFE5FEF6FFE6FEF6FFE5FDF6FFF7F7F7FFA5A5A5FFFFFFFFFFFFFF
+      FFFFFFFFFFFF5A5A5AFF00000000000000006B6B6BFFFFFFFFFFE3FBF4FFE3FB
+      F4FFE3FBF3FFE3FBF4FFE3FCF4FFE3FBF4FFF7F7F7FF949494FF8C8C8CFF7373
+      73FF5A5A5AFF5A5A5AFF00000000000000006B6B6BFFFFFFFFFFE0F9F2FFE1F9
+      F2FFE0F8F2FFE0F8F2FFE0F8F2FFE1F9F2FFF7F7F7FFD6D6D6FFC6C6C6FFB5B5
+      B5FF9C9C9CFF525252FF00000000000000006B6B6BFFFFFFFFFFDEF6F0FFDEF6
+      F0FFDDF5F0FFDDF5EFFFDDF5F0FFBD4242FFDDF5EFFFDDF5F0FFDEF5F0FFC6DE
+      DEFFDEDEDEFF525252FF0000000000000000636363FFFFFFFFFFDAF2EDFFDAF2
+      EDFFDAF2EDFFDAF2EDFFBD4242FFBD4242FFBD4242FFBD4242FFBD4242FFBD42
+      42FFBD4242FFBD4242FFBD4242FF000000005A5A5AFFFFFFFFFFD7EEEAFFD7EE
+      EBFFD6EEEBFFB23E3EFFB23E3EFFB23E3EFFB23E3EFFB33F3FFFB23E3EFFB23E
+      3EFFB23E3EFFB23E3EFFB23E3EFF000000005A5A5AFFFFFFFFFFD3EBE8FFD3EB
+      E8FFA33939FFA33939FFA33939FFA33939FFA33939FFA33939FFA33939FFA339
+      39FFA33939FFA33939FFA33939FF000000004A4A4AFFFFFFFFFFD0E8E5FFD0E8
+      E6FFCFE8E5FF923333FF923333FF923333FF923333FF923333FF923333FF9233
+      33FF923333FF923333FF923333FF000000004A4A4AFFFFFFFFFFCDE5E3FFCCE5
+      E3FFCDE5E3FFB5B5B5FF812D2DFF812D2DFF812D2DFF812D2DFF812D2DFF812D
+      2DFF812D2DFF812D2DFF812D2DFF000000004A4A4AFFFFFFFFFFCAE2E1FFCAE2
+      E1FFCAE2E1FFCAE2E1FFB5B5B5FF722828FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5
+      B5FFB5B5B5FF181818FFB5B5B5FF00000000424242FFFFFFFFFFC8E0E0FFC8E0
+      DFFFC8E0E0FFC8E0E0FFC8E0DFFFB5B5B5FFC8DFDFFFC7DFDFFFC8DFE0FFC8E0
+      DFFFFFFFFFFF313131FF0000000000000000424242FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFF292929FF00000000000000006B6B6BFF292929FF212121FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+      18FF181818FF4A4A4AFF00000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000687F7FFF798D8DFF879999FF000000000000
+      0000687F7FFF798D8DFF879999FF0000000000000000687F7FFF798D8DFF8799
+      99FF00000000000000000000000000000000425454FF5A7373FF788C8CFF0000
+      000000000000425454FF5A7373FF788C8CFF0000000000000000425454FF5A73
+      73FF788C8CFF00000000000000000000000000000000425454FF5A7373FF788C
+      8CFF0000000000000000425454FF5A7373FF788C8CFF00000000000000004254
+      54FF5A7373FF788C8CFF00000000000000000000000000000000425454FF5A73
+      73FF788C8CFF0000000000000000425454FF5A7373FF788C8CFF000000000000
+      0000425454FF5A7373FF788C8CFF000000000000000000000000788C8CFF5A73
+      73FF425454FF0000000000000000788C8CFF5A7373FF425454FF000000000000
+      0000788C8CFF5A7373FF425454FF0000000000000000788C8CFF5A7373FF4254
+      54FF0000000000000000788C8CFF5A7373FF425454FF0000000000000000788C
+      8CFF5A7373FF425454FF0000000000000000788C8CFF5A7373FF425454FF0000
+      000000000000788C8CFF5A7373FF425454FF0000000000000000788C8CFF5A73
+      73FF425454FF00000000000000004E6363FF425555FF364545FF000000000000
+      00004E6363FF425555FF364545FF00000000000000004E6363FF425555FF3645
+      45FF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000008C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF737373FFFFFFFFFFD3D3D3FFD3D3D3FFD3D3
+      D3FFFFFFFFFFA2A2A2FFBBBBBBFF949494FF949494FFBBBBBBFFA2A2A2FFFFFF
+      FFFFFFFFFFFFFFFFFFFF737373FF6B6B6BFFFFFFFFFFE9E9E9FFE9E9E9FFFFFF
+      FFFFFFFFFFFFD3D3D3FFD3D3D3FFFFFFFFFFFFFFFFFFD3D3D3FFD3D3D3FFFFFF
+      FFFFFFFFFFFFFFFFFFFF6B6B6BFF636363FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFF636363FF5A5A5AFFC2975CFFC2975CFFC2975CFFC297
+      5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC297
+      5CFFC2975CFFC2975CFF5A5A5AFF525252FFC2975CFFC2975CFFC2975CFFC297
+      5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC297
+      5CFFC2975CFFC2975CFF525252FF4A4A4AFFC2975CFFCEAD82FFD6BB99FFC297
+      5CFFC2975CFFE1CEB7FFC2975CFFCEAD82FFCEAD82FFC2975CFFE1CEB7FFE1CE
+      B7FFDAC2A3FFC2975CFF4A4A4AFF4A4A4AFFC2975CFFD2B48EFFF4EDE5FFC69E
+      6AFFDAC2A3FFE5D5C1FFC2975CFFDEC8AEFFE1CEB7FFC2975CFFE1CEB7FFC297
+      5CFFE5D5C1FFC2975CFF4A4A4AFF424242FFC2975CFFD2B48EFFD6BB99FFE9DB
+      CAFFDEC8AEFFE1CEB7FFC2975CFFE1CEB7FFE1CEB7FFC2975CFFE9DBCAFFE1CE
+      B7FFE1CEB7FFC2975CFF424242FF424242FFC2975CFFD2B48EFFD2B48EFFD2B4
+      8EFFC2975CFFE1CEB7FFDAC2A3FFE5D5C1FFE5D5C1FFDAC2A3FFE1CEB7FFC297
+      5CFFC2975CFFC2975CFF424242FF393939FFC2975CFFCAA676FFCAA676FFC297
+      5CFFC2975CFFD2B48EFFD2B48EFFC2975CFFC2975CFFD2B48EFFD2B48EFFC297
+      5CFFC2975CFFC2975CFF393939FF393939FFC2975CFFC2975CFFC2975CFFC297
+      5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC297
+      5CFFC2975CFFC2975CFF393939FF393939FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFF393939FF292929FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFF292929FF292929FFFFFFFFFFDEDEDEFFC7C7C7FFFFFF
+      FFFFFFFFFFFFA2A2A2FFFFFFFFFFDEDEDEFFDEDEDEFFFFFFFFFFA2A2A2FFA2A2
+      A2FFBBBBBBFFFFFFFFFF292929FF292929FF292929FF292929FF292929FF2929
+      29FF292929FF292929FF292929FF292929FF292929FF292929FF292929FF2929
+      29FF292929FF292929FF292929FF848484FF848484FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF848484FF848484FF848484FF8B7C65FF8B7C65FF8B7C65FF8B7C
+      65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF413C34FF8B7C
+      65FF8B7C65FF8B7C65FF737373FF7B7B7BFF86765EFF86765EFF86765EFF8676
+      5EFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF403A31FF8676
+      5EFF86765EFF86765EFF6B6B6BFF7B7B7BFF826F57FF826F57FF826F57FF826F
+      57FF826F57FF826F57FF826F57FF826F57FF826F57FF826F57FF3E372FFF826F
+      57FF826F57FF826F57FF636363FF7B7B7BFF7E6950FF7E6950FF7E6950FF7E69
+      50FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF3D352CFF7E69
+      50FF7E6950FF7E6950FF5A5A5AFF6B6B6BFF7A644AFF7A644AFF7A644AFF7A64
+      4AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF3B332AFF7A64
+      4AFF7A644AFF7A644AFF525252FF636363FF775F44FF775F44FF775F44FF775F
+      44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F44FF3A3228FF775F
+      44FF775F44FF775F44FF4A4A4AFF5A5A5AFF745B40FF745B40FF745B40FF745B
+      40FF745B40FF745B40FF745B40FF745B40FF745B40FF745B40FF393026FF745B
+      40FF745B40FF745B40FF4A4A4AFF5A5A5AFF71573CFF71573CFF71573CFF7157
+      3CFF71573CFF71573CFF71573CFF71573CFF71573CFF71573CFF382F25FF7157
+      3CFF71573CFF71573CFF424242FF525252FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF372E24FF6F54
+      38FF6F5438FF6F5438FF424242FF525252FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF372E24FF6F54
+      38FF6F5438FF6F5438FF393939FF4A4A4AFF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF372E24FF6F54
+      38FF6F5438FF6F5438FF393939FF4A4A4AFF372E24FF372E24FF372E24FF372E
+      24FF372E24FF372E24FF372E24FF372E24FF372E24FF372E24FF372E24FF6F54
+      38FF6F5438FF6F5438FF393939FF424242FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF292929FF393939FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+      38FF6F5438FF6F5438FF292929FF292929FF292929FF212121FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF292929FF2929
+      29FF212121FF212121FF212121FF
+    }
   end
   object SaveDialog: TSaveDialog
-    DefaultExt = 'wad'
+    DefaultExt = '.wad'
     Filter = 'Карты Doom 2D: Forever (*.wad)|*.wad|Все файлы (*.*)|*.*'
     Options = [ofHideReadOnly, ofNoChangeDir, ofPathMustExist, ofNoReadOnlyReturn, ofEnableSizing, ofDontAddToRecent]
-    Left = 64
-    Top = 64
+    left = 64
+    top = 64
   end
   object MainMenu: TMainMenu
     Images = ImageList
-    Left = 96
-    Top = 64
+    left = 96
+    top = 64
     object miMenuFile: TMenuItem
       Caption = 'Файл'
       object miNewMap: TMenuItem
         Caption = 'Новая карта'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000006B6B
+          6BFF292929FF212121FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF181818FF181818FF181818FF4A4A4AFF00000000000000004242
+          42FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF292929FF00000000000000004242
+          42FFFFFFFFFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+          DEFFC6DEDEFFC6DEDEFFC6DEDEFFFFFFFFFF313131FF00000000000000004A4A
+          4AFFFFFFFFFFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDE
+          D6FFBDDED6FFBDDED6FFBDDED6FFFFFFFFFF313131FF00000000000000004A4A
+          4AFFFFFFFFFFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7
+          E7FFCEE7E7FFCEE7E7FFCEE7E7FFFFFFFFFF313131FF00000000000000004A4A
+          4AFFFFFFFFFFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7
+          E7FFCEE7E7FFCEE7E7FFCEE7E7FFFFFFFFFF393939FF00000000000000005A5A
+          5AFFFFFFFFFFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EF
+          E7FFD6EFE7FFD6EFE7FFD6EFE7FFFFFFFFFF424242FF00000000000000005A5A
+          5AFFFFFFFFFFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EF
+          E7FFD6EFE7FFD6EFE7FFD6EFE7FFFFFFFFFF424242FF00000000000000006363
+          63FFFFFFFFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EF
+          EFFFD6EFEFFFD6EFEFFFD6EFEFFFFFFFFFFF4A4A4AFF00000000000000006B6B
+          6BFFFFFFFFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+          F7FFDEF7F7FFCEEFE7FFC6DEDEFFDEDEDEFF525252FF00000000000000006B6B
+          6BFFFFFFFFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFF7F7
+          F7FFD6D6D6FFC6C6C6FFB5B5B5FF9C9C9CFF525252FF00000000000000006B6B
+          6BFFFFFFFFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFF7F7
+          F7FF949494FF8C8C8CFF737373FF5A5A5AFF5A5A5AFF00000000000000006B6B
+          6BFFFFFFFFFFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7
+          F7FFA5A5A5FFFFFFFFFFFFFFFFFFFFFFFFFF5A5A5AFF00000000000000006B6B
+          6BFFFFFFFFFFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7
+          F7FFB5B5B5FFFFFFFFFFD6F7EFFFB5D6CEFF6B6B6BFF00000000000000006B6B
+          6BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFCECECEFFFFFFFFFFB5D6CEFF737373FF0000000000000000000000007373
+          73FF737373FF737373FF737373FF7B7B7BFF7B7B7BFF7B7B7BFF848484FF8484
+          84FF848484FF848484FF848484FF000000000000000000000000
+        }
         ImageIndex = 0
         ShortCut = 16462
         OnClick = aNewMapExecute
       end
       object miOpenMap: TMenuItem
         Caption = 'Открыть карту'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000004A4A
+          52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A52FF4A4A
+          52FF4A4A52FF4A4A52FF4A4A52FF7B9494FF0000000000000000000000003939
+          39FF7B8C8CFF849C94FF7B9494FF7B9494FF7B9494FF7B9494FF7B9494FF7B94
+          94FF7B9494FF7B9494FF7B9494FF7B9494FF0000000000000000000000003939
+          39FF7B9494FF94ADADFF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94AD
+          A5FF94ADADFF94B5ADFF94B5B5FF7B9494FF0000000000000000000000004242
+          42FF5A6363FF9CB5ADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94AD
+          ADFF94ADADFF9CB5B5FF9CBDB5FFA5BDBDFF7B9494FF00000000000000004A4A
+          4AFF5A5A5AFF94B5ADFFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BD
+          B5FFA5BDB5FFA5BDB5FFA5BDBDFFADCEC6FF7B9494FF00000000000000005252
+          52FF5A5A5AFF7B8C8CFFADC6C6FFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BD
+          BDFFA5BDBDFFA5BDBDFFADC6C6FFBDD6CEFF7B9494FF00000000000000005A5A
+          5AFF5A5A5AFF737B7BFFB5CEC6FFADC6BDFFADC6BDFFADC6BDFFADC6C6FFADC6
+          BDFFADC6BDFFB5CEC6FFB5CECEFFBDDED6FF7B9494FF00000000000000006363
+          63FF6B6B6BFF636363FFA5B5B5FFBDD6D6FFBDD6D6FFB5D6CEFFB5D6CEFFB5CE
+          CEFFB5CECEFFB5CECEFFB5D6CEFFBDD6D6FFC6DEDEFF7B9494FF000000006B6B
+          6BFF7B7373FF6B6B6BFF7B8484FFB5CECEFFB5CECEFFBDD6D6FFBDD6D6FFBDD6
+          D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDDED6FFCEE7DEFF7B9494FF000000007373
+          73FF847B7BFF7B7B7BFF6B6B6BFF737373FF737373FF737373FF6B736BFFADC6
+          BDFFCEE7E7FFC6DED6FFC6DED6FFC6DED6FFC6E7DEFF7B9494FF000000007B7B
+          7BFF848484FF848484FF848484FF848484FF848484FF848484FF7B7B7BFF848C
+          84FFD6EFE7FFDEF7F7FFDEF7F7FFDEF7F7FFE7F7F7FF7B9494FF000000008484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8484
+          84FF848484FF848C84FF848C84FF848C84FF848484FF00000000000000008C8C
+          8CFF949494FF8C948CFF8C9494FF949494FF949494FF8C8C8CFF7B7B7BFF7B7B
+          7BFF737373FF737373FF737373FF737373FF0000000000000000000000009494
+          94FF9C9C9CFF9C9C9CFF9C9C9CFF9C9C9CFF9C9C9CFF949494FF000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00008C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF00000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 1
         ShortCut = 16463
         OnClick = aOpenMapExecute
       end
       object miSaveMap: TMenuItem
         Caption = 'Сохранить карту'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000002929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF00000000393939FF7B94
+          94FF7B9494FF636363FFE7E7E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7
+          E7FFD6D6D6FFE7E7E7FF5A5A5AFF7B9494FF7B9494FF292929FF424242FF7B94
+          94FF7B9494FF6B6B6BFFFFFFFFFFE7E7E7FFA5BDB5FFFFFFFFFFFFFFFFFFEFEF
+          EFFFE7E7E7FFE7E7E7FF6B6B6BFF7B9494FF7B9494FF292929FF4A4A4AFF94AD
+          A5FF8CA5A5FF7B7B7BFFFFFFFFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF6B6B6BFF849C9CFF849C9CFF393939FF4A4A4AFF94AD
+          A5FF8CA5A5FF7B7B7BFFFFFFFFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF6B6B6BFF849C9CFF849C9CFF393939FF525252FF9CB5
+          B5FF9CB5ADFF9C9C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF7B7B7BFF849C9CFF849C9CFF393939FF525252FFA5BD
+          B5FFA5BDB5FFA5BDB5FF94B5ADFF8CADA5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+          A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF424242FF5A5A5AFFA5C6
+          BDFF8CA59CFF8CA5A5FF849C9CFF7B948CFF738C84FF738C84FF738C84FF738C
+          8CFF738C8CFF738C8CFF738C8CFF6B8484FF8CADA5FF424242FF5A5A5AFFADC6
+          BDFF94ADA5FFE7E7E7FFF7F7F7FFF7F7F7FFEFEFEFFFEFEFEFFFEFEFEFFFEFEF
+          EFFFF7F7F7FFEFEFEFFFDEDEDEFF73948CFF94ADADFF4A4A4AFF636363FFADC6
+          C6FF94ADADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFF7F7F7FF7B9494FF94ADADFF4A4A4AFF6B6B6BFFADCE
+          C6FF9CB5ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFF7F7F7FF7B9C94FF9CB5B5FF525252FF7B7B7BFFCEE7
+          DEFFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFF8CA5A5FFADC6C6FF5A5A5AFF7B7B7BFFD6EF
+          E7FFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFF94ADADFFADC6C6FF636363FF7B7B7BFFD6F7
+          EFFFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFF94ADA5FFADCEC6FF6B6B6BFF848484FFDEF7
+          F7FFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFF7F7F7FF9CB5ADFFB5CECEFF737373FF000000008484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF00000000
+        }
         ImageIndex = 2
         ShortCut = 16467
         OnClick = aSaveMapExecute
       end
       object miSaveMapAs: TMenuItem
         Caption = 'Сохранить карту как...'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000002929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF00000000393939FF7B94
+          94FF7B9494FF636363FFE7E7E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7
+          E7FFD6D6D6FFE7E7E7FF5A5A5AFF7B9494FF7B9494FF292929FF424242FF7B94
+          94FF7B9494FF6B6B6BFFFFFFFFFFE7E7E7FFA5BDB5FFFFFFFFFFFFFFFFFFEFEF
+          EFFFE7E7E7FFE7E7E7FF6B6B6BFF7B9494FF7B9494FF292929FF4A4A4AFF94AD
+          A5FF8CA5A5FF7B7B7BFFFFFFFFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF6B6B6BFF849C9CFF849C9CFF393939FF4A4A4AFF94AD
+          A5FF8CA5A5FF7B7B7BFFFFFFFFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF6B6B6BFF849C9CFF849C9CFF393939FF525252FF9CB5
+          B5FF9CB5ADFF9C9C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF7B7B7BFF849C9CFF849C9CFF393939FF525252FFA5BD
+          B5FFA5BDB5FFA5BDB5FF94B5ADFF8CADA5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+          A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF424242FF5A5A5AFFA5C6
+          BDFF8CA59CFF8CA5A5FF849C9CFF7B948CFF738C84FF738C84FF738C84FF738C
+          8CFF738C8CFF738C8CFF738C8CFF6B8484FF8CADA5FF424242FF5A5A5AFFADC6
+          BDFF94ADA5FFE7E7E7FFF7F7F7FFF7F7F7FFEFEFEFFFEFEFEFFFEFEFEFFFEFEF
+          EFFFF7F7F7FFEFEFEFFFDEDEDEFF73948CFF94ADADFF4A4A4AFF636363FFADC6
+          C6FF94ADADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B6B6BFF6B6B6BFFFFFF
+          FFFFFFFFFFFFFFFFFFFFF7F7F7FF7B9494FF94ADADFF4A4A4AFF6B6B6BFFADCE
+          C6FF9CB5ADFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDEDEDEFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFF7F7F7FF7B9C94FF9CB5B5FF525252FF7B7B7BFFCEE7
+          DEFFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B6B6BFF6B6B6BFFDEDE
+          DEFFFFFFFFFFFFFFFFFFFFFFFFFF8CA5A5FFADC6C6FF5A5A5AFF7B7B7BFFD6EF
+          E7FFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDEDEDEFF6B6B
+          6BFFFFFFFFFFFFFFFFFFFFFFFFFF94ADADFFADC6C6FF636363FF7B7B7BFFD6F7
+          EFFFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFF8C8C8CFF6B6B6BFF6B6B6BFFDEDE
+          DEFFFFFFFFFFFFFFFFFFFFFFFFFF94ADA5FFADCEC6FF6B6B6BFF848484FFDEF7
+          F7FFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFF7F7F7FF9CB5ADFFB5CECEFF737373FF000000008484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF00000000
+        }
         ImageIndex = 21
         OnClick = aSaveMapAsExecute
       end
       object miOpenWadMap: TMenuItem
         Caption = 'Выбрать карту'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF292929FF292929FF292929FF292929FF292929FF292929FF292929FF2929
+          29FF292929FF292929FF292929FF292929FF292929FF292929FF292929FFFFFF
+          FFFFDEDEDEFFC7C7C7FFFFFFFFFFFFFFFFFFA2A2A2FFFFFFFFFFDEDEDEFFDEDE
+          DEFFFFFFFFFFA2A2A2FFA2A2A2FFBBBBBBFFFFFFFFFF292929FF292929FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF292929FF393939FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF393939FF393939FFC297
+          5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC297
+          5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFF393939FF393939FFC297
+          5CFFCAA676FFCAA676FFC2975CFFC2975CFFD2B48EFFD2B48EFFC2975CFFC297
+          5CFFD2B48EFFD2B48EFFC2975CFFC2975CFFC2975CFF393939FF424242FFC297
+          5CFFD2B48EFFD2B48EFFD2B48EFFC2975CFFE1CEB7FFDAC2A3FFE5D5C1FFE5D5
+          C1FFDAC2A3FFE1CEB7FFC2975CFFC2975CFFC2975CFF424242FF424242FFC297
+          5CFFD2B48EFFD6BB99FFE9DBCAFFDEC8AEFFE1CEB7FFC2975CFFE1CEB7FFE1CE
+          B7FFC2975CFFE9DBCAFFE1CEB7FFE1CEB7FFC2975CFF424242FF4A4A4AFFC297
+          5CFFD2B48EFFF4EDE5FFC69E6AFFDAC2A3FFE5D5C1FFC2975CFFDEC8AEFFE1CE
+          B7FFC2975CFFE1CEB7FFC2975CFFE5D5C1FFC2975CFF4A4A4AFF4A4A4AFFC297
+          5CFFCEAD82FFD6BB99FFC2975CFFC2975CFFE1CEB7FFC2975CFFCEAD82FFCEAD
+          82FFC2975CFFE1CEB7FFE1CEB7FFDAC2A3FFC2975CFF4A4A4AFF525252FFC297
+          5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC297
+          5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFF525252FF5A5A5AFFC297
+          5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFFC297
+          5CFFC2975CFFC2975CFFC2975CFFC2975CFFC2975CFF5A5A5AFF636363FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF636363FF6B6B6BFFFFFF
+          FFFFE9E9E9FFE9E9E9FFFFFFFFFFFFFFFFFFD3D3D3FFD3D3D3FFFFFFFFFFFFFF
+          FFFFD3D3D3FFD3D3D3FFFFFFFFFFFFFFFFFFFFFFFFFF6B6B6BFF737373FFFFFF
+          FFFFD3D3D3FFD3D3D3FFD3D3D3FFFFFFFFFFA2A2A2FFBBBBBBFF949494FF9494
+          94FFBBBBBBFFA2A2A2FFFFFFFFFFFFFFFFFFFFFFFFFF737373FF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF
+        }
         ImageIndex = 28
         OnClick = miOpenWadMapClick
       end
@@ -1939,16 +1938,124 @@ object MainForm: TMainForm
       end
       object miSaveMiniMap: TMenuItem
         Caption = 'Сохранить мини-карту'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000002929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF00000000393939FF7B94
+          94FF7B9494FF636363FFE7E7E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7E7
+          E7FFD6D6D6FFE7E7E7FF5A5A5AFF7B9494FF7B9494FF292929FF424242FF7B94
+          94FF7B9494FF6B6B6BFFFFFFFFFFE7E7E7FFA5BDB5FFFFFFFFFFFFFFFFFFEFEF
+          EFFFE7E7E7FFE7E7E7FF6B6B6BFF7B9494FF7B9494FF292929FF4A4A4AFF94AD
+          A5FF8CA5A5FF7B7B7BFFFFFFFFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF6B6B6BFF849C9CFF849C9CFF393939FF4A4A4AFF94AD
+          A5FF8CA5A5FF7B7B7BFFFFFFFFFF5A736BFF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF6B6B6BFF849C9CFF849C9CFF393939FF525252FF9CB5
+          B5FF9CB5ADFF9C9C9CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFE7E7E7FF7B7B7BFF849C9CFF849C9CFF393939FF525252FFA5BD
+          B5FFA5BDB5FFA5BDB5FF94B5ADFF8CADA5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+          A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF424242FF5A5A5AFFA5C6
+          BDFF8CA59CFF8CA5A5FF849C9CFF7B948CFF738C84FF738C84FF738C84FF738C
+          8CFF738C8CFF738C8CFF738C8CFF6B8484FF8CADA5FF424242FF5A5A5AFFADC6
+          BDFF94ADA5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFF000000FF000000FF000000FF73948CFF94ADADFF4A4A4AFF636363FFADC6
+          C6FF94ADADFFFFFFFFFF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FFFFFF
+          FFFF000000FF000000FFC6C6C6FF7B9494FF94ADADFF4A4A4AFF6B6B6BFFADCE
+          C6FF9CB5ADFFFFFFFFFFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFFFFF
+          FFFF000000FF000000FF000000FF7B9C94FF9CB5B5FF525252FF7B7B7BFFCEE7
+          DEFFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFFFF
+          FFFF080808FF080808FFC6C6C6FF8CA5A5FFADC6C6FF5A5A5AFF7B7B7BFFD6EF
+          E7FFA5BDB5FF081810FF081810FF081810FF081810FF081810FF081810FF0818
+          10FF081810FF081810FF081810FF94ADADFFADC6C6FF636363FF7B7B7BFFD6F7
+          EFFFA5BDB5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1821
+          18FF182118FF182118FFC6C6C6FF94ADA5FFADCEC6FF6B6B6BFF848484FFDEF7
+          F7FFA5BDB5FF212929FF212929FF212929FF212929FF212929FFFFFFFFFF2129
+          29FF212929FF212929FF212929FF9CB5ADFFB5CECEFF737373FF000000008484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF00000000
+        }
         ImageIndex = 22
         OnClick = miSaveMiniMapClick
       end
       object miDeleteMap: TMenuItem
         Caption = 'Удалить карту из WAD...'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000006B6B
+          6BFF292929FF212121FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF181818FF181818FF4A4AFFFF4A4AFFFF00000000000000004242
+          42FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFB5B5B5FF4A4AFFFF4A4AFFFF292929FF00000000000000004242
+          42FFFFFFFFFFC6DEDEFFC6DEDEFFB5B5B5FFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+          DEFFB5B5B5FF4A4AFFFF4A4AFFFFFFFFFFFF313131FF00000000000000004A4A
+          4AFFFFFFFFFFBDDED6FFBDDED6FF4A4AFFFFB5B5B5FFB5B5B5FFBDDED6FFB5B5
+          B5FF4A4AFFFF4A4AFFFFBDDED6FFFFFFFFFF313131FF00000000000000004A4A
+          4AFFFFFFFFFFCEE7E7FFCEE7E7FFCEE7E7FF4A4AFFFF4A4AFFFFB5B5B5FF4A4A
+          FFFF4A4AFFFFCEE7E7FFCEE7E7FFFFFFFFFF313131FF00000000000000004A4A
+          4AFFFFFFFFFFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FF4A4AFFFF4A4AFFFF4A4A
+          FFFFB5B5B5FFCEE7E7FFCEE7E7FFFFFFFFFF393939FF00000000000000005A5A
+          5AFFFFFFFFFFD6EFE7FFD6EFE7FFD6EFE7FFB5B5B5FF4A4AFFFF4A4AFFFF4A4A
+          FFFF4A4AFFFFB5B5B5FFB5B5B5FFFFFFFFFF424242FF00000000000000005A5A
+          5AFFFFFFFFFFD6EFE7FFD6EFE7FFD6EFE7FF4A4AFFFF4A4AFFFF4A4AFFFFD6EF
+          E7FF4A4AFFFF4A4AFFFF4A4AFFFFB5B5B5FF424242FF00000000000000006363
+          63FFFFFFFFFFD6EFEFFFD6EFEFFFB5B5B5FF4A4AFFFF4A4AFFFFD6EFEFFFD6EF
+          EFFFD6EFEFFF4A4AFFFF4A4AFFFF4A4AFFFF4A4A4AFF00000000000000006B6B
+          6BFFFFFFFFFFDEF7F7FFB5B5B5FF4A4AFFFF4A4AFFFFDEF7F7FFDEF7F7FFDEF7
+          F7FFDEF7F7FFCEEFE7FF4A4AFFFF4A4AFFFF4A4AFFFF00000000000000006B6B
+          6BFFFFFFFFFFB5B5B5FF4A4AFFFF4A4AFFFF4A4AFFFFDEF7F7FFDEF7F7FFF7F7
+          F7FFD6D6D6FFC6C6C6FFB5B5B5FF4A4AFFFF4A4AFFFF4A4AFFFF000000006B6B
+          6BFFFFFFFFFF4A4AFFFF4A4AFFFF4A4AFFFFDEF7F7FFDEF7F7FFDEF7F7FFF7F7
+          F7FF949494FF8C8C8CFF737373FF5A5A5AFF4A4AFFFF4A4AFFFF000000006B6B
+          6BFFFFFFFFFFE7FFF7FF4A4AFFFF4A4AFFFFE7FFF7FFE7FFF7FFE7FFF7FFF7F7
+          F7FFA5A5A5FFFFFFFFFFFFFFFFFFFFFFFFFF5A5A5AFF4A4AFFFF000000006B6B
+          6BFFFFFFFFFFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7
+          F7FFB5B5B5FFFFFFFFFFD6F7EFFFB5D6CEFF6B6B6BFF00000000000000006B6B
+          6BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFCECECEFFFFFFFFFFB5D6CEFF737373FF0000000000000000000000007373
+          73FF737373FF737373FF737373FF7B7B7BFF7B7B7BFF7B7B7BFF848484FF8484
+          84FF848484FF848484FF848484FF000000000000000000000000
+        }
         ImageIndex = 11
         OnClick = aDeleteMap
       end
       object miPackMap: TMenuItem
         Caption = 'Упаковать карту'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000006B6B
+          6BFF292929FF212121FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF181818FF181818FF181818FF4A4A4AFF00000000000000004242
+          42FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF292929FF00000000000000004242
+          42FFFFFFFFFFC8E0E0FFC8E0DFFFC8E0E0FFC8E0E0FFC8E0DFFFB5B5B5FFC8DF
+          DFFFC7DFDFFFC8DFE0FFC8E0DFFFFFFFFFFF313131FF00000000000000004A4A
+          4AFFFFFFFFFFCAE2E1FFCAE2E1FFCAE2E1FFCAE2E1FFB5B5B5FF722828FFB5B5
+          B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FF181818FFB5B5B5FF000000004A4A
+          4AFFFFFFFFFFCDE5E3FFCCE5E3FFCDE5E3FFB5B5B5FF812D2DFF812D2DFF812D
+          2DFF812D2DFF812D2DFF812D2DFF812D2DFF812D2DFF812D2DFF000000004A4A
+          4AFFFFFFFFFFD0E8E5FFD0E8E6FFCFE8E5FF923333FF923333FF923333FF9233
+          33FF923333FF923333FF923333FF923333FF923333FF923333FF000000005A5A
+          5AFFFFFFFFFFD3EBE8FFD3EBE8FFA33939FFA33939FFA33939FFA33939FFA339
+          39FFA33939FFA33939FFA33939FFA33939FFA33939FFA33939FF000000005A5A
+          5AFFFFFFFFFFD7EEEAFFD7EEEBFFD6EEEBFFB23E3EFFB23E3EFFB23E3EFFB23E
+          3EFFB33F3FFFB23E3EFFB23E3EFFB23E3EFFB23E3EFFB23E3EFF000000006363
+          63FFFFFFFFFFDAF2EDFFDAF2EDFFDAF2EDFFDAF2EDFFBD4242FFBD4242FFBD42
+          42FFBD4242FFBD4242FFBD4242FFBD4242FFBD4242FFBD4242FF000000006B6B
+          6BFFFFFFFFFFDEF6F0FFDEF6F0FFDDF5F0FFDDF5EFFFDDF5F0FFBD4242FFDDF5
+          EFFFDDF5F0FFDEF5F0FFC6DEDEFFDEDEDEFF525252FF00000000000000006B6B
+          6BFFFFFFFFFFE0F9F2FFE1F9F2FFE0F8F2FFE0F8F2FFE0F8F2FFE1F9F2FFF7F7
+          F7FFD6D6D6FFC6C6C6FFB5B5B5FF9C9C9CFF525252FF00000000000000006B6B
+          6BFFFFFFFFFFE3FBF4FFE3FBF4FFE3FBF3FFE3FBF4FFE3FCF4FFE3FBF4FFF7F7
+          F7FF949494FF8C8C8CFF737373FF5A5A5AFF5A5A5AFF00000000000000006B6B
+          6BFFFFFFFFFFE5FEF6FFE5FDF6FFE5FDF6FFE5FEF6FFE6FEF6FFE5FDF6FFF7F7
+          F7FFA5A5A5FFFFFFFFFFFFFFFFFFFFFFFFFF5A5A5AFF00000000000000006B6B
+          6BFFFFFFFFFFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7F7
+          F7FFB5B5B5FFFFFFFFFFD6F7EFFFB5D6CEFF6B6B6BFF00000000000000006B6B
+          6BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFCECECEFFFFFFFFFFB5D6CEFF737373FF0000000000000000000000007373
+          73FF737373FF737373FF737373FF7B7B7BFF7B7B7BFF7B7B7BFF848484FF8484
+          84FF848484FF848484FF848484FF000000000000000000000000
+        }
         ImageIndex = 26
         OnClick = miPackMapClick
       end
@@ -1957,6 +2064,42 @@ object MainForm: TMainForm
       end
       object miExit: TMenuItem
         Caption = 'Выход'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000292929FF292929FF292929FF292929FF292929FF292929FF292929FF2929
+          29FF292929FF292929FF212121FF292929FF0000000000000000000000000000
+          0000393939FF7B9C9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C9CFF7B9C
+          9CFF7B9C9CFF7B9C9CFF7B9C9CFF292929FF0000000000000000000000000000
+          0000424242FF849C9CFF849C9CFF849C9CFF849C9CFF849C9CFF849C9CFF849C
+          9CFF849C9CFF849C9CFF849C9CFF292929FF0000000000000000000000000000
+          00004A4A4AFF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+          A5FF8CA5A5FF8CA5A5FF8CA5A5FF393939FF0000000000000000000000000000
+          00004A4A4AFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94AD
+          ADFF94ADADFF94ADADFF94ADADFF393939FF0000000000000000000000000000
+          0000525252FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5B5FF9CB5
+          B5FF9CB5B5FF9CB5B5FF9CB5B5FF393939FF0000000000000000000000000000
+          0000525252FFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BD
+          BDFF7B9C9CFF6B8484FFA5BDBDFF424242FF0000000000000000000000000000
+          00005A5A5AFFADC6C6FFADC6C6FFADC6C6FFADC6C6FFADC6C6FFADC6C6FFADC6
+          C6FFDEF7F7FF7B9C9CFFADC6C6FF424242FF0000000000000000000000000000
+          00005A5A5AFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CE
+          CEFFB5CECEFFB5CECEFFB5CECEFF4A4A4AFF0000000000000000000000000000
+          0000636363FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6
+          D6FFBDD6D6FFBDD6D6FFBDD6D6FF4A4A4AFF0000000000000000000000000000
+          00006B6B6BFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+          DEFFC6DEDEFFC6DEDEFFC6DEDEFF525252FF0000000000000000000000000000
+          00007B7B7BFFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7
+          E7FFCEE7E7FFCEE7E7FFCEE7E7FF5A5A5AFF0000000000000000000000000000
+          00007B7B7BFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EF
+          EFFFD6EFEFFFD6EFEFFFD6EFEFFF636363FF0000000000000000000000000000
+          00007B7B7BFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+          F7FFDEF7F7FFDEF7F7FFDEF7F7FF6B6B6BFF0000000000000000000000000000
+          0000848484FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+          F7FFDEF7F7FFDEF7F7FFDEF7F7FF737373FF0000000000000000000000000000
+          00007B7B7BFF848484FF848484FF848484FF848484FF848484FF848484FF8484
+          84FF848484FF848484FF848484FF737373FF0000000000000000
+        }
         ImageIndex = 10
         ShortCut = 121
         OnClick = aExitExecute
@@ -1967,6 +2110,42 @@ object MainForm: TMainForm
       object miUndo: TMenuItem
         Caption = 'Отменить'
         Enabled = False
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000294A4AFF294A4AFF294A4AFF294A4AFF294A4AFF00000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00006B8484FF42635AFF294A4AFF294A4AFF0000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00006B8484FF42635AFF42635AFF294A4AFF0000000000000000000000000000
+          0000000000000000000000000000294A4AFF0000000000000000000000000000
+          00006B8484FF6B8484FF42635AFF294A4AFF294A4AFF00000000000000000000
+          000000000000000000000000000042635AFF294A4AFF00000000000000000000
+          00006B8484FF000000006B8484FF42635AFF294A4AFF294A4AFF000000000000
+          00000000000000000000294A4AFF42635AFF6B8484FF00000000000000000000
+          000000000000000000000000000042635AFF42635AFF294A4AFF294A4AFF294A
+          4AFF294A4AFF294A4AFF42635AFF42635AFF0000000000000000000000000000
+          00000000000000000000000000006B8484FF42635AFF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF42635AFF6B8484FF0000000000000000000000000000
+          0000000000000000000000000000000000006B8484FF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF6B8484FF000000000000000000000000000000000000
+          000000000000000000000000000000000000000000006B8484FF6B8484FF6B84
+          84FF6B8484FF6B8484FF00000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 5
         ShortCut = 16474
         OnClick = aUndoExecute
@@ -1977,6 +2156,42 @@ object MainForm: TMainForm
       object miCopy: TMenuItem
         Caption = 'Копировать объект'
         Enabled = False
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000006B6B6BFF292929FF212121FF1818
+          18FF181818FF181818FF181818FF181818FF181818FF4A4A4AFF000000000000
+          000000000000000000000000000000000000424242FFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF292929FF6B6B6BFF2929
+          29FF212121FF181818FF181818FF181818FF424242FFFFFFFFFFE7C6C6FFE7C6
+          C6FFE7C6C6FFE7C6C6FFE7C6C6FFE7C6C6FFFFFFFFFF313131FF424242FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A4A4AFFFFFFFFFFEFCECEFFEFCE
+          CEFFEFCECEFFEFCECEFFEFCECEFFEFCECEFFFFFFFFFF313131FF424242FFFFFF
+          FFFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFF5A5A5AFFFFFFFFFFF7D6DEFFF7D6
+          DEFFF7D6DEFFF7D6DEFFF7D6DEFFF7D6DEFFFFFFFFFF424242FF4A4A4AFFFFFF
+          FFFFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FF5A5A5AFFFFFFFFFFF7D6DEFFF7D6
+          DEFFF7D6DEFFF7D6DEFFF7D6DEFFF7D6DEFFFFFFFFFF424242FF5A5A5AFFFFFF
+          FFFFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FF6B6B6BFFFFFFFFFFFFDEDEFFFFDE
+          DEFFFFDEDEFFFFDEDEFFFFDEDEFFE7C6C6FFDEDEDEFF525252FF5A5A5AFFFFFF
+          FFFFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FF6B6B6BFFFFFFFFFFFFDEDEFFFFDE
+          DEFFFFDEDEFFF7F7F7FFD6D6D6FFB5B5B5FF9C9C9CFF525252FF6B6B6BFFFFFF
+          FFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FF6B6B6BFFFFFFFFFFFFDEDEFFFFDE
+          DEFFFFDEDEFFF7F7F7FF949494FF737373FF5A5A5AFF5A5A5AFF6B6B6BFFFFFF
+          FFFFDEF7F7FFDEF7F7FFDEF7F7FFF7F7F7FF6B6B6BFFFFFFFFFFFFE7EFFFFFE7
+          EFFFFFE7EFFFF7F7F7FFA5A5A5FFFFFFFFFFFFFFFFFF5A5A5AFF6B6B6BFFFFFF
+          FFFFDEF7F7FFDEF7F7FFDEF7F7FFF7F7F7FF6B6B6BFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFFFFFFFFFFCECECEFFDEB5BDFF737373FF000000006B6B6BFFFFFF
+          FFFFE7FFF7FFE7FFF7FFE7FFF7FFF7F7F7FF737373FF737373FF737373FF7373
+          73FF7B7B7BFF848484FF848484FF848484FF00000000000000006B6B6BFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCECECEFFB5D6CEFF737373FF0000
+          0000000000000000000000000000000000000000000000000000737373FF7373
+          73FF737373FF737373FF7B7B7BFF848484FF848484FF848484FF000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 8
         ShortCut = 16451
         OnClick = aCopyObjectExecute
@@ -1984,12 +2199,84 @@ object MainForm: TMainForm
       object miCut: TMenuItem
         Caption = 'Вырезать объект'
         Enabled = False
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          000000000000295239FF315A4AFF295239FF0000000000000000000000002952
+          39FF31634AFF214A31FF00000000000000000000000000000000000000000000
+          0000315242FF52846BFF528C6BFF5A8C73FF4A6B5AFF00000000426B5AFF5A84
+          73FF5A9473FF639473FF214A31FF000000000000000000000000000000000000
+          0000294231FF4A7B63FF0000000000000000637B73FF396352FF5A7B6BFF0000
+          000000000000527B63FF395A42FF000000000000000000000000000000000000
+          0000000000004A6B5AFF000000000000000000000000426B5AFF000000000000
+          000000000000527B63FF00000000000000000000000000000000000000000000
+          0000000000004A6B5AFF527363FF00000000315A4AFF4A7B6BFF295A4AFF0000
+          00004A7363FF4A6B5AFF00000000000000000000000000000000000000000000
+          000000000000000000004A6B5AFF6B8C7BFF52846BFF6B9C8CFF6B9C8CFF5273
+          63FF526B63FF0000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000004A4A4AFF4A4A4AFF4A4A4AFF0000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000004A4A4AFF6B6B6BFF4A4A4AFF6B6B6BFF4A4A
+          4AFF000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000006B6B6BFF848484FF4A4A4AFF848484FF6B6B
+          6BFF000000000000000000000000000000000000000000000000000000000000
+          000000000000000000004A4A4AFF6B6B6BFFA5A5A5FF00000000A5A5A5FF6B6B
+          6BFF4A4A4AFF0000000000000000000000000000000000000000000000000000
+          000000000000000000006B6B6BFF848484FFA5A5A5FF00000000A5A5A5FF8484
+          84FF6B6B6BFF0000000000000000000000000000000000000000000000000000
+          00000000000000000000848484FFA5A5A5FF000000000000000000000000A5A5
+          A5FF848484FF0000000000000000000000000000000000000000000000000000
+          00000000000000000000848484FFA5A5A5FF000000000000000000000000A5A5
+          A5FF848484FF0000000000000000000000000000000000000000000000000000
+          00000000000000000000A5A5A5FFA5A5A5FF000000000000000000000000A5A5
+          A5FFA5A5A5FF0000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 7
         ShortCut = 16472
         OnClick = aCutObjectExecute
       end
       object miPaste: TMenuItem
         Caption = 'Вставить объект'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF292929FF292929FF212121FF000000000000000000000000393939FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFF000000FF000000FF292929FF000000000000000000000000424242FFFFFF
+          FFFF8C0000FFFFDEDEFFFFDEDEFFFFDEDEFFFFDEDEFFFFDEDEFFFFDEDEFFFFFF
+          FFFFDEDEDEFF000000FF292929FF0000000000000000000000004A4A4AFFFFFF
+          FFFFBD0000FFFFDEDEFF4A6352FF42635AFF42635AFF42635AFF42635AFF4263
+          5AFFDEDEDEFF000000FF393939FF0000000000000000000000004A4A4AFFFFFF
+          FFFFD60000FFFFDEDEFF6B8484FF5A7373FF5A7373FF5A7373FF42635AFFFFFF
+          FFFF000000FF000000FF393939FF000000000000000000000000525252FFFFFF
+          FFFFEF0000FFFFDEDEFF6B8484FF5A7373FF5A7373FF42635AFF42635AFFFFFF
+          FFFF000000FF000000FF393939FF000000000000000000000000525252FFFFFF
+          FFFFFFFFFFFFFFFFFFFF6B8484FF5A7373FF6B8484FF5A7373FF42635AFF4263
+          5AFFDEDEDEFF080808FF424242FF0000000000000000000000005A5A5AFF0808
+          08FF080808FFDEDEDEFF6B8484FF6B8484FF6B8484FF6B8484FF5A7373FF4263
+          5AFF42635AFFEFEFEFFF181818FF181818FF181818FF4A4A4AFF5A5A5AFF0808
+          08FF212929FFDEE7E7FF6B8484FFDEE7E7FFF7F7F7FF6B8484FF6B8484FF5A73
+          73FF42635AFF42635AFFFFFFFFFFFFFFFFFFFFFFFFFF292929FF7B7B7BFF2129
+          29FF212929FFF7F7F7FFF7F7F7FFF7F7F7FF212929FFF7F7F7FF6B8484FF6B84
+          84FF5A7373FF42635AFF42635AFFFFFFFFFFFFFFFFFF313131FF5A5A5AFF3139
+          39FF313939FF313939FF313939FF313939FF313939FF313939FFFFFFFFFF6B84
+          84FF6B8484FF42635AFFFFFFFFFFFFFFFFFFDEDEDEFF525252FF7B7B7BFF3942
+          42FF394242FF394242FF394242FF394242FF394242FF394242FF6B6B6BFFFFFF
+          FFFF6B8484FFFFFFFFFFFFFFFFFFB5B5B5FF9C9C9CFF525252FF848484FF525A
+          5AFF4A5A52FF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF6B6B6BFFFFFF
+          FFFFFFFFFFFFFFFFFFFF949494FF737373FF5A5A5AFF5A5A5AFF848484FF8484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF6B6B6BFFFFFF
+          FFFFFFE7EFFFF7F7F7FFA5A5A5FFFFFFFFFFFFFFFFFF5A5A5AFF000000000000
+          00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+          FFFFFFFFFFFFFFFFFFFFCECECEFFDEB5BDFF737373FF00000000000000000000
+          0000000000000000000000000000000000000000000000000000737373FF7373
+          73FF737373FF848484FF848484FF848484FF0000000000000000
+        }
         ImageIndex = 9
         ShortCut = 16470
         OnClick = aPasteObjectExecute
@@ -1999,6 +2286,42 @@ object MainForm: TMainForm
       end
       object miSelectAll: TMenuItem
         Caption = 'Выделить все объекты'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF212121FF393939FF0000
+          63FF000063FF000063FF000063FF00006BFF000063FF000063FF000063FF0000
+          6BFF000063FF000000FF000000FF000000FF000000FF292929FF424242FF0000
+          73FF000073FF000073FF000073FF000073FF000073FF000073FF000073FF0000
+          73FF000073FF000000FF000000FF000000FF000000FF292929FF4A4A4AFF0000
+          84FF000084FF000084FF000084FF000084FF000084FF000084FF000084FF0000
+          84FF000084FF000000FF000000FF000084FF000084FF393939FF4A4A4AFF0000
+          94FF000094FF000094FF000094FF000094FF000094FF000094FF000094FF0000
+          94FF000094FF000000FF000000FF000000FF000000FF393939FF525252FF0000
+          A5FF0000A5FF0000A5FF00009CFF00009CFF00009CFF0000A5FF0000A5FF0000
+          A5FF0000A5FF000000FF000000FF000000FF000000FF393939FF525252FF0000
+          ADFF0000ADFF0000ADFF0000ADFF0000ADFF0000ADFF0000ADFF0000ADFF0000
+          ADFF0000ADFF080808FF000000FF0000ADFF0000ADFF424242FF5A5A5AFF0808
+          08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+          08FF080808FF080808FF000000FF000000FF000000FF424242FF5A5A5AFF0008
+          08FF000808FF000808FF000808FF000808FF000808FF000808FF000808FF0008
+          08FF000808FF000808FF000808FF000808FF000808FF4A4A4AFF636363FF0810
+          08FF081008FF081008FF081008FF081008FF081008FF081008FF081008FF0810
+          08FF081008FF081008FF081008FF2929ADFF2929ADFF4A4A4AFF6B6B6BFF3939
+          ADFF3939ADFF3939ADFF3939ADFF3939ADFF3939ADFF3939ADFF3939ADFF1018
+          10FF101810FF101810FF101810FF101810FF101810FF525252FF7B7B7BFF1821
+          21FF182121FF182121FF182121FF182121FF182121FF182121FF4A4AADFF1821
+          21FF182121FF182121FF182121FF182121FF182121FF5A5A5AFF7B7B7BFF2129
+          29FF212929FF212929FF212929FF212929FF212929FF212929FF212929FF2129
+          29FF212929FF212929FF212929FF5252ADFF5252ADFF636363FF7B7B7BFF2929
+          31FF292931FF292931FF292931FF292931FF292931FF292931FF292931FF2929
+          31FF292931FF292931FF292931FF292931FF292931FF6B6B6BFF848484FF525A
+          5AFF4A5A52FF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A
+          5AFF525A5AFF525A5AFF525A5AFF4A5A52FF4A5A52FF737373FF848484FF8484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF848484FF
+        }
         ImageIndex = 24
         ShortCut = 16449
         OnClick = aSelectAllExecute
@@ -2009,6 +2332,42 @@ object MainForm: TMainForm
       object miToFore: TMenuItem
         Caption = 'Передвинуть вперед'
         Enabled = False
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000003139ADFF10219CFF10219CFF1021
+          9CFF10219CFF10219CFF10219CFF10219CFF10219CFF10219CFF000000000000
+          0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          00000000000042635AFF294A4AFF294A4AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          0000000000005A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          0000000000005A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF39524AFF2942
+          39FF294239FF5A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF4A5AB5FF4A5AB5FF4A5AB5FF4A5A
+          B5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF3139ADFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF294A4AFF000000000000000000000000425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF294A4AFF000000000000000000000000425A52FF3952
+          4AFF39524AFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A73
+          6BFF5A736BFF5A736BFF42635AFF000000000000000000000000425A52FF3952
+          4AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF2942
+          39FF000000000000000000000000000000000000000000000000425A52FF3952
+          4AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF2942
+          39FF000000000000000000000000000000000000000000000000425A52FF425A
+          52FF425A52FF425A52FF425A52FF425A52FF425A52FF425A52FF425A52FF3952
+          4AFF000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 25
         ShortCut = 16605
         OnClick = aMoveToFore
@@ -2016,6 +2375,42 @@ object MainForm: TMainForm
       object miToBack: TMenuItem
         Caption = 'Передвинуть назад'
         Enabled = False
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000005A7373FF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF000000000000
+          0000000000000000000000000000000000006B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF000000000000
+          0000000000000000000000000000000000006B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF000000000000
+          00000000000042635AFF294A4AFF294A4AFF6B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF000000000000
+          0000000000005A736BFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF000000000000
+          0000000000005A736BFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF3139ADFF1021
+          9CFF10219CFF5A736BFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF4A5AB5FF3139
+          ADFF3139ADFF5A736BFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF4A5AB5FF3139
+          ADFF3139ADFF5A736BFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+          73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF42635AFF4A5AB5FF3139
+          ADFF3139ADFF5A736BFF42635AFF42635AFF6B8484FF6B8484FF6B8484FF6B84
+          84FF6B8484FF6B8484FF6B8484FF6B8484FF6B8484FF5A7373FF4A5AB5FF3139
+          ADFF3139ADFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF294A4AFF0000000000000000000000004A5AB5FF3139
+          ADFF3139ADFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF294A4AFF0000000000000000000000004A5AB5FF3139
+          ADFF3139ADFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A73
+          6BFF5A736BFF5A736BFF42635AFF0000000000000000000000004A5AB5FF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF1021
+          9CFF0000000000000000000000000000000000000000000000004A5AB5FF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF1021
+          9CFF0000000000000000000000000000000000000000000000004A5AB5FF4A5A
+          B5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF3139
+          ADFF000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 13
         ShortCut = 16603
         OnClick = aMoveToBack
@@ -2025,29 +2420,209 @@ object MainForm: TMainForm
       Caption = 'Инструменты'
       object miSnapToGrid: TMenuItem
         Caption = 'Привязка к сетке'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF212121FF393939FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF292929FF424242FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF292929FF4A4A4AFF6F54
+          38FF6F5438FF6F5438FF393939FF6F5438FF6F5438FF6F5438FF393939FF6F54
+          38FF6F5438FF6F5438FF393939FF6F5438FF6F5438FF393939FF4A4A4AFF6F54
+          38FF6F5438FFFFFFFFFF6F5438FF6F5438FF6F5438FFFFFFFFFF6F5438FF6F54
+          38FF6F5438FFFFFFFFFF6F5438FF6F5438FF6F5438FF393939FF525252FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF393939FF525252FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF424242FF5A5A5AFF7157
+          3CFF71573CFF71573CFF393939FF71573CFF71573CFF71573CFF393939FF7157
+          3CFF71573CFF71573CFF393939FF71573CFF71573CFF424242FF5A5A5AFF745B
+          40FF745B40FFFFFFFFFF745B40FF745B40FF745B40FFFFFFFFFF745B40FF745B
+          40FF745B40FFFFFFFFFF745B40FF745B40FF745B40FF4A4A4AFF636363FF775F
+          44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F
+          44FF775F44FF775F44FF775F44FF775F44FF775F44FF4A4A4AFF6B6B6BFF7A64
+          4AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A64
+          4AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF525252FF7B7B7BFF7E69
+          50FF7E6950FF7E6950FF393939FF7E6950FF7E6950FF7E6950FF393939FF7E69
+          50FF7E6950FF7E6950FF393939FF7E6950FF7E6950FF5A5A5AFF7B7B7BFF826F
+          57FF826F57FFFFFFFFFF826F57FF826F57FF826F57FFFFFFFFFF826F57FF826F
+          57FF826F57FFFFFFFFFF826F57FF826F57FF826F57FF636363FF7B7B7BFF8676
+          5EFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF8676
+          5EFF86765EFF86765EFF86765EFF86765EFF86765EFF6B6B6BFF848484FF8B7C
+          65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C
+          65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF737373FF848484FF8484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF848484FF
+        }
         ImageIndex = 20
         ShortCut = 16465
         OnClick = miSnapToGridClick
       end
       object miMiniMap: TMenuItem
         Caption = 'Мини-карта'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF212121FF393939FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFF000000FF000000FF000000FF000000FF292929FF424242FFFFFF
+          FFFF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C00
+          00FFFFFFFFFF000000FF000000FF000000FF000000FF292929FF4A4A4AFFFFFF
+          FFFFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD00
+          00FFFFFFFFFF000000FF000000FFC6C6C6FFC6C6C6FF393939FF4A4A4AFFFFFF
+          FFFFD60000FFD60000FFD60000FFD60000FFD60000FFD60000FFD60000FFD600
+          00FFFFFFFFFF000000FF000000FF000000FF000000FF393939FF525252FFFFFF
+          FFFFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF00
+          00FFFFFFFFFF000000FF000000FF000000FF000000FF393939FF525252FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF00
+          00FFFFFFFFFF080808FF080808FFC6C6C6FFC6C6C6FF424242FF5A5A5AFF0808
+          08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+          08FF080808FF080808FF080808FF080808FF080808FF424242FF5A5A5AFF0808
+          08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+          08FF080808FF080808FF080808FF080808FF080808FF4A4A4AFF636363FF0818
+          10FF081810FF081810FF081810FF081810FF081810FF081810FF081810FF0818
+          10FF081810FF081810FF081810FFC6C6C6FFC6C6C6FF4A4A4AFF6B6B6BFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1821
+          18FF182118FF182118FF182118FF182118FF182118FF525252FF7B7B7BFF2129
+          29FF212929FF212929FF212929FF212929FF212929FF212929FFFFFFFFFF2129
+          29FF212929FF212929FF212929FF212929FF212929FF5A5A5AFF7B7B7BFF3139
+          39FF313939FF313939FF313939FF313939FF313939FF313939FF313939FF3139
+          39FF313939FF313939FF313939FFC6C6C6FFC6C6C6FF636363FF7B7B7BFF3942
+          42FF394242FF394242FF394242FF394242FF394242FF394242FF394242FF3942
+          42FF394242FF394242FF394242FF394242FF394242FF6B6B6BFF848484FF525A
+          5AFF4A5A52FF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A
+          5AFF525A5AFF525A5AFF525A5AFF4A5A52FF4A5A52FF737373FF848484FF8484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF848484FF
+        }
         ImageIndex = 14
         ShortCut = 16471
         OnClick = miMiniMapClick
       end
       object miSwitchGrid: TMenuItem
         Caption = 'Переключить сетку'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF212121FF393939FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF393939FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF393939FF292929FF424242FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FFFFFFFFFF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FFFFFFFFFF6F5438FF292929FF4A4A4AFF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF393939FF4A4A4AFF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF393939FF525252FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF393939FF525252FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF424242FF5A5A5AFF7157
+          3CFF71573CFF71573CFF71573CFF71573CFF71573CFF71573CFF393939FF7157
+          3CFF71573CFF71573CFF71573CFF71573CFF393939FF424242FF5A5A5AFF745B
+          40FF745B40FF745B40FF745B40FF745B40FF745B40FFFFFFFFFF745B40FF745B
+          40FF745B40FF745B40FF745B40FFFFFFFFFF745B40FF4A4A4AFF636363FF775F
+          44FF775F44FF393939FF775F44FF775F44FF393939FF775F44FF775F44FF775F
+          44FF775F44FF775F44FF775F44FF775F44FF775F44FF4A4A4AFF6B6B6BFF7A64
+          4AFFFFFFFFFF7A644AFF7A644AFFFFFFFFFF7A644AFF7A644AFF7A644AFF7A64
+          4AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF525252FF7B7B7BFF7E69
+          50FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E69
+          50FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF5A5A5AFF7B7B7BFF826F
+          57FF826F57FF393939FF826F57FF826F57FF393939FF826F57FF826F57FF826F
+          57FF826F57FF826F57FF826F57FF826F57FF826F57FF636363FF7B7B7BFF8676
+          5EFFFFFFFFFF86765EFF86765EFFFFFFFFFF86765EFF86765EFF86765EFF8676
+          5EFF86765EFF86765EFF86765EFF86765EFF86765EFF6B6B6BFF848484FF8B7C
+          65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C
+          65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF737373FF848484FF8484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF848484FF
+        }
         ImageIndex = 19
         ShortCut = 16453
         OnClick = miSwitchGridClick
       end
       object miShowEdges: TMenuItem
         Caption = 'Границы карты'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF212121FF393939FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF292929FF424242FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF292929FF4A4A4AFF372E
+          24FF372E24FF372E24FF372E24FF372E24FF372E24FF372E24FF372E24FF372E
+          24FF372E24FF372E24FF6F5438FF6F5438FF6F5438FF393939FF4A4A4AFF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF372E24FF6F5438FF6F5438FF6F5438FF393939FF525252FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF372E24FF6F5438FF6F5438FF6F5438FF393939FF525252FF6F54
+          38FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F5438FF6F54
+          38FF6F5438FF372E24FF6F5438FF6F5438FF6F5438FF424242FF5A5A5AFF7157
+          3CFF71573CFF71573CFF71573CFF71573CFF71573CFF71573CFF71573CFF7157
+          3CFF71573CFF382F25FF71573CFF71573CFF71573CFF424242FF5A5A5AFF745B
+          40FF745B40FF745B40FF745B40FF745B40FF745B40FF745B40FF745B40FF745B
+          40FF745B40FF393026FF745B40FF745B40FF745B40FF4A4A4AFF636363FF775F
+          44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F44FF775F
+          44FF775F44FF3A3228FF775F44FF775F44FF775F44FF4A4A4AFF6B6B6BFF7A64
+          4AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A644AFF7A64
+          4AFF7A644AFF3B332AFF7A644AFF7A644AFF7A644AFF525252FF7B7B7BFF7E69
+          50FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E6950FF7E69
+          50FF7E6950FF3D352CFF7E6950FF7E6950FF7E6950FF5A5A5AFF7B7B7BFF826F
+          57FF826F57FF826F57FF826F57FF826F57FF826F57FF826F57FF826F57FF826F
+          57FF826F57FF3E372FFF826F57FF826F57FF826F57FF636363FF7B7B7BFF8676
+          5EFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF86765EFF8676
+          5EFF86765EFF403A31FF86765EFF86765EFF86765EFF6B6B6BFF848484FF8B7C
+          65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C65FF8B7C
+          65FF8B7C65FF413C34FF8B7C65FF8B7C65FF8B7C65FF737373FF848484FF8484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF848484FF
+        }
         ImageIndex = 29
         OnClick = miShowEdgesClick
       end
       object miLayers: TMenuItem
         Caption = 'Слои'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000003139ADFF10219CFF10219CFF1021
+          9CFF10219CFF10219CFF10219CFF10219CFF10219CFF10219CFF000000000000
+          0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          00000000000042635AFF294A4AFF294A4AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          0000000000005A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF000000000000
+          0000000000005A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF39524AFF2942
+          39FF294239FF5A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF4A5AB5FF3139ADFF3139ADFF3139
+          ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF10219CFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF4A5AB5FF4A5AB5FF4A5AB5FF4A5A
+          B5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF3139ADFF425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF294A4AFF000000000000000000000000425A52FF3952
+          4AFF39524AFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+          5AFF42635AFF42635AFF294A4AFF000000000000000000000000425A52FF3952
+          4AFF39524AFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A73
+          6BFF5A736BFF5A736BFF42635AFF000000000000000000000000425A52FF3952
+          4AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF2942
+          39FF000000000000000000000000000000000000000000000000425A52FF3952
+          4AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF39524AFF2942
+          39FF000000000000000000000000000000000000000000000000425A52FF425A
+          52FF425A52FF425A52FF425A52FF425A52FF425A52FF425A52FF425A52FF3952
+          4AFF000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 25
         object miLayer1: TMenuItem
           Caption = 'Фон'
@@ -2101,22 +2676,166 @@ object MainForm: TMainForm
       Caption = 'Сервис'
       object miCheckMap: TMenuItem
         Caption = 'Проверка карты'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000042635AFF42635AFF0000
+          0000000000000000000000000000000000000000000000000000000000000000
+          000000000000000000000000000000000000000000006B8484FF6B8484FF0000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000042635AFF42635AFF0000
+          0000000000000000000000000000000000000000000000000000000000000000
+          000000000000000000000000000000000000000000006B8484FF5A7373FF4263
+          5AFF000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000000000000000000000000000006B8484FF6B84
+          84FF42635AFF0000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00005A7373FF42635AFF00000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00006B8484FF5A7373FF00000000000000000000000000000000000000000000
+          000000000000000000000000000042635AFF42635AFF00000000000000004263
+          5AFF5A7373FF6B8484FF00000000000000000000000000000000000000000000
+          00000000000000000000000000006B8484FF5A7373FF42635AFF42635AFF5A73
+          73FF6B8484FF0000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000006B8484FF6B8484FF6B8484FF6B84
+          84FF000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 17
         OnClick = aCheckMapExecute
       end
       object miOptimmization: TMenuItem
         Caption = 'Оптимизация карты'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000000000000010219CFF00000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          000000000000000000000000000010219CFF3139ADFF10219CFF000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000003139ADFF4A5AB5FF3139ADFF000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000010219CFF3139ADFF000000003139ADFF10219CFF0000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000010219CFF3139ADFF4A5AB5FF000000004A5AB5FF3139ADFF0000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000003139ADFF4A5AB5FF0000000000000000000000003139ADFF1021
+          9CFF000000000000000000000000000000000000000000000000000000000000
+          0000000000004A5AB5FF000000000000000000000000000000004A5AB5FF3139
+          ADFF000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000003139
+          ADFF10219CFF10219CFF00000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000004A5A
+          B5FF3139ADFF3139ADFF10219CFF10219CFF0000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00004A5AB5FF4A5AB5FF3139ADFF3139ADFF0000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          000000000000000000004A5AB5FF4A5AB5FF0000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 18
         OnClick = aOptimizeExecute
       end
       object miMapPreview: TMenuItem
         Caption = 'Предварительный просмотр'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000C6CED6FFADB5B5FFADB5B5FFADB5B5FFADB5B5FFC6CE
+          D6FF000000000000000000000000000000000000000000000000000000000000
+          000000000000BDC6C6FF848C8CFF424242FF393939FF393939FF394242FF7B84
+          84FFBDC6CEFFC6CED6FF00000000000000000000000000000000000000000000
+          0000C6CED6FF292929FF636B6BFF9C9CA5FFADB5B5FFADB5B5FFBDC6C6FF737B
+          7BFF181818FF848C8CFFC6CED6FF000000000000000000000000000000000000
+          0000C6CECEFFADB5BDFFC6CED6FF394242FF000000FF000000FF181818FFADB5
+          B5FFADB5B5FF101010FF7B7B84FF000000000000000000000000000000000000
+          00009CA5ADFF9CA5ADFF212929FF000000FF000000FF000000FF000000FF0000
+          00FF94949CFF848C8CFF182121FF000000000000000000000000000000000000
+          00005A5A63FF848C8CFF000000FF424242FFC6CECEFF000000FF000000FF0000
+          00FF84848CFF313939FF293131FFB5BDBDFF0000000000000000000000000000
+          0000949C9CFF212121FF000000FF000000FF292929FF080808FF000000FF0000
+          00FF393939FF212929FF7B8484FF8C8C8CFF0000000000000000000000000000
+          00004A5252FF84848CFF73737BFF42424AFF101010FF181818FF101010FF5252
+          52FF5A6363FF8C8C94FF424242FF949C9CFF0000000000000000000000000000
+          0000949C9CFF4A4A4AFF737B7BFF737B7BFF949C9CFF94949CFF94949CFF7B84
+          84FF6B6B73FF525252FFA5A5ADFF000000000000000000000000000000000000
+          0000C6CED6FFBDC6C6FF84848CFF737B7BFF525252FF525252FF525252FF6B73
+          73FF848C8CFFBDBDC6FF00000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 23
         ShortCut = 9
         OnClick = miMapPreviewClick
       end
       object miTestMap: TMenuItem
         Caption = 'Тест карты в игре'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000000000000000000000000000004E6363FF4255
+          55FF364545FF00000000000000004E6363FF425555FF364545FF000000000000
+          00004E6363FF425555FF364545FF00000000000000000000000000000000788C
+          8CFF5A7373FF425454FF0000000000000000788C8CFF5A7373FF425454FF0000
+          000000000000788C8CFF5A7373FF425454FF0000000000000000000000000000
+          0000788C8CFF5A7373FF425454FF0000000000000000788C8CFF5A7373FF4254
+          54FF0000000000000000788C8CFF5A7373FF425454FF00000000000000000000
+          000000000000788C8CFF5A7373FF425454FF0000000000000000788C8CFF5A73
+          73FF425454FF0000000000000000788C8CFF5A7373FF425454FF000000000000
+          000000000000425454FF5A7373FF788C8CFF0000000000000000425454FF5A73
+          73FF788C8CFF0000000000000000425454FF5A7373FF788C8CFF000000000000
+          0000425454FF5A7373FF788C8CFF0000000000000000425454FF5A7373FF788C
+          8CFF0000000000000000425454FF5A7373FF788C8CFF00000000000000004254
+          54FF5A7373FF788C8CFF0000000000000000425454FF5A7373FF788C8CFF0000
+          000000000000425454FF5A7373FF788C8CFF0000000000000000687F7FFF798D
+          8DFF879999FF0000000000000000687F7FFF798D8DFF879999FF000000000000
+          0000687F7FFF798D8DFF879999FF000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000
+        }
         ImageIndex = 27
         OnClick = miTestMapClick
       end
@@ -2125,6 +2844,42 @@ object MainForm: TMainForm
       Caption = 'Настройка'
       object miMapOptions: TMenuItem
         Caption = 'Карта'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000292929FF2929
+          29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+          18FF181818FF292929FF292929FF212121FF212121FF212121FF393939FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+          FFFFFFFFFFFF000000FF000000FF000000FF000000FF292929FF424242FFFFFF
+          FFFF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C00
+          00FFFFFFFFFF000000FF000000FF000000FF000000FF292929FF4A4A4AFFFFFF
+          FFFFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD00
+          00FFFFFFFFFF000000FF000000FFC6C6C6FFC6C6C6FF393939FF4A4A4AFFFFFF
+          FFFFD60000FFD60000FFD60000FFD60000FFD60000FFD60000FFD60000FFD600
+          00FFFFFFFFFF000000FF000000FF000000FF000000FF393939FF525252FFFFFF
+          FFFFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF00
+          00FFFFFFFFFF000000FF000000FF000000FF000000FF393939FF525252FFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF00
+          00FFFFFFFFFF080808FF080808FFC6C6C6FFC6C6C6FF424242FF5A5A5AFF0808
+          08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+          08FF080808FF080808FF080808FF080808FF080808FF424242FF5A5A5AFF0808
+          08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+          08FF080808FF080808FF080808FF080808FF080808FF4A4A4AFF636363FF0818
+          10FF081810FF081810FF081810FF081810FF081810FF081810FF081810FF0818
+          10FF081810FF081810FF081810FFC6C6C6FFC6C6C6FF4A4A4AFF6B6B6BFFFFFF
+          FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1821
+          18FF182118FF182118FF182118FF182118FF182118FF525252FF7B7B7BFF2129
+          29FF212929FF212929FF212929FF212929FF212929FF212929FFFFFFFFFF2129
+          29FF212929FF212929FF212929FF212929FF212929FF5A5A5AFF7B7B7BFF3139
+          39FF313939FF313939FF313939FF313939FF313939FF313939FF313939FF3139
+          39FF313939FF313939FF313939FFC6C6C6FFC6C6C6FF636363FF7B7B7BFF3942
+          42FF394242FF394242FF394242FF394242FF394242FF394242FF394242FF3942
+          42FF394242FF394242FF394242FF394242FF394242FF6B6B6BFF848484FF525A
+          5AFF4A5A52FF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A5AFF525A
+          5AFF525A5AFF525A5AFF525A5AFF4A5A52FF4A5A52FF737373FF848484FF8484
+          84FF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+          8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF848484FF848484FF
+        }
         ImageIndex = 14
         ShortCut = 16461
         OnClick = aMapOptionsExecute
@@ -2134,6 +2889,42 @@ object MainForm: TMainForm
       end
       object miOptions: TMenuItem
         Caption = 'Редактор'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000FF000000FF00000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000FFADADADFFBDBDBDFF000000FF316B63FF0042
+          39FF004239FF004239FF004239FF004239FF004239FF004239FF004239FF0000
+          00FF000000FF00000000000000FFB5B5B5FFCEC6CEFF000000FF5A8C84FF316B
+          63FF316B63FF316B63FF316B63FF316B63FF316B63FF316B63FF004239FF0000
+          00FF8C8C8CFF000000FFC6C6C6FFD6D6D6FF000000FF000000005A8C84FF316B
+          63FF316B63FF316B63FF316B63FF316B63FF316B63FF316B63FF004239FF0000
+          00FF9C9C9CFF8C8C8CFFCECECEFFDEDEDEFF000000FF000000005A8C84FF316B
+          63FF427B73FF10524AFF10524AFF10524AFF10524AFF10524AFF10524AFF0000
+          00FFC6C6C6FFD6D6D6FFE7E7E7FF8C8C8CFF000000FF000000FF5A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF427B73FF427B73FF427B73FF427B73FF0000
+          00FFCECECEFFDEDEDEFFEFEFEFFFFFFFFFFFFFFFFFFF000000FF5A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF5A8C8CFF216B5AFF216B5AFF216B5AFF0000
+          00FFDEDEDEFFEFEFEFFFF7F7F7FFFFFFFFFF000000FF000000005A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FFE7E7E7FFF7F7F7FFFFFFFFFF000000FF00000000000000005A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FFF7F7EFFFFFFFFFFF000000FF216B5AFF00000000000000005A8C84FF5A8C
+          84FF6BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FFF7F7F7FF000000FF5A8C8CFF216B5AFF0000000000000000000000000000
+          00006BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FF000000FF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00006BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+          8CFF5A8C8CFF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00006BA59CFF6BA59CFF6BA59CFF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+          8CFF5A8C8CFF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00000000000000000000000000007BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+          8CFF5A8C8CFF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00000000000000000000000000007BB5B5FF7BB5B5FF7BB5B5FF7BB5B5FF7BB5
+          B5FF7BB5B5FF7BB5B5FF7BB5B5FF5A8C8CFF0000000000000000
+        }
         ImageIndex = 16
         OnClick = aEditorOptionsExecute
       end
@@ -2149,6 +2940,42 @@ object MainForm: TMainForm
       Caption = 'Справка'
       object miAbout: TMenuItem
         Caption = 'О программе'
+        Bitmap.Data = {
+          36040000424D3604000000000000360000002800000010000000100000000100
+          2000000000000004000064000000640000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000FF000000FF00000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          00000000000000000000000000FFADADADFFBDBDBDFF000000FF316B63FF0042
+          39FF004239FF004239FF004239FF004239FF004239FF004239FF004239FF0000
+          00FF000000FF00000000000000FFB5B5B5FFCEC6CEFF000000FF5A8C84FF316B
+          63FF316B63FF316B63FF316B63FF316B63FF316B63FF316B63FF004239FF0000
+          00FF8C8C8CFF000000FFC6C6C6FFD6D6D6FF000000FF000000005A8C84FF316B
+          63FF316B63FF316B63FF316B63FF316B63FF316B63FF316B63FF004239FF0000
+          00FF9C9C9CFF8C8C8CFFCECECEFFDEDEDEFF000000FF000000005A8C84FF316B
+          63FF427B73FF10524AFF10524AFF10524AFF10524AFF10524AFF10524AFF0000
+          00FFC6C6C6FFD6D6D6FFE7E7E7FF8C8C8CFF000000FF000000FF5A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF427B73FF427B73FF427B73FF427B73FF0000
+          00FFCECECEFFDEDEDEFFEFEFEFFFFFFFFFFFFFFFFFFF000000FF5A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF5A8C8CFF216B5AFF216B5AFF216B5AFF0000
+          00FFDEDEDEFFEFEFEFFFF7F7F7FFFFFFFFFF000000FF000000005A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FFE7E7E7FFF7F7F7FFFFFFFFFF000000FF00000000000000005A8C84FF316B
+          63FF6BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FFF7F7EFFFFFFFFFFF000000FF216B5AFF00000000000000005A8C84FF5A8C
+          84FF6BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FFF7F7F7FF000000FF5A8C8CFF216B5AFF0000000000000000000000000000
+          00006BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF0000
+          00FF000000FF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00006BA59CFF427B73FF427B73FF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+          8CFF5A8C8CFF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00006BA59CFF6BA59CFF6BA59CFF7BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+          8CFF5A8C8CFF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00000000000000000000000000007BB5B5FF5A8C8CFF5A8C8CFF5A8C8CFF5A8C
+          8CFF5A8C8CFF5A8C8CFF5A8C8CFF216B5AFF0000000000000000000000000000
+          00000000000000000000000000007BB5B5FF7BB5B5FF7BB5B5FF7BB5B5FF7BB5
+          B5FF7BB5B5FF7BB5B5FF7BB5B5FF5A8C8CFF0000000000000000
+        }
         ImageIndex = 16
         OnClick = aAboutExecute
       end
@@ -2170,8 +2997,8 @@ object MainForm: TMainForm
   end
   object pmShow: TPopupMenu
     Images = ImageList
-    Left = 128
-    Top = 64
+    left = 128
+    top = 64
     object miLayerP1: TMenuItem
       Caption = 'Фон'
       Checked = True
@@ -2221,178 +3048,508 @@ object MainForm: TMainForm
   object ilToolbar: TImageList
     Height = 24
     Width = 24
-    Left = 64
-    Top = 101
+    left = 64
+    top = 101
     Bitmap = {
-      494C010109000E00040018001800FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
-      0000000000003600000028000000600000006000000001002000000000000090
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+      4C69090000001800000018000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000737373FF7373
+      73FF737373FF737373FF7B7B7BFF7B7B7BFF848484FF848484FF848484FF8484
+      84FF848484FF848484FF848484FF848484FF0000000000000000000000000000
+      00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFCECECEFFFFFFFFFFB5D6CEFF737373FF00000000000000000000
+      00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFC6C6C6FFFFFFFFFFD6F7EFFFB5D6CEFF6B6B6BFF000000000000
+      00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+      FFFFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FF
+      F7FFF7F7F7FFB5B5B5FFFFFFFFFFD6F7EFFFD6F7EFFFB5D6CEFF6B6B6BFF0000
+      00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+      FFFFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FF
+      F7FFF7F7F7FFA5A5A5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A5A5AFF0000
+      00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+      FFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+      F7FFF7F7F7FF949494FF8C8C8CFF737373FF737373FF5A5A5AFF5A5A5AFF0000
+      00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+      FFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+      F7FFF7F7F7FFD6D6D6FFC6C6C6FFB5B5B5FFADADADFF9C9C9CFF525252FF0000
+      00000000000000000000000000000000000000000000000000006B6B6BFFFFFF
+      FFFFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7F7FFDEF7
+      F7FFDEF7F7FFDEF7F7FFCEEFE7FFC6DEDEFFC6DEDEFFDEDEDEFF525252FF0000
+      0000000000000000000000000000000000000000000000000000636363FFFFFF
+      FFFFD6F7EFFFD6F7EFFFD6F7EFFFD6F7EFFFD6F7EFFFD6F7EFFFD6F7EFFFD6F7
+      EFFFD6F7EFFFD6F7EFFFD6F7EFFFD6F7EFFFDEFFF7FFFFFFFFFF4A4A4AFF0000
+      0000000000000000000000000000000000000000000000000000636363FFFFFF
+      FFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EF
+      EFFFD6EFEFFFD6EFEFFFD6EFEFFFD6EFEFFFDEF7F7FFFFFFFFFF4A4A4AFF0000
+      00000000000000000000000000000000000000000000000000005A5A5AFFFFFF
+      FFFFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EF
+      E7FFD6EFE7FFD6EFE7FFD6EFE7FFD6EFE7FFDEF7F7FFFFFFFFFF424242FF0000
+      00000000000000000000000000000000000000000000000000005A5A5AFFFFFF
+      FFFFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7
+      E7FFCEE7E7FFCEE7E7FFCEE7E7FFCEE7E7FFDEF7F7FFFFFFFFFF424242FF0000
+      0000000000000000000000000000000000000000000000000000525252FFFFFF
+      FFFFC6E7DEFFC6E7DEFFC6E7DEFFC6E7DEFFC6E7DEFFC6E7DEFFC6E7DEFFC6E7
+      DEFFC6E7DEFFC6E7DEFFC6E7DEFFC6E7DEFFD6F7EFFFFFFFFFFF393939FF0000
+      00000000000000000000000000000000000000000000000000004A4A4AFFFFFF
+      FFFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+      DEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFD6EFEFFFFFFFFFFF393939FF0000
+      00000000000000000000000000000000000000000000000000004A4A4AFFFFFF
+      FFFFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DE
+      D6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFD6EFE7FFFFFFFFFF393939FF0000
+      00000000000000000000000000000000000000000000000000004A4A4AFFFFFF
+      FFFFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DE
+      D6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFD6EFE7FFFFFFFFFF393939FF0000
+      00000000000000000000000000000000000000000000000000004A4A4AFFFFFF
+      FFFFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDE
+      D6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFCEE7E7FFFFFFFFFF313131FF0000
+      00000000000000000000000000000000000000000000000000004A4A4AFFFFFF
+      FFFFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFBDDE
+      D6FFBDDED6FFBDDED6FFBDDED6FFBDDED6FFCEE7E7FFFFFFFFFF313131FF0000
+      0000000000000000000000000000000000000000000000000000424242FFFFFF
+      FFFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+      DEFFC6DEDEFFC6DEDEFFC6E7DEFFC6DEDEFFC6E7DEFFFFFFFFFF313131FF0000
+      0000000000000000000000000000000000000000000000000000424242FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF292929FF0000
+      00000000000000000000000000000000000000000000000000006B6B6BFF2929
+      29FF212121FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF4A4A4AFF0000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000848484FF848484FF8484
+      84FF848484FF848484FF848484FF848484FF0000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000848484FF9C9C9CFF9C9C9CFF9C9C
+      9CFF9C9C9CFF9C9C9CFF9C9C9CFF9C9C9CFF848484FF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000848484FF949494FF949494FF9494
+      94FF949494FF949494FF949494FF949494FF848484FF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000007B7B7BFF948C8CFF948C94FF8C8C
+      8CFF8C948CFF8C8C94FF8C948CFF8C9494FF7B7B7BFF7B7B7BFF7B7B7BFF7B7B
+      7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF000000000000
+      000000000000000000000000000000000000737373FF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF6B6B6BFF6B6B6BFF6B6B6BFF6B6B6BFF6B6B6BFF6B6B6BFF6B6B
+      6BFF6B6B6BFF000000000000000000000000737373FF848484FF848484FF8484
+      84FF848484FF848484FF848484FF848484FF848484FF848484FF848484FF8484
+      84FF6B6B63FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFE7FFF7FFF7FF
+      FFFFEFFFFFFF8CA5A5FF00000000000000006B6B6BFF848484FF848484FF8484
+      84FF848484FF848484FF848484FF848484FF848484FF848484FF848484FF6B6B
+      63FFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DE
+      DEFFD6EFE7FF8CA5A5FF0000000000000000636363FF7B7B7BFF7B7B7BFF7B7B
+      7BFF737373FF636363FF636363FF636363FF636363FF636363FF636363FF7B94
+      8CFFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFC6DED6FFCEE7
+      E7FFBDD6D6FF8CA5A5FF0000000000000000636363FF7B7373FF737373FF7373
+      73FF636363FF7B948CFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFC6DEDEFFBDD6
+      D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFBDD6D6FFCEE7DEFFBDD6
+      D6FF8CA5A5FF0000000000000000000000005A5A5AFF737373FF737373FF7373
+      73FF636363FFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CE
+      CEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFB5CECEFFBDD6D6FFC6DE
+      D6FF8CA5A5FF000000000000000000000000525252FF6B6B6BFF6B6B6BFF5A5A
+      5AFF7B948CFFB5CEC6FFB5CEC6FFB5CEC6FFB5CEC6FFB5CEC6FFB5CEC6FFB5CE
+      C6FFB5CEC6FFB5CEC6FFB5CEC6FFB5CEC6FFBDD6D6FFBDD6CEFFBDD6D6FFC6DE
+      D6FF8CA5A5FF000000000000000000000000525252FF636363FF636363FF5A5A
+      5AFFADC6C6FFADC6BDFFADC6BDFFADC6BDFFADC6BDFFADC6BDFFADC6C6FFADC6
+      BDFFADC6BDFFADC6BDFFADC6BDFFB5CECEFFADC6C6FFB5D6CEFFC6DEDEFFBDD6
+      D6FF8CA5A5FF0000000000000000000000004A4A4AFF5A6363FF636363FF5A52
+      5AFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BD
+      BDFFA5BDBDFFA5BDBDFFA5BDBDFFA5BDBDFFB5CEC6FFBDD6D6FFB5CECEFF8CA5
+      A5FF00000000000000000000000000000000424242FF5A5A5AFF525252FF7B94
+      8CFFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BDB5FFA5BD
+      B5FFA5BDB5FFA5BDB5FFA5BDB5FFADC6BDFFA5BDBDFFADC6BDFFADCEC6FF8CA5
+      A5FF00000000000000000000000000000000424242FF525252FF525252FF9CB5
+      ADFF9CB5ADFF9CB5ADFF9CB5ADFF9CB5ADFF9CB5ADFF9CB5ADFF9CB5ADFF9CB5
+      ADFF9CB5ADFF9CB5ADFFA5BDB5FF9CB5B5FFA5BDBDFFADCEC6FFADC6C6FF8CA5
+      A5FF00000000000000000000000000000000393939FF525252FF4A4A52FF94AD
+      ADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94ADADFF94AD
+      ADFF94ADADFF94ADADFF94ADADFFA5BDB5FF9CB5B5FF9CB5B5FFA5C6BDFF8CA5
+      A5FF00000000000000000000000000000000313139FF4A4A4AFF7B948CFF94AD
+      A5FF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94ADA5FF94AD
+      A5FF94ADA5FF94ADA5FF9CB5ADFF94ADADFF9CB5B5FF9CBDB5FF8CA5A5FF0000
+      000000000000000000000000000000000000313131FF4A4A4AFF8CA5A5FF8CA5
+      A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+      A5FF8CA5A5FF94ADADFF8CA5A5FF94ADADFF8CA5A5FF9CBDB5FF8CA5A5FF0000
+      000000000000000000000000000000000000313131FF4A4A4AFF7B948CFF7B94
+      8CFF7B948CFF7B948CFF7B948CFF7B948CFF7B948CFF7B948CFF7B948CFF7B94
+      8CFF7B948CFF7B948CFF7B948CFF7B948CFF94ADADFF8CA5A5FF8CA5A5FF0000
+      0000000000000000000000000000000000000000000042424AFF42424AFF4242
+      4AFF42424AFF42424AFF42424AFF42424AFF42424AFF42424AFF42424AFF4242
+      4AFF42424AFF42424AFF42424AFF42424AFF42424AFF42424AFF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000848484FF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C
+      8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8C8C8CFF8484
+      84FF00000000000000000000000000000000848484FFDEF7F7FFA5BDB5FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7F7FF9CB5ADFFB5CE
+      CEFF737373FF0000000000000000000000007B7B7BFFD6F7EFFFA5BDB5FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94ADA5FFADCE
+      C6FF6B6B6BFF0000000000000000000000007B7B7BFFD6EFE7FFA5BDB5FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94ADADFFADC6
+      C6FF636363FF0000000000000000000000007B7B7BFFCEE7DEFFA5BDB5FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8CA5A5FFADC6
+      C6FF5A5A5AFF000000000000000000000000737373FFC6DED6FFA5BDB5FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF849C9CFFA5C6
+      BDFF5A5A5AFF000000000000000000000000737373FFB5D6CEFFA5BDB5FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF849C9CFFA5BD
+      B5FF5A5A5AFF0000000000000000000000006B6B6BFFB5CEC6FF9CB5B5FFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF849C94FF9CBD
+      B5FF525252FF0000000000000000000000006B6B6BFFADCEC6FF9CB5ADFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7F7FF7B9C94FF9CB5
+      B5FF525252FF000000000000000000000000636363FFADC6C6FF94ADADFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7F7FF7B9494FF94AD
+      ADFF4A4A4AFF0000000000000000000000005A5A5AFFADC6BDFF94ADA5FFE7E7
+      E7FFF7F7F7FFF7F7F7FFF7F7F7FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEF
+      EFFFEFEFEFFFEFEFEFFFEFEFEFFFF7F7F7FFEFEFEFFFDEDEDEFF73948CFF94AD
+      ADFF4A4A4AFF0000000000000000000000005A5A5AFFA5C6BDFF8CA59CFF8CA5
+      A5FF8CA5A5FF849C9CFF7B948CFF738C84FF738C84FF738C84FF738C84FF738C
+      84FF738C84FF738C8CFF738C8CFF738C8CFF738C8CFF738C8CFF6B8484FF8CAD
+      A5FF424242FF000000000000000000000000525252FFA5BDB5FFA5BDB5FFA5BD
+      B5FF9CB5B5FF94B5ADFF8CADA5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+      A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5A5FF8CA5
+      A5FF424242FF000000000000000000000000525252FF9CB5B5FF9CB5ADFF9C9C
+      9CFFB5CECEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94ADA5FF7B7B7BFF849C9CFF849C
+      9CFF393939FF0000000000000000000000004A4A4AFF94ADA5FF8CA5A5FF7B7B
+      7BFF9CB5B5FFFFFFFFFF5A736BFF6B8C84FF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9CB5B5FF6B6B6BFF849C9CFF849C
+      9CFF393939FF0000000000000000000000004A4A4AFF94ADA5FF8CA5A5FF7B7B
+      7BFF9CB5B5FFFFFFFFFF5A736BFF6B8C84FF8CA5A5FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9CB5B5FF6B6B6BFF849C9CFF849C
+      9CFF393939FF0000000000000000000000004A4A4AFF849C9CFF7B9C94FF7373
+      73FF94ADADFFFFFFFFFF52736BFF73948CFF94ADADFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94ADADFF6B6B6BFF7B9C94FF7B9C
+      94FF313131FF000000000000000000000000424242FF7B9C94FF7B9C94FF6B6B
+      6BFF8CADA5FFFFFFFFFF6B847BFF738C8CFF94ADA5FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F7F7FF94ADADFF6B6B6BFF7B9C94FF7B9C
+      94FF313131FF000000000000000000000000424242FF7B9494FF7B9494FF6B6B
+      6BFF8CA59CFFFFFFFFFFE7E7E7FF9CB5ADFFA5BDB5FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFEFEFEFFFEFEFEFFFE7E7E7FF94ADA5FF6B6B6BFF7B9494FF7B94
+      94FF292929FF000000000000000000000000393939FF7B9494FF7B9494FF6363
+      63FF738C8CFFE7E7E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFF7F7F7FFE7E7E7FFE7E7E7FFD6D6D6FF6B8C84FF5A5A5AFF7B9494FF7B94
+      94FF292929FF00000000000000000000000000000000292929FF212121FF1818
+      18FF181818FF181818FF181818FF181818FF181818FF181818FF181818FF1818
+      18FF181818FF181818FF181818FF181818FF292929FF292929FF212121FF2121
+      21FF000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000007B8C8CFF7B8C8CFF7B8C8CFF7B8C
+      8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C
+      8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C8CFF7B8C
+      8CFF7B8C8CFF0000000000000000000000007B8C8CFF4A5A52FF4A5A52FF4A5A
+      52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A
+      52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A52FF4A5A
+      52FF7B8C8CFF0000000000000000000000007B8C8CFF424A4AFF424A4AFF424A
+      4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A
+      4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A4AFF424A
+      4AFF7B8C8CFF0000000000000000000000007B8C8CFF394242FF394242FF3942
+      42FF394242FF394242FF394242FF394242FF394242FF394242FF394242FF3942
+      42FF394242FF394242FF394242FF394242FF394242FF394242FFA5ADADFFA5AD
+      ADFF7B8C8CFF000000000000000000000000848C8CFF313939FF313939FF3139
+      39FF313939FF313939FF313939FF313939FF313939FF313939FFCED6D6FF3139
+      39FF313939FF313939FF313939FF313939FF313939FF313939FF313939FF3139
+      39FF848C8CFF000000000000000000000000848C8CFF293131FF293131FF2931
+      31FF293131FF293131FF293131FF293131FF293131FF293131FFD6DEDEFF2931
+      31FF293131FF293131FF293131FF293131FF293131FF293131FF293131FF2931
+      31FF848C8CFF000000000000000000000000848C84FFDEE7E7FFDEE7E7FFDEE7
+      E7FFDEE7E7FFDEE7E7FFDEE7E7FFDEE7E7FFDEE7E7FFDEE7E7FFDEE7E7FF2129
+      29FF212929FF212929FF212929FF212929FF212929FF212929FFB5BDB5FFB5BD
+      B5FF848C84FF000000000000000000000000848484FF182118FF182118FF1821
+      18FF182118FF182118FF182118FF182118FF182118FF182118FF182118FF1821
+      18FF182118FF182118FF182118FF182118FF182118FF182118FF182118FF1821
+      18FF848484FF000000000000000000000000848484FF101810FF101810FF1018
+      10FF101810FF101810FF101810FF101810FF101810FF101810FF101810FF1018
+      10FF101810FF101810FF101810FF101810FF101810FF101810FF101810FF1018
+      10FF848484FF000000000000000000000000848484FF081010FF081010FF0810
+      10FF081010FF081010FF081010FF081010FF081010FF081010FF081010FF0810
+      10FF081010FF081010FF081010FF081010FF081010FF081010FFBDC6C6FFBDC6
+      C6FF848484FF000000000000000000000000848484FF080808FF080808FF0808
+      08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+      08FF080808FF080808FF080808FF080808FF080808FF080808FF080808FF0808
+      08FF848484FF000000000000000000000000848484FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000
+      00FF848484FF000000000000000000000000848484FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0000FFFF00
+      00FFFF0000FFFF0000FFFFFFFFFF000000FF000000FF000000FFC6C6C6FFC6C6
+      C6FF848484FF000000000000000000000000848484FFFFFFFFFFFF0000FFFF00
+      00FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF00
+      00FFFF0000FFFF0000FFFFFFFFFF000000FF000000FF000000FF000000FF0000
+      00FF848484FF000000000000000000000000848484FFFFFFFFFFEF0000FFEF00
+      00FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF0000FFEF00
+      00FFEF0000FFEF0000FFFFFFFFFF000000FF000000FF000000FF000000FF0000
+      00FF848484FF000000000000000000000000848484FFFFFFFFFFD60000FFD600
+      00FFD60000FFD60000FFD60000FFD60000FFD60000FFD60000FFD60000FFD600
+      00FFD60000FFD60000FFFFFFFFFF000000FF000000FF000000FFC6C6C6FFC6C6
+      C6FF848484FF000000000000000000000000848484FFFFFFFFFFBD0000FFBD00
+      00FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD0000FFBD00
+      00FFBD0000FFBD0000FFFFFFFFFF000000FF000000FF000000FF000000FF0000
+      00FF848484FF000000000000000000000000848484FFFFFFFFFFA50000FFA500
+      00FFA50000FFA50000FFA50000FFA50000FFA50000FFA50000FFA50000FFA500
+      00FFA50000FFA50000FFFFFFFFFF000000FF000000FF000000FF000000FF0000
+      00FF848484FF000000000000000000000000848484FFFFFFFFFF8C0000FF8C00
+      00FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C0000FF8C00
+      00FF8C0000FF8C0000FFFFFFFFFF000000FF000000FF000000FFC6C6C6FFC6C6
+      C6FF848484FF000000000000000000000000848484FFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+      FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000FF000000FF000000FF000000FF0000
+      00FF848484FF000000000000000000000000848484FF848484FF848484FF8484
+      84FF848484FF848484FF848484FF848484FF848484FF848484FF848484FF8484
+      84FF848484FF848484FF848484FF848484FF848484FF848484FF848484FF8484
+      84FF848484FF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000004A5AB5FF4A5AB5FF4A5AB5FF4A5A
+      B5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5AB5FF4A5A
+      B5FF3139ADFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF10219CFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF10219CFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139ADFF3139
+      ADFF10219CFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A736BFF5A73
+      6BFF5A736BFF5A736BFF5A736BFF5A736BFF42635AFF00000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF294A4AFF00000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF294A4AFF00000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF294A4AFF00000000000000000000
+      0000000000000000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF42635AFF42635AFF42635AFF6B8484FF6B8484FF6B8484FF6B84
+      84FF6B8484FF6B8484FF6B8484FF6B8484FF6B8484FF6B8484FF6B8484FF6B84
+      84FF5A7373FF0000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF42635AFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF42635AFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000004A5AB5FF3139ADFF3139ADFF3139
+      ADFF5A736BFF42635AFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000003139ADFF10219CFF10219CFF1021
+      9CFF5A736BFF42635AFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      00005A736BFF42635AFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      00005A736BFF42635AFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      00005A736BFF42635AFF42635AFF42635AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      000042635AFF294A4AFF294A4AFF294A4AFF6B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000006B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000006B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000006B8484FF5A7373FF5A7373FF5A73
+      73FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A7373FF5A73
+      73FF42635AFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000005A7373FF42635AFF42635AFF4263
+      5AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF42635AFF4263
+      5AFF42635AFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF000000000000000000000000828282FFA8A191FFA8A191FFA8A1
+      91FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A1
+      91FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A1
+      91FF777777FF0000000000000000000000007E7E7EFFA59C8CFFFFFFFFFFA59C
+      8CFFA59C8CFFA59C8CFFFFFFFFFFA59C8CFFA59C8CFFA59C8CFFA59C8CFFA59C
+      8CFFA59C8CFFA59C8CFFA59C8CFFA59C8CFFA59C8CFFA59C8CFFA59C8CFFA59C
+      8CFF686868FF0000000000000000000000007D7D7DFFA19785FFA19785FF665F
+      54FFA19785FFA19785FFA19785FF665F54FFA19785FFA19785FFA19785FFA197
+      85FFA19785FFA19785FFA19785FFA19785FFA19785FFA19785FFA19785FFA197
+      85FF616161FF000000000000000000000000787878FF9D9280FF9D9280FF9D92
+      80FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D92
+      80FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D92
+      80FF5E5E5EFF000000000000000000000000757575FF9A8D7AFF9A8D7AFF9A8D
+      7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D
+      7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D
+      7AFF5B5B5BFF000000000000000000000000717171FF998C79FFFFFFFFFF9788
+      75FF978875FF978875FFFFFFFFFF978875FF978875FF978875FF978875FF9788
+      75FF978875FF978875FF978875FF978875FF978875FF978875FF978875FF9788
+      75FF585858FF0000000000000000000000006C6C6CFF93846FFF93846FFF5D53
+      46FF93846FFF93846FFF93846FFF5D5346FF93846FFF93846FFF93846FFF9384
+      6FFF93846FFF93846FFF93846FFF93846FFF93846FFF93846FFF93846FFF9384
+      6FFF555555FF000000000000000000000000686868FF917F6BFF917F6BFF917F
+      6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F
+      6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F
+      6BFF525252FF000000000000000000000000656565FF8E7C66FF8E7C66FF8E7C
+      66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FFFFFFFFFF8E7C66FF8E7C
+      66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FFFFFFFFFF8E7C
+      66FF4C4C4CFF0000000000000000000000005F5F5FFF8B7862FF8B7862FF8B78
+      62FF8B7862FF8B7862FF8B7862FF8B7862FF8B7862FF8B7862FF584C3EFF8B78
+      62FF8B7862FF8B7862FF8B7862FF8B7862FF8B7862FF8B7862FF8B7862FF584C
+      3EFF484848FF0000000000000000000000005B5B5BFF8A765FFF8A765FFF8A76
+      5FFF8A765FFF8A765FFF8A765FFF8A765FFF8A765FFF8A765FFF8A765FFF8A76
+      5FFF8A765FFF8A765FFF8A765FFF8A765FFF8A765FFF8A765FFF8A765FFF8A76
+      5FFF454545FF000000000000000000000000555555FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF404040FF000000000000000000000000525252FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF3C3C3CFF0000000000000000000000004C4C4CFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF383838FF0000000000000000000000004C4C4CFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF383838FF000000000000000000000000484848FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF333333FF000000000000000000000000434343FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF323232FF000000000000000000000000404040FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFFFFFFFFFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFFFFFFFFFF8873
+      5DFF2C2C2CFF0000000000000000000000003D3D3DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF56493BFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF5649
+      3BFF2A2A2AFF0000000000000000000000002C2C2CFF2C2C2CFF222222FF1F1F
+      1FFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C
+      1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF292929FF2A2A2AFF202020FF2525
+      25FF2C2C2CFF0000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF000000000000000000000000828282FFA8A191FFA8A191FFA8A1
+      91FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A1
+      91FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A191FFA8A1
+      91FF777777FF0000000000000000000000007E7E7EFFA59C8CFFFFFFFFFFA59C
+      8CFFA59C8CFFA59C8CFFFFFFFFFFA59C8CFFA59C8CFFA59C8CFFFFFFFFFFA59C
+      8CFFA59C8CFFA59C8CFFFFFFFFFFA59C8CFFA59C8CFFA59C8CFFFFFFFFFFA59C
+      8CFF686868FF0000000000000000000000007D7D7DFFA19785FFA19785FF665F
+      54FFA19785FFA19785FFA19785FF665F54FFA19785FFA19785FFA19785FF665F
+      54FFA19785FFA19785FFA19785FF665F54FFA19785FFA19785FFA19785FF665F
+      54FF616161FF000000000000000000000000787878FF9D9280FF9D9280FF9D92
+      80FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D92
+      80FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D9280FF9D92
+      80FF5E5E5EFF000000000000000000000000757575FF9A8D7AFF9A8D7AFF9A8D
+      7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D
+      7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D7AFF9A8D
+      7AFF5B5B5BFF000000000000000000000000717171FF998C79FFFFFFFFFF9788
+      75FF978875FF978875FFFFFFFFFF978875FF978875FF978875FFFFFFFFFF9788
+      75FF978875FF978875FFFFFFFFFF978875FF978875FF978875FFFFFFFFFF9788
+      75FF585858FF0000000000000000000000006C6C6CFF93846FFF93846FFF5D53
+      46FF93846FFF93846FFF93846FFF5D5346FF93846FFF93846FFF93846FFF5D53
+      46FF93846FFF93846FFF93846FFF5D5346FF93846FFF93846FFF93846FFF5D53
+      46FF555555FF000000000000000000000000686868FF917F6BFF917F6BFF917F
+      6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F
+      6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F6BFF917F
+      6BFF525252FF000000000000000000000000656565FF8E7C66FF8E7C66FF8E7C
+      66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C
+      66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C66FF8E7C
+      66FF4C4C4CFF0000000000000000000000005F5F5FFF8B7862FFFFFFFFFF8B78
+      62FF8B7862FF8B7862FFFFFFFFFF8B7862FF8B7862FF8B7862FFFFFFFFFF8B78
+      62FF8B7862FF8B7862FFFFFFFFFF8B7862FF8B7862FF8B7862FFFFFFFFFF8B78
+      62FF484848FF0000000000000000000000005B5B5BFF8A765FFF8A765FFF574B
+      3CFF8A765FFF8A765FFF8A765FFF574B3CFF8A765FFF8A765FFF8A765FFF574B
+      3CFF8A765FFF8A765FFF8A765FFF574B3CFF8A765FFF8A765FFF8A765FFF574B
+      3CFF454545FF000000000000000000000000555555FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF404040FF000000000000000000000000525252FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF3C3C3CFF0000000000000000000000004C4C4CFF88735DFFFFFFFFFF8873
+      5DFF88735DFF88735DFFFFFFFFFF88735DFF88735DFF88735DFFFFFFFFFF8873
+      5DFF88735DFF88735DFFFFFFFFFF88735DFF88735DFF88735DFFFFFFFFFF8873
+      5DFF383838FF0000000000000000000000004C4C4CFF88735DFF88735DFF5649
+      3BFF88735DFF88735DFF88735DFF56493BFF88735DFF88735DFF88735DFF5649
+      3BFF88735DFF88735DFF88735DFF56493BFF88735DFF88735DFF88735DFF5649
+      3BFF383838FF000000000000000000000000484848FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF333333FF000000000000000000000000434343FF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF88735DFF8873
+      5DFF323232FF000000000000000000000000404040FF88735DFFFFFFFFFF8873
+      5DFF88735DFF88735DFFFFFFFFFF88735DFF88735DFF88735DFFFFFFFFFF8873
+      5DFF88735DFF88735DFFFFFFFFFF88735DFF88735DFF88735DFFFFFFFFFF8873
+      5DFF2C2C2CFF0000000000000000000000003D3D3DFF88735DFF88735DFF5649
+      3BFF88735DFF88735DFF88735DFF56493BFF88735DFF88735DFF88735DFF5649
+      3BFF88735DFF88735DFF88735DFF56493BFF88735DFF88735DFF88735DFF5649
+      3BFF2A2A2AFF0000000000000000000000002C2C2CFF2C2C2CFF222222FF1F1F
+      1FFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C
+      1CFF1C1C1CFF1C1C1CFF1C1C1CFF1C1C1CFF292929FF2A2A2AFF202020FF2525
+      25FF2C2C2CFF0000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -2410,10 +3567,54 @@ object MainForm: TMainForm
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000006B84
+      84FF6B8484FF6B8484FF00000000000000006B8484FF6B8484FF6B8484FF0000
+      0000000000006B8484FF6B8484FF6B8484FF0000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      000042635AFF5A7373FF6B8484FF000000000000000042635AFF5A7373FF6B84
+      84FF000000000000000042635AFF5A7373FF6B8484FF00000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      00000000000042635AFF5A7373FF6B8484FF000000000000000042635AFF5A73
+      73FF6B8484FF000000000000000042635AFF5A7373FF6B8484FF000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000042635AFF5A7373FF6B8484FF00000000000000004263
+      5AFF5A7373FF6B8484FF000000000000000042635AFF5A7373FF6B8484FF0000
       0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000005A7373FF5A7373FF6B8484FF000000000000
+      00005A7373FF5A7373FF6B8484FF00000000000000005A7373FF5A7373FF6B84
+      84FF000000000000000000000000000000000000000000000000000000000000
+      000000000000000000006B8484FF5A7373FF42635AFF00000000000000006B84
+      84FF5A7373FF42635AFF00000000000000006B8484FF5A7373FF42635AFF0000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000006B8484FF5A7373FF42635AFF00000000000000006B8484FF5A73
+      73FF42635AFF00000000000000006B8484FF5A7373FF42635AFF000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00006B8484FF5A7373FF42635AFF00000000000000006B8484FF5A7373FF4263
+      5AFF00000000000000006B8484FF5A7373FF42635AFF00000000000000000000
+      0000000000000000000000000000000000000000000000000000000000005A73
+      73FF42635AFF42635AFF00000000000000005A7373FF42635AFF42635AFF0000
+      0000000000005A7373FF42635AFF42635AFF0000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000000000FF000000FF0000
+      00FF000000FF00000000000000FF000000FF000000FF000000FF000000000000
+      00FF000000FF000000FF000000FF00000000000000FF000000FF000000FF0000
+      00FF000000000000000000000000000000000000000000000000000000FF0000
+      00FF0000000000000000000000FF000000FF0000000000000000000000000000
+      00FF000000FF00000000000000000000000000000000000000FF000000FF0000
+      0000000000000000000000000000000000000000000000000000000000FF0000
+      00FF0000000000000000000000FF000000FF000000FF00000000000000000000
+      00FF000000FF000000FF000000FF0000000000000000000000FF000000FF0000
+      0000000000000000000000000000000000000000000000000000000000FF0000
+      00FF0000000000000000000000FF000000FF0000000000000000000000000000
+      000000000000000000FF000000FF0000000000000000000000FF000000FF0000
+      0000000000000000000000000000000000000000000000000000000000FF0000
+      00FF0000000000000000000000FF000000FF000000FF000000FF000000000000
+      00FF000000FF000000FF000000FF0000000000000000000000FF000000FF0000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -2429,1006 +3630,111 @@ object MainForm: TMainForm
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000008D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D9CFF8D9D
+      9CFF8D9D9CFF000000000000000000000000828282FF9D9D9DFFF4F4F4FFC8C8
+      C8FF737373FFF4F4F4FFF0F0F0FFADADADFFADADADFFF4F4F4FFADADADFFF4F4
+      F4FF9D9D9DFFEAEAEAFFC8C8C8FFF4F4F4FF9D9D9DFFEAEAEAFFBCBCBCFFDDDD
+      DDFF777777FF0000000000000000000000007E7E7EFF9D9D9DFFF0F0F0FF9D9D
+      9DFFADADADFFF4F4F4FFC8C8C8FFEAEAEAFF9D9D9DFFF4F4F4FF898989FFADAD
+      ADFFADADADFFDDDDDDFFDDDDDDFFF4F4F4FFADADADFFF4F4F4FFDDDDDDFFDDDD
+      DDFF686868FF0000000000000000000000007D7D7DFFEAEAEAFF737373FFC8C8
+      C8FFADADADFFF4F4F4FF9D9D9DFFADADADFF898989FFD4D4D4FFADADADFFF4F4
+      F4FFF4F4F4FFE4E4E4FFC8C8C8FFF4F4F4FFADADADFFF4F4F4FFDDDDDDFFDDDD
+      DDFF616161FF000000000000000000000000787878FFF4F4F4FF898989FFF4F4
+      F4FFC8C8C8FFF4F4F4FFBCBCBCFFF4F4F4FFF4F4F4FFBCBCBCFFC8C8C8FFF4F4
+      F4FFF4F4F4FFF4F4F4FFADADADFFADADADFFE4E4E4FFEAEAEAFF9D9D9DFF9D9D
+      9DFF5E5E5EFF000000000000000000000000757575FFF2F2F2FFF2F2F2FFF2F2
+      F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2
+      F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2F2FFF2F2
+      F2FF5B5B5BFF000000000000000000000000717171FFC6A069FFC6A069FFC6A0
+      69FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A0
+      69FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A0
+      69FF585858FF0000000000000000000000006C6C6CFFC6A069FFC6A069FFC6A0
+      69FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A0
+      69FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A069FFC6A0
+      69FF555555FF000000000000000000000000686868FFD2B790FFC6A069FFC6A0
+      69FFE9E0D1FFC6A069FFC6A069FFE7DAC6FFD2B790FFC6A069FFE7DAC6FFEEE5
+      DAFFDDC9B0FFC6A069FFDDC9B0FFEEE5DAFFCCAD7CFFD2B790FFEEE5DAFFDDC9
+      B0FF525252FF000000000000000000000000656565FFEFE8DEFFC2975CFFDAC7
+      A8FFFAF8F5FFC2975CFFC2975CFFF3EEE7FFE9DECCFFC2975CFFEDE4D7FFC297
+      5CFFF3EEE7FFC7A56FFFEDE4D7FFC7A56FFFEFE8DEFFCDAE83FFC2975CFFEFE8
+      DEFF4C4C4CFF0000000000000000000000005F5F5FFFEEE7DDFFBE9258FFEEE7
+      DDFFECE2D5FFBE9258FFDECDB1FFD3B892FFEEE7DDFFBE9258FFEEE7DDFFD8C3
+      A5FFF2EDE6FFD8C3A5FFD8C3A5FFBE9258FFECE2D5FFBE9258FFBE9258FFEEE7
+      DDFF484848FF0000000000000000000000005B5B5BFFD8C1A0FFEBE0D3FFE7DA
+      CBFFEBE0D3FFBF9154FFEFE6DCFFEBE1D4FFF5F0EBFFD2B790FFEFE6DCFFD8C1
+      A0FFBF9154FFD8C1A0FFDECAB1FFBF9154FFEBE0D3FFBF9154FFEEE5DCFFD2B7
+      90FF454545FF000000000000000000000000555555FFBC8B51FFFBFAF9FFC399
+      63FFEBE1D4FFBC8B51FFEEE5DCFFBC8B51FFC39963FFEEE5DCFFEBE1D4FFBC8B
+      51FFBC8B51FFBC8B51FFF2EBE5FFEBE1D4FFDDC9B0FFE2D3BEFFF5EFEBFFEBE1
+      D4FF404040FF000000000000000000000000525252FFBC8B51FFBC8B51FFBC8B
+      51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B
+      51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B
+      51FF3C3C3CFF0000000000000000000000004C4C4CFFBC8B51FFBC8B51FFBC8B
+      51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B
+      51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B51FFBC8B
+      51FF383838FF0000000000000000000000004C4C4CFFE5E5E5FFE5E5E5FFE5E5
+      E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5
+      E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5
+      E5FF383838FF000000000000000000000000484848FFE5E5E5FFE5E5E5FFE5E5
+      E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5
+      E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5E5FFE5E5
+      E5FF333333FF000000000000000000000000434343FF9E9E9EFFE5E5E5FFDEDE
+      DEFF0C0C0CFFE5E5E5FFE5E5E5FF232323FFB1B1B1FFE5E5E5FF464646FF6F6F
+      6FFF464646FFE5E5E5FF585858FF585858FFB1B1B1FF9E9E9EFF6F6F6FFF6F6F
+      6FFF323232FF000000000000000000000000404040FF464646FFE5E5E5FF6F6F
+      6FFF464646FFE5E5E5FFD6D6D6FF9E9E9EFF6F6F6FFFE5E5E5FF6F6F6FFFE5E5
+      E5FF585858FFCDCDCDFFB1B1B1FFE5E5E5FF585858FFE5E5E5FFDEDEDEFF5858
+      58FF2C2C2CFF0000000000000000000000003D3D3DFF898989FFD6D6D6FF6F6F
+      6FFF6F6F6FFFE5E5E5FF898989FFB1B1B1FF323232FFDEDEDEFF464646FF6F6F
+      6FFFB1B1B1FFC0C0C0FFC0C0C0FFE5E5E5FF6F6F6FFFD6D6D6FF6F6F6FFF6F6F
+      6FFF2A2A2AFF0000000000000000000000002A2A2AFF2A2A2AFF2A2A2AFF2A2A
+      2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A
+      2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A2AFF2A2A
+      2AFF2A2A2AFF0000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000002A2A2A002A2A2A002A2A
-      2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A
-      2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A2A002A2A
-      2A002A2A2A002A2A2A0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000003D3D3D0089898900D6D6
-      D6006F6F6F006F6F6F00E5E5E50089898900B1B1B10032323200DEDEDE004646
-      46006F6F6F00B1B1B100C0C0C000C0C0C000E5E5E5006F6F6F00D6D6D6006F6F
-      6F006F6F6F002A2A2A0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004040400046464600E5E5
-      E5006F6F6F0046464600E5E5E500D6D6D6009E9E9E006F6F6F00E5E5E5006F6F
-      6F00E5E5E50058585800CDCDCD00B1B1B100E5E5E50058585800E5E5E500DEDE
-      DE00585858002C2C2C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000434343009E9E9E00E5E5
-      E500DEDEDE000C0C0C00E5E5E500E5E5E50023232300B1B1B100E5E5E5004646
-      46006F6F6F0046464600E5E5E5005858580058585800B1B1B1009E9E9E006F6F
-      6F006F6F6F003232320000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000048484800E5E5E500E5E5
-      E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5
-      E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5
-      E500E5E5E5003333330000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00E5E5E500E5E5
-      E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5
-      E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5E500E5E5
-      E500E5E5E5003838380000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004C4C4C00BC8B5100BC8B
-      5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B
-      5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B
-      5100BC8B51003838380000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000052525200BC8B5100BC8B
-      5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B
-      5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B5100BC8B
-      5100BC8B51003C3C3C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000055555500BC8B5100FBFA
-      F900C3996300EBE1D400BC8B5100EEE5DC00BC8B5100C3996300EEE5DC00EBE1
-      D400BC8B5100BC8B5100BC8B5100F2EBE500EBE1D400DDC9B000E2D3BE00F5EF
-      EB00EBE1D4004040400000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000005B5B5B00D8C1A000EBE0
-      D300E7DACB00EBE0D300BF915400EFE6DC00EBE1D400F5F0EB00D2B79000EFE6
-      DC00D8C1A000BF915400D8C1A000DECAB100BF915400EBE0D300BF915400EEE5
-      DC00D2B790004545450000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000005F5F5F00EEE7DD00BE92
-      5800EEE7DD00ECE2D500BE925800DECDB100D3B89200EEE7DD00BE925800EEE7
-      DD00D8C3A500F2EDE600D8C3A500D8C3A500BE925800ECE2D500BE925800BE92
-      5800EEE7DD004848480000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000065656500EFE8DE00C297
-      5C00DAC7A800FAF8F500C2975C00C2975C00F3EEE700E9DECC00C2975C00EDE4
-      D700C2975C00F3EEE700C7A56F00EDE4D700C7A56F00EFE8DE00CDAE8300C297
-      5C00EFE8DE004C4C4C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000068686800D2B79000C6A0
-      6900C6A06900E9E0D100C6A06900C6A06900E7DAC600D2B79000C6A06900E7DA
-      C600EEE5DA00DDC9B000C6A06900DDC9B000EEE5DA00CCAD7C00D2B79000EEE5
-      DA00DDC9B0005252520000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000006C6C6C00C6A06900C6A0
-      6900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A0
-      6900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A0
-      6900C6A069005555550000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000071717100C6A06900C6A0
-      6900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A0
-      6900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A06900C6A0
-      6900C6A069005858580000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000075757500F2F2F200F2F2
-      F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2
-      F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2F200F2F2
-      F200F2F2F2005B5B5B0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000078787800F4F4F4008989
-      8900F4F4F400C8C8C800F4F4F400BCBCBC00F4F4F400F4F4F400BCBCBC00C8C8
-      C800F4F4F400F4F4F400F4F4F400ADADAD00ADADAD00E4E4E400EAEAEA009D9D
-      9D009D9D9D005E5E5E0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007D7D7D00EAEAEA007373
-      7300C8C8C800ADADAD00F4F4F4009D9D9D00ADADAD0089898900D4D4D400ADAD
-      AD00F4F4F400F4F4F400E4E4E400C8C8C800F4F4F400ADADAD00F4F4F400DDDD
-      DD00DDDDDD006161610000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007E7E7E009D9D9D00F0F0
-      F0009D9D9D00ADADAD00F4F4F400C8C8C800EAEAEA009D9D9D00F4F4F4008989
-      8900ADADAD00ADADAD00DDDDDD00DDDDDD00F4F4F400ADADAD00F4F4F400DDDD
-      DD00DDDDDD006868680000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000000000000000828282009D9D9D00F4F4
-      F400C8C8C80073737300F4F4F400F0F0F000ADADAD00ADADAD00F4F4F400ADAD
-      AD00F4F4F4009D9D9D00EAEAEA00C8C8C800F4F4F4009D9D9D00EAEAEA00BCBC
-      BC00DDDDDD007777770000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000005A73730042635A004263
-      5A0042635A0042635A0042635A0042635A0042635A0042635A0042635A004263
-      5A0042635A0042635A000000000000000000000000002C2C2C002C2C2C002222
-      22001F1F1F001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C
-      1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C00292929002A2A2A002020
-      2000252525002C2C2C000000000000000000000000002C2C2C002C2C2C002222
-      22001F1F1F001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C
-      1C001C1C1C001C1C1C001C1C1C001C1C1C001C1C1C00292929002A2A2A002020
-      2000252525002C2C2C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000003D3D3D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D005649
-      3B0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0056493B002A2A2A000000000000000000000000003D3D3D0088735D008873
-      5D0056493B0088735D0088735D0088735D0056493B0088735D0088735D008873
-      5D0056493B0088735D0088735D0088735D0056493B0088735D0088735D008873
-      5D0056493B002A2A2A0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000004040400088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D00FFFFFF008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D00FFFF
-      FF0088735D002C2C2C000000000000000000000000004040400088735D00FFFF
-      FF0088735D0088735D0088735D00FFFFFF0088735D0088735D0088735D00FFFF
-      FF0088735D0088735D0088735D00FFFFFF0088735D0088735D0088735D00FFFF
-      FF0088735D002C2C2C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000004343430088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D00323232000000000000000000000000004343430088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D003232320000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000042635A00294A4A00294A4A00294A4A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000004848480088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D00333333000000000000000000000000004848480088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D003333330000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000005A736B0042635A0042635A0042635A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000004C4C4C0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D00383838000000000000000000000000004C4C4C0088735D008873
-      5D0056493B0088735D0088735D0088735D0056493B0088735D0088735D008873
-      5D0056493B0088735D0088735D0088735D0056493B0088735D0088735D008873
-      5D0056493B003838380000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000005A736B0042635A0042635A0042635A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000004C4C4C0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D00383838000000000000000000000000004C4C4C0088735D00FFFF
-      FF0088735D0088735D0088735D00FFFFFF0088735D0088735D0088735D00FFFF
-      FF0088735D0088735D0088735D00FFFFFF0088735D0088735D0088735D00FFFF
-      FF0088735D003838380000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000005A736B0042635A0042635A0042635A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000005252520088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D003C3C3C000000000000000000000000005252520088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D003C3C3C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000003139AD0010219C001021
-      9C0010219C005A736B0042635A0042635A0042635A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000005555550088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D00404040000000000000000000000000005555550088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D0088735D0088735D0088735D0088735D0088735D0088735D008873
-      5D0088735D004040400000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B0042635A0042635A0042635A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000005B5B5B008A765F008A76
-      5F008A765F008A765F008A765F008A765F008A765F008A765F008A765F008A76
-      5F008A765F008A765F008A765F008A765F008A765F008A765F008A765F008A76
-      5F008A765F00454545000000000000000000000000005B5B5B008A765F008A76
-      5F00574B3C008A765F008A765F008A765F00574B3C008A765F008A765F008A76
-      5F00574B3C008A765F008A765F008A765F00574B3C008A765F008A765F008A76
-      5F00574B3C004545450000000000000000000000000000000000000000000000
-      00005A73730042635A0042635A0000000000000000005A73730042635A004263
-      5A0000000000000000005A73730042635A0042635A0000000000000000000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B0042635A0042635A0042635A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A000000000000000000000000005F5F5F008B7862008B78
-      62008B7862008B7862008B7862008B7862008B7862008B7862008B786200584C
-      3E008B7862008B7862008B7862008B7862008B7862008B7862008B7862008B78
-      6200584C3E00484848000000000000000000000000005F5F5F008B786200FFFF
-      FF008B7862008B7862008B786200FFFFFF008B7862008B7862008B786200FFFF
-      FF008B7862008B7862008B786200FFFFFF008B7862008B7862008B786200FFFF
-      FF008B7862004848480000000000000000000000000000000000000000000000
-      0000000000006B8484005A73730042635A0000000000000000006B8484005A73
-      730042635A0000000000000000006B8484005A73730042635A00000000000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B0042635A0042635A0042635A006B8484005A7373005A73
-      73005A7373005A7373005A7373005A7373005A7373005A7373005A7373005A73
-      73005A73730042635A00000000000000000000000000656565008E7C66008E7C
-      66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C6600FFFFFF008E7C
-      66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C6600FFFF
-      FF008E7C66004C4C4C00000000000000000000000000656565008E7C66008E7C
-      66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C
-      66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C66008E7C
-      66008E7C66004C4C4C0000000000000000000000000000000000000000000000
-      000000000000000000006B8484005A73730042635A0000000000000000006B84
-      84005A73730042635A0000000000000000006B8484005A73730042635A000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B0042635A0042635A0042635A006B8484006B8484006B84
-      84006B8484006B8484006B8484006B8484006B8484006B8484006B8484006B84
-      84006B8484005A73730000000000000000000000000068686800917F6B00917F
-      6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F
-      6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F
-      6B00917F6B005252520000000000000000000000000068686800917F6B00917F
-      6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F
-      6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F6B00917F
-      6B00917F6B005252520000000000000000000000000000000000000000000000
-      00000000000000000000000000006B8484005A73730042635A00000000000000
-      00006B8484005A73730042635A0000000000000000006B8484005A7373004263
-      5A0000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B0042635A0042635A0042635A0042635A0042635A004263
-      5A0042635A0042635A0042635A0042635A0042635A00294A4A00000000000000
-      000000000000000000000000000000000000000000006C6C6C0093846F009384
-      6F005D53460093846F0093846F0093846F005D53460093846F0093846F009384
-      6F0093846F0093846F0093846F0093846F0093846F0093846F0093846F009384
-      6F0093846F00555555000000000000000000000000006C6C6C0093846F009384
-      6F005D53460093846F0093846F0093846F005D53460093846F0093846F009384
-      6F005D53460093846F0093846F0093846F005D53460093846F0093846F009384
-      6F005D5346005555550000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000005A7373005A7373006B8484000000
-      0000000000005A7373005A7373006B84840000000000000000005A7373005A73
-      73006B848400000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B0042635A0042635A0042635A0042635A0042635A004263
-      5A0042635A0042635A0042635A0042635A0042635A00294A4A00000000000000
-      0000000000000000000000000000000000000000000071717100998C7900FFFF
-      FF00978875009788750097887500FFFFFF009788750097887500978875009788
-      7500978875009788750097887500978875009788750097887500978875009788
-      7500978875005858580000000000000000000000000071717100998C7900FFFF
-      FF00978875009788750097887500FFFFFF00978875009788750097887500FFFF
-      FF00978875009788750097887500FFFFFF00978875009788750097887500FFFF
-      FF00978875005858580000000000000000000000000000000000000000000000
-      000000000000000000000000000042635A005A7373006B848400000000000000
-      000042635A005A7373006B848400000000000000000042635A005A7373006B84
-      840000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B0042635A0042635A0042635A0042635A0042635A004263
-      5A0042635A0042635A0042635A0042635A0042635A00294A4A00000000000000
-      00000000000000000000000000000000000000000000757575009A8D7A009A8D
-      7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D
-      7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D
-      7A009A8D7A005B5B5B00000000000000000000000000757575009A8D7A009A8D
-      7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D
-      7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D7A009A8D
-      7A009A8D7A005B5B5B0000000000000000000000000000000000000000000000
-      0000000000000000000042635A005A7373006B84840000000000000000004263
-      5A005A7373006B848400000000000000000042635A005A7373006B8484000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD005A736B005A736B005A736B005A736B005A736B005A736B005A73
-      6B005A736B005A736B005A736B005A736B005A736B0042635A00000000000000
-      00000000000000000000000000000000000000000000787878009D9280009D92
-      80009D9280009D9280009D9280009D9280009D9280009D9280009D9280009D92
-      80009D9280009D9280009D9280009D9280009D9280009D9280009D9280009D92
-      80009D9280005E5E5E00000000000000000000000000787878009D9280009D92
-      80009D9280009D9280009D9280009D9280009D9280009D9280009D9280009D92
-      80009D9280009D9280009D9280009D9280009D9280009D9280009D9280009D92
-      80009D9280005E5E5E0000000000000000000000000000000000000000000000
-      00000000000042635A005A7373006B848400000000000000000042635A005A73
-      73006B848400000000000000000042635A005A7373006B848400000000000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD003139AD003139AD003139AD003139AD003139AD003139AD003139
-      AD003139AD0010219C0000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007D7D7D00A1978500A197
-      8500665F5400A1978500A1978500A1978500665F5400A1978500A1978500A197
-      8500A1978500A1978500A1978500A1978500A1978500A1978500A1978500A197
-      8500A1978500616161000000000000000000000000007D7D7D00A1978500A197
-      8500665F5400A1978500A1978500A1978500665F5400A1978500A1978500A197
-      8500665F5400A1978500A1978500A1978500665F5400A1978500A1978500A197
-      8500665F54006161610000000000000000000000000000000000000000000000
-      00006B8484006B8484006B84840000000000000000006B8484006B8484006B84
-      840000000000000000006B8484006B8484006B84840000000000000000000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD003139AD003139AD003139AD003139AD003139AD003139AD003139
-      AD003139AD0010219C0000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007E7E7E00A59C8C00FFFF
-      FF00A59C8C00A59C8C00A59C8C00FFFFFF00A59C8C00A59C8C00A59C8C00A59C
-      8C00A59C8C00A59C8C00A59C8C00A59C8C00A59C8C00A59C8C00A59C8C00A59C
-      8C00A59C8C00686868000000000000000000000000007E7E7E00A59C8C00FFFF
-      FF00A59C8C00A59C8C00A59C8C00FFFFFF00A59C8C00A59C8C00A59C8C00FFFF
-      FF00A59C8C00A59C8C00A59C8C00FFFFFF00A59C8C00A59C8C00A59C8C00FFFF
-      FF00A59C8C006868680000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004A5AB5003139AD003139
-      AD003139AD003139AD003139AD003139AD003139AD003139AD003139AD003139
-      AD003139AD0010219C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000082828200A8A19100A8A1
-      9100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A1
-      9100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A1
-      9100A8A191007777770000000000000000000000000082828200A8A19100A8A1
-      9100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A1
-      9100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A19100A8A1
-      9100A8A191007777770000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000004A5AB5004A5AB5004A5A
-      B5004A5AB5004A5AB5004A5AB5004A5AB5004A5AB5004A5AB5004A5AB5004A5A
-      B5004A5AB5003139AD0000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C000000000000000000000000008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D9C008D9D
-      9C008D9D9C008D9D9C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000006B6B
-      6B00292929002121210018181800181818001818180018181800181818001818
-      1800181818001818180018181800181818001818180018181800181818004A4A
-      4A0000000000000000000000000000000000000000000000000042424A004242
-      4A0042424A0042424A0042424A0042424A0042424A0042424A0042424A004242
-      4A0042424A0042424A0042424A0042424A0042424A0042424A0042424A000000
-      0000000000000000000000000000000000000000000000000000292929002121
-      2100181818001818180018181800181818001818180018181800181818001818
-      1800181818001818180018181800181818001818180029292900292929002121
-      2100212121000000000000000000000000000000000084848400848484008484
-      8400848484008484840084848400848484008484840084848400848484008484
-      8400848484008484840084848400848484008484840084848400848484008484
-      8400848484008484840000000000000000000000000000000000000000004242
-      4200FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002929
-      29000000000000000000000000000000000000000000313131004A4A4A007B94
-      8C007B948C007B948C007B948C007B948C007B948C007B948C007B948C007B94
-      8C007B948C007B948C007B948C007B948C007B948C0094ADAD008CA5A5008CA5
-      A5000000000000000000000000000000000000000000393939007B9494007B94
-      940063636300738C8C00E7E7E700FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00F7F7F700E7E7E700E7E7E700D6D6D6006B8C84005A5A5A007B94
-      94007B9494002929290000000000000000000000000084848400FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000
-      0000000000008484840000000000000000000000000000000000000000004242
-      4200FFFFFF00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DE
-      DE00C6DEDE00C6DEDE00C6DEDE00C6E7DE00C6DEDE00C6E7DE00FFFFFF003131
-      31000000000000000000000000000000000000000000313131004A4A4A008CA5
-      A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5
-      A5008CA5A5008CA5A50094ADAD008CA5A50094ADAD008CA5A5009CBDB5008CA5
-      A5000000000000000000000000000000000000000000424242007B9494007B94
-      94006B6B6B008CA59C00FFFFFF00E7E7E7009CB5AD00A5BDB500FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00EFEFEF00EFEFEF00E7E7E70094ADA5006B6B6B007B94
-      94007B9494002929290000000000000000000000000084848400FFFFFF008C00
-      00008C0000008C0000008C0000008C0000008C0000008C0000008C0000008C00
-      00008C0000008C0000008C000000FFFFFF00000000000000000000000000C6C6
-      C600C6C6C6008484840000000000000000000000000000000000000000004A4A
-      4A00FFFFFF00BDDED600BDDED600BDDED600BDDED600BDDED600BDDED600BDDE
-      D600BDDED600BDDED600BDDED600BDDED600BDDED600CEE7E700FFFFFF003131
-      31000000000000000000000000000000000000000000313139004A4A4A007B94
-      8C0094ADA50094ADA50094ADA50094ADA50094ADA50094ADA50094ADA50094AD
-      A50094ADA50094ADA50094ADA5009CB5AD0094ADAD009CB5B5009CBDB5008CA5
-      A5000000000000000000000000000000000000000000424242007B9C94007B9C
-      94006B6B6B008CADA500FFFFFF006B847B00738C8C0094ADA500FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00F7F7F70094ADAD006B6B6B007B9C
-      94007B9C94003131310000000000000000000000000084848400FFFFFF00A500
-      0000A5000000A5000000A5000000A5000000A5000000A5000000A5000000A500
-      0000A5000000A5000000A5000000FFFFFF000000000000000000000000000000
-      0000000000008484840000000000000000000000000000000000000000004A4A
-      4A00FFFFFF00BDDED600BDDED600BDDED600BDDED600BDDED600BDDED600BDDE
-      D600BDDED600BDDED600BDDED600BDDED600BDDED600CEE7E700FFFFFF003131
-      3100000000000000000000000000000000000000000039393900525252004A4A
-      520094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094ADAD0094AD
-      AD0094ADAD0094ADAD0094ADAD0094ADAD00A5BDB5009CB5B5009CB5B500A5C6
-      BD008CA5A500000000000000000000000000000000004A4A4A00849C9C007B9C
-      94007373730094ADAD00FFFFFF0052736B0073948C0094ADAD00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0094ADAD006B6B6B007B9C
-      94007B9C94003131310000000000000000000000000084848400FFFFFF00BD00
-      0000BD000000BD000000BD000000BD000000BD000000BD000000BD000000BD00
-      0000BD000000BD000000BD000000FFFFFF000000000000000000000000000000
-      0000000000008484840000000000000000000000000000000000000000004A4A
-      4A00FFFFFF00C6DED600C6DED600C6DED600C6DED600C6DED600C6DED600C6DE
-      D600C6DED600C6DED600C6DED600C6DED600C6DED600D6EFE700FFFFFF003939
-      3900000000000000000000000000000000000000000042424200525252005252
-      52009CB5AD009CB5AD009CB5AD009CB5AD009CB5AD009CB5AD009CB5AD009CB5
-      AD009CB5AD009CB5AD009CB5AD00A5BDB5009CB5B500A5BDBD00ADCEC600ADC6
-      C6008CA5A500000000000000000000000000000000004A4A4A0094ADA5008CA5
-      A5007B7B7B009CB5B500FFFFFF005A736B006B8C84008CA5A500FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009CB5B5006B6B6B00849C
-      9C00849C9C003939390000000000000000000000000084848400FFFFFF00D600
-      0000D6000000D6000000D6000000D6000000D6000000D6000000D6000000D600
-      0000D6000000D6000000D6000000FFFFFF00000000000000000000000000C6C6
-      C600C6C6C6008484840000000000000000000000000000000000000000004A4A
-      4A00FFFFFF00C6DED600C6DED600C6DED600C6DED600C6DED600C6DED600C6DE
-      D600C6DED600C6DED600C6DED600C6DED600C6DED600D6EFE700FFFFFF003939
-      39000000000000000000000000000000000000000000424242005A5A5A005252
-      52007B948C00A5BDB500A5BDB500A5BDB500A5BDB500A5BDB500A5BDB500A5BD
-      B500A5BDB500A5BDB500A5BDB500A5BDB500ADC6BD00A5BDBD00ADC6BD00ADCE
-      C6008CA5A500000000000000000000000000000000004A4A4A0094ADA5008CA5
-      A5007B7B7B009CB5B500FFFFFF005A736B006B8C84008CA5A500FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009CB5B5006B6B6B00849C
-      9C00849C9C003939390000000000000000000000000084848400FFFFFF00EF00
-      0000EF000000EF000000EF000000EF000000EF000000EF000000EF000000EF00
-      0000EF000000EF000000EF000000FFFFFF000000000000000000000000000000
-      0000000000008484840000000000000000000000000000000000000000004A4A
-      4A00FFFFFF00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DE
-      DE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00D6EFEF00FFFFFF003939
-      390000000000000000000000000000000000000000004A4A4A005A6363006363
-      63005A525A00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BD
-      BD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00A5BDBD00B5CEC600BDD6D600B5CE
-      CE008CA5A50000000000000000000000000000000000525252009CB5B5009CB5
-      AD009C9C9C00B5CECE00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0094ADA5007B7B7B00849C
-      9C00849C9C003939390000000000000000000000000084848400FFFFFF00FF00
-      0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00
-      0000FF000000FF000000FF000000FFFFFF000000000000000000000000000000
-      0000000000008484840000000000000000000000000000000000000000005252
-      5200FFFFFF00C6E7DE00C6E7DE00C6E7DE00C6E7DE00C6E7DE00C6E7DE00C6E7
-      DE00C6E7DE00C6E7DE00C6E7DE00C6E7DE00C6E7DE00D6F7EF00FFFFFF003939
-      3900000000000000000000000000000000000000000052525200636363006363
-      63005A5A5A00ADC6C600ADC6BD00ADC6BD00ADC6BD00ADC6BD00ADC6BD00ADC6
-      C600ADC6BD00ADC6BD00ADC6BD00ADC6BD00B5CECE00ADC6C600B5D6CE00C6DE
-      DE00BDD6D6008CA5A50000000000000000000000000052525200A5BDB500A5BD
-      B500A5BDB5009CB5B50094B5AD008CADA5008CA5A5008CA5A5008CA5A5008CA5
-      A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5A5008CA5
-      A5008CA5A5004242420000000000000000000000000084848400FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF000000FF00
-      0000FF000000FF000000FF000000FFFFFF00000000000000000000000000C6C6
-      C600C6C6C6008484840000000000000000000000000000000000000000005A5A
-      5A00FFFFFF00CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7
-      E700CEE7E700CEE7E700CEE7E700CEE7E700CEE7E700DEF7F700FFFFFF004242
-      42000000000000000000000000000000000000000000525252006B6B6B006B6B
-      6B005A5A5A007B948C00B5CEC600B5CEC600B5CEC600B5CEC600B5CEC600B5CE
-      C600B5CEC600B5CEC600B5CEC600B5CEC600B5CEC600BDD6D600BDD6CE00BDD6
-      D600C6DED6008CA5A5000000000000000000000000005A5A5A00A5C6BD008CA5
-      9C008CA5A5008CA5A500849C9C007B948C00738C8400738C8400738C8400738C
-      8400738C8400738C8400738C8C00738C8C00738C8C00738C8C00738C8C006B84
-      84008CADA5004242420000000000000000000000000084848400000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000008484840000000000000000000000000000000000000000005A5A
-      5A00FFFFFF00D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700D6EF
-      E700D6EFE700D6EFE700D6EFE700D6EFE700D6EFE700DEF7F700FFFFFF004242
-      420000000000000000000000000000000000000000005A5A5A00737373007373
-      73007373730063636300B5CECE00B5CECE00B5CECE00B5CECE00B5CECE00B5CE
-      CE00B5CECE00B5CECE00B5CECE00B5CECE00B5CECE00B5CECE00B5CECE00BDD6
-      D600C6DED6008CA5A5000000000000000000000000005A5A5A00ADC6BD0094AD
-      A500E7E7E700F7F7F700F7F7F700F7F7F700EFEFEF00EFEFEF00EFEFEF00EFEF
-      EF00EFEFEF00EFEFEF00EFEFEF00EFEFEF00F7F7F700EFEFEF00DEDEDE007394
-      8C0094ADAD004A4A4A0000000000000000000000000084848400080808000808
-      0800080808000808080008080800080808000808080008080800080808000808
-      0800080808000808080008080800080808000808080008080800080808000808
-      0800080808008484840000000000000000000000000000000000000000006363
-      6300FFFFFF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EF
-      EF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00D6EFEF00DEF7F700FFFFFF004A4A
-      4A000000000000000000000000000000000000000000636363007B7373007373
-      730073737300636363007B948C00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DE
-      DE00BDD6D600BDD6D600BDD6D600BDD6D600BDD6D600BDD6D600BDD6D600CEE7
-      DE00BDD6D6008CA5A50000000000000000000000000063636300ADC6C60094AD
-      AD00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00F7F7F7007B94
-      940094ADAD004A4A4A0000000000000000000000000084848400081010000810
-      1000081010000810100008101000081010000810100008101000081010000810
-      100008101000081010000810100008101000081010000810100008101000BDC6
-      C600BDC6C6008484840000000000000000000000000000000000000000006363
-      6300FFFFFF00D6F7EF00D6F7EF00D6F7EF00D6F7EF00D6F7EF00D6F7EF00D6F7
-      EF00D6F7EF00D6F7EF00D6F7EF00D6F7EF00D6F7EF00DEFFF700FFFFFF004A4A
-      4A000000000000000000000000000000000000000000636363007B7B7B007B7B
-      7B007B7B7B007373730063636300636363006363630063636300636363006363
-      63007B948C00C6DED600C6DED600C6DED600C6DED600C6DED600C6DED600C6DE
-      D600CEE7E700BDD6D6008CA5A50000000000000000006B6B6B00ADCEC6009CB5
-      AD00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00F7F7F7007B9C
-      94009CB5B5005252520000000000000000000000000084848400101810001018
-      1000101810001018100010181000101810001018100010181000101810001018
-      1000101810001018100010181000101810001018100010181000101810001018
-      1000101810008484840000000000000000000000000000000000000000006B6B
-      6B00FFFFFF00DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7
-      F700DEF7F700DEF7F700DEF7F700CEEFE700C6DEDE00C6DEDE00DEDEDE005252
-      520000000000000000000000000000000000000000006B6B6B00848484008484
-      8400848484008484840084848400848484008484840084848400848484008484
-      84006B6B6300C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DEDE00C6DE
-      DE00C6DEDE00D6EFE7008CA5A50000000000000000006B6B6B00B5CEC6009CB5
-      B500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00849C
-      94009CBDB5005252520000000000000000000000000084848400182118001821
-      1800182118001821180018211800182118001821180018211800182118001821
-      1800182118001821180018211800182118001821180018211800182118001821
-      1800182118008484840000000000000000000000000000000000000000006B6B
-      6B00FFFFFF00DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7
-      F700DEF7F700F7F7F700D6D6D600C6C6C600B5B5B500ADADAD009C9C9C005252
-      5200000000000000000000000000000000000000000073737300848484008484
-      8400848484008484840084848400848484008484840084848400848484008484
-      8400848484006B6B6300E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700E7FF
-      F700F7FFFF00EFFFFF008CA5A500000000000000000073737300B5D6CE00A5BD
-      B500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00849C
-      9C00A5BDB5005A5A5A00000000000000000000000000848C8400DEE7E700DEE7
-      E700DEE7E700DEE7E700DEE7E700DEE7E700DEE7E700DEE7E700DEE7E700DEE7
-      E70021292900212929002129290021292900212929002129290021292900B5BD
-      B500B5BDB500848C840000000000000000000000000000000000000000006B6B
-      6B00FFFFFF00DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7F700DEF7
-      F700DEF7F700F7F7F700949494008C8C8C0073737300737373005A5A5A005A5A
-      5A000000000000000000000000000000000000000000737373008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C006B6B6B006B6B6B006B6B6B006B6B6B006B6B6B006B6B
-      6B006B6B6B006B6B6B0000000000000000000000000073737300C6DED600A5BD
-      B500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00849C
-      9C00A5C6BD005A5A5A00000000000000000000000000848C8C00293131002931
-      310029313100293131002931310029313100293131002931310029313100D6DE
-      DE00293131002931310029313100293131002931310029313100293131002931
-      310029313100848C8C0000000000000000000000000000000000000000006B6B
-      6B00FFFFFF00E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700E7FF
-      F700E7FFF700F7F7F700A5A5A500FFFFFF00FFFFFF00FFFFFF00FFFFFF005A5A
-      5A0000000000000000000000000000000000000000007B7B7B00948C8C00948C
-      94008C8C8C008C948C008C8C94008C948C008C9494007B7B7B007B7B7B007B7B
-      7B007B7B7B007B7B7B007B7B7B007B7B7B007B7B7B007B7B7B007B7B7B000000
-      000000000000000000000000000000000000000000007B7B7B00CEE7DE00A5BD
-      B500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008CA5
-      A500ADC6C6005A5A5A00000000000000000000000000848C8C00313939003139
-      390031393900313939003139390031393900313939003139390031393900CED6
-      D600313939003139390031393900313939003139390031393900313939003139
-      390031393900848C8C0000000000000000000000000000000000000000006B6B
-      6B00FFFFFF00E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700E7FFF700E7FF
-      F700E7FFF700F7F7F700B5B5B500FFFFFF00D6F7EF00D6F7EF00B5D6CE006B6B
-      6B00000000000000000000000000000000000000000084848400949494009494
-      9400949494009494940094949400949494009494940084848400000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007B7B7B00D6EFE700A5BD
-      B500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0094AD
-      AD00ADC6C600636363000000000000000000000000007B8C8C00394242003942
-      4200394242003942420039424200394242003942420039424200394242003942
-      420039424200394242003942420039424200394242003942420039424200A5AD
-      AD00A5ADAD007B8C8C0000000000000000000000000000000000000000006B6B
-      6B00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00C6C6C600FFFFFF00D6F7EF00B5D6CE006B6B6B000000
-      00000000000000000000000000000000000000000000848484009C9C9C009C9C
-      9C009C9C9C009C9C9C009C9C9C009C9C9C009C9C9C0084848400000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000000000007B7B7B00D6F7EF00A5BD
-      B500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0094AD
-      A500ADCEC6006B6B6B000000000000000000000000007B8C8C00424A4A00424A
-      4A00424A4A00424A4A00424A4A00424A4A00424A4A00424A4A00424A4A00424A
-      4A00424A4A00424A4A00424A4A00424A4A00424A4A00424A4A00424A4A00424A
-      4A00424A4A007B8C8C0000000000000000000000000000000000000000006B6B
-      6B00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00CECECE00FFFFFF00B5D6CE0073737300000000000000
-      0000000000000000000000000000000000000000000000000000848484008484
-      8400848484008484840084848400848484008484840000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000084848400DEF7F700A5BD
-      B500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
-      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00F7F7F7009CB5
-      AD00B5CECE00737373000000000000000000000000007B8C8C004A5A52004A5A
-      52004A5A52004A5A52004A5A52004A5A52004A5A52004A5A52004A5A52004A5A
-      52004A5A52004A5A52004A5A52004A5A52004A5A52004A5A52004A5A52004A5A
-      52004A5A52007B8C8C0000000000000000000000000000000000000000007373
-      73007373730073737300737373007B7B7B007B7B7B0084848400848484008484
-      8400848484008484840084848400848484008484840000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000848484008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C8C008C8C
-      8C0084848400000000000000000000000000000000007B8C8C007B8C8C007B8C
-      8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C
-      8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C8C007B8C
-      8C007B8C8C007B8C8C0000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      000000000000000000000000000000000000424D3E000000000000003E000000
-      2800000060000000600000000100010000000000800400000000000000000000
-      000000000000000000000000FFFFFF0000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
-      00000000000000000000000000000000FFFFFF000000000000000000FFFFFF00
-      0000000000000000800003000000000000000000800003000000000000000000
-      8000030000000000000000008000030000000000000000008000030000000000
-      0000000080000300000000000000000080000300000000000000000080000300
-      0000000000000000800003000000000000000000800003000000000000000000
-      8000030000000000000000008000030000000000000000008000030000000000
-      0000000080000300000000000000000080000300000000000000000080000300
-      0000000000000000800003000000000000000000800003000000000000000000
-      8000030000000000000000008000030000000000000000008000030000000000
-      00000000FFFFFF000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-      FFFFFFFFFFFFFFFFFF8003800003800003FFFFFFFF8003800003800003FFFFFF
-      FF8003800003800003E610CFFF8003800003800003E67CCFF800038000038000
-      03E630CFF80003800003800003E673CFF80003800003800003C21087F8000380
-      0003800003FFFFFF800003800003800003FFFFFF800003800003800003F18C7F
-      800003800003800003F8C63F800003800003800003FC631F8000038000038000
-      03FE318F80003F800003800003FF18C780003F800003800003FE318F80003F80
-      0003800003FC631F80003F800003800003F8C63F8003FF800003800003F18C7F
-      8003FF800003800003FFFFFF8003FF800003800003FFFFFF8003FF8000038000
-      03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-      FFFFFFFFFFFFFFFFE0000FC0001FC00007800003E0000F80000F800003800003
-      E0000F80000F800003800003E0000F80000F800003800003E0000F8000078000
-      03800003E0000F800007800003800003E0000F800007800003800003E0000F80
-      0007800003800003E0000F800003800003800003E0000F800003800003800003
-      E0000F800003800003800003E0000F800003800003800003E0000F8000018000
-      03800003E0000F800001800003800003E0000F800001800003800003E0000F80
-      0003800003800003E0000F80001F800003800003E0000F803FFF800003800003
-      E0001F803FFF800003800003E0003FC07FFF800003800003E0007FFFFFFFC000
-      07800003FFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000
-      000000000000}
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000
+    }
   end
   object pmMapTest: TPopupMenu
-    Left = 160
-    Top = 64
+    left = 160
+    top = 64
     object miMapTestPMSet: TMenuItem
       Caption = 'Параметры'
       OnClick = miMapTestSettingsClick
     end
   end
   object ColorDialog: TColorDialog
-    Left = 64
-    Top = 146
+    Color = clBlack
+    CustomColors.Strings = (
+      'ColorA=000000'
+      'ColorB=000080'
+      'ColorC=008000'
+      'ColorD=008080'
+      'ColorE=800000'
+      'ColorF=800080'
+      'ColorG=808000'
+      'ColorH=808080'
+      'ColorI=C0C0C0'
+      'ColorJ=0000FF'
+      'ColorK=00FF00'
+      'ColorL=00FFFF'
+      'ColorM=FF0000'
+      'ColorN=FF00FF'
+      'ColorO=FFFF00'
+      'ColorP=FFFFFF'
+      'ColorQ=C0DCC0'
+      'ColorR=F0CAA6'
+      'ColorS=F0FBFF'
+      'ColorT=A4A0A0'
+    )
+    left = 64
+    top = 146
   end
 end
index d3193006eebd27184d3b0bc384de61a50d60962e..9167af7bd3a34d88085e7006fc671d0d9ac12ec7 100644 (file)
@@ -8,10 +8,14 @@ uses
   LCLIntf, LCLType, LMessages, SysUtils, Variants, Classes, Graphics,
   Controls, Forms, Dialogs, ImgList, StdCtrls, Buttons,
   ComCtrls, ValEdit, Types, ToolWin, Menus, ExtCtrls,
-  CheckLst, Grids;
+  CheckLst, Grids, OpenGLContext;
 
 type
+
+  { TMainForm }
+
   TMainForm = class(TForm)
+    lLoad: TLabel;
   // Главное меню:
     MainMenu: TMainMenu;
   // "Файл":
@@ -77,6 +81,9 @@ type
 
   // Панель инструментов:
     MainToolBar: TToolBar;
+    pbLoad: TProgressBar;
+    pLoadProgress: TPanel;
+    RenderPanel: TOpenGLControl;
     tbNewMap: TToolButton;
     tbOpenMap: TToolButton;
     tbSaveMap: TToolButton;
@@ -107,12 +114,6 @@ type
 
   // Панель карты:
     PanelMap: TPanel;
-  // Панель отображения карты:
-    RenderPanel: TPanel;
-  // Панель загрузки:
-    pLoadProgress: TPanel;
-    lLoad: TLabel;
-    pbLoad: TProgressBar;
   // Полосы прокрутки:
     sbHorizontal: TScrollBar;
     sbVertical: TScrollBar;
@@ -209,6 +210,7 @@ type
     procedure RenderPanelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
     procedure RenderPanelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+    procedure RenderPanelPaint(Sender: TObject);
     procedure RenderPanelResize(Sender: TObject);
     procedure vleObjectPropertyEditButtonClick(Sender: TObject);
     procedure vleObjectPropertyGetPickList(Sender: TObject; const KeyName: String; Values: TStrings);
@@ -321,14 +323,14 @@ procedure ChangeShownProperty(Name: String; NewValue: String);
 implementation
 
 uses
-  f_options, e_graphics, e_log, dglOpenGL, Math,
+  f_options, e_graphics, e_log, GL, GLExt, Math,
   f_mapoptions, g_basic, f_about, f_mapoptimization,
   f_mapcheck, f_addresource_texture, g_textures,
   f_activationtype, f_keys, MAPWRITER, MAPSTRUCT,
-  MAPREADER, f_selectmap, f_savemap, WADEDITOR, MAPDEF,
+  MAPREADER, f_selectmap, f_savemap, WADEDITOR, WADSTRUCT, MAPDEF,
   g_map, f_saveminimap, f_addresource, CONFIG, f_packmap,
   f_addresource_sound, f_maptest, f_choosetype,
-  g_language, f_selectlang, ClipBrd, Windows;
+  g_language, f_selectlang, ClipBrd;
 
 const
   UNDO_DELETE_PANEL   = 1;
@@ -419,9 +421,8 @@ type
   TCopyRecArray = Array of TCopyRec;
 
 var
-  hDC: THandle;
-  hRC: THandle;
   gEditorFont: DWORD;
+  gDataLoaded: Boolean = False;
   ShowMap: Boolean = False;
   DrawRect: PRect = nil;
   SnapToGrid: Boolean = True;
@@ -1869,7 +1870,7 @@ end;
 
 function AddTexture(aWAD, aSection, aTex: String; silent: Boolean): Boolean;
 var
-  a: Integer;
+  a, FrameLen: Integer;
   ok: Boolean;
   FileName: String;
   ResourceName: String;
@@ -1940,9 +1941,9 @@ begin
 
     if IsAnim(FullResourceName) then
       begin // Аним. текстура
-        GetFrame(FullResourceName, Data, Width, Height);
+        GetFrame(FullResourceName, Data, FrameLen, Width, Height);
 
-        if g_CreateTextureMemorySize(Data, ResourceName, 0, 0, Width, Height, 1) then
+        if g_CreateTextureMemorySize(Data, FrameLen, ResourceName, 0, 0, Width, Height, 1) then
           a := MainForm.lbTextureList.Items.Add(ResourceName);
       end
     else // Обычная текстура
@@ -2520,51 +2521,57 @@ begin
   OptionsForm.ShowModal();
 end;
 
-procedure TMainForm.FormCreate(Sender: TObject);
+procedure LoadStdFont(cfgres, texture: string; var FontID: DWORD);
 var
-  PixelFormat: GLuint;
-  pfd: TPIXELFORMATDESCRIPTOR;
+  cwdt, chgt: Byte;
+  spc: ShortInt;
+  ID: DWORD;
+  wad: TWADEditor_1;
+  cfgdata: Pointer;
+  cfglen: Integer;
   config: TConfig;
-  i: Integer;
-  s: String;
 begin
-  Randomize();
+  cfglen := 0;
 
-  EditorDir := ExtractFilePath(Application.ExeName);
+  wad := TWADEditor_1.Create;
+  if wad.ReadFile(EditorDir+'data\Game.wad') then
+    wad.GetResource('FONTS', cfgres, cfgdata, cfglen);
+  wad.Free();
 
-  e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
+  if cfglen <> 0 then
+  begin
+    if not g_CreateTextureWAD('FONT_STD', EditorDir+'data\Game.wad:FONTS\'+texture) then
+      e_WriteLog('ERROR ERROR ERROR', MSG_WARNING);
 
-  e_WriteLog('Init OpenGL', MSG_NOTIFY);
+    config := TConfig.CreateMem(cfgdata, cfglen);
+    cwdt := Min(Max(config.ReadInt('FontMap', 'CharWidth', 0), 0), 255);
+    chgt := Min(Max(config.ReadInt('FontMap', 'CharHeight', 0), 0), 255);
+    spc := Min(Max(config.ReadInt('FontMap', 'Kerning', 0), -128), 127);
 
-  InitOpenGL();
-  hDC := GetDC(RenderPanel.Handle);
+    if g_GetTexture('FONT_STD', ID) then
+      e_TextureFontBuild(ID, FontID, cwdt, chgt, spc-2);
 
-  FillChar(pfd, SizeOf(pfd), 0);
-  with pfd do
-  begin
-    nSize := SizeOf(pfd);
-    nVersion := 1;
-    dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
-    dwLayerMask := PFD_MAIN_PLANE;
-    iPixelType := PFD_TYPE_RGBA;
-    cColorBits := 24;
-    cDepthBits := 32;
-    iLayerType := PFD_MAIN_PLANE;
-  end;
-  PixelFormat := ChoosePixelFormat (hDC, @pfd);
-  SetPixelFormat(hDC, PixelFormat, @pfd);
+    config.Free();
+  end
+  else
+    e_WriteLog('Could not load FONT_STD', MSG_WARNING);
 
-  hRC := wglCreateContext(hDC);
-  ActivateRenderingContext(hDC, hRC);
+  if cfglen <> 0 then FreeMem(cfgdata);
+end;
 
-  e_InitGL(False);
+procedure TMainForm.FormCreate(Sender: TObject);
+var
+  config: TConfig;
+  i: Integer;
+  s: String;
+begin
+  Randomize();
 
-  gEditorFont := e_SimpleFontCreate('Arial Cyr', 12, FW_BOLD, hDC);
+  EditorDir := ExtractFilePath(Application.ExeName);
 
-  slInvalidTextures := TStringList.Create;
+  e_InitLog(EditorDir+'Editor.log', WM_NEWFILE);
 
-  e_WriteLog('Loading data', MSG_NOTIFY);
-  LoadData();
+  slInvalidTextures := TStringList.Create;
 
   ShowLayer(LAYER_BACK, True);
   ShowLayer(LAYER_WALLS, True);
@@ -2657,9 +2664,14 @@ begin
   Application.OnIdle := OnIdle;
 end;
 
+procedure PrintBlack(X, Y: Integer; Text: string; FontID: DWORD);
+begin
+  // NOTE: all the font printing routines assume CP1251
+  e_TextureFontPrintEx(X, Y, Text, FontID, 0, 0, 0, 1.0);
+end;
+
 procedure TMainForm.Draw();
 var
-  ps: TPaintStruct;
   x, y: Integer;
   a, b: Integer;
   ID: DWORD;
@@ -2668,7 +2680,6 @@ var
   ObjCount: Word;
   aX, aY, aX2, aY2, XX, ScaleSz: Integer;
 begin
-  BeginPaint(Handle, ps);
   e_BeginRender();
 
   e_Clear(GL_COLOR_BUFFER_BIT,
@@ -2755,7 +2766,7 @@ begin
 
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_TELEPORT]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_TELEPORT], gEditorFont);
   end;
 
 // Подсказка при выборе точки появления:
@@ -2766,7 +2777,7 @@ begin
                0, 0, 255);
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_SPAWN]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_SPAWN], gEditorFont);
   end;
 
 // Подсказка при выборе панели двери:
@@ -2774,7 +2785,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_DOOR]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_DOOR], gEditorFont);
   end;
 
 // Подсказка при выборе панели с текстурой:
@@ -2782,7 +2793,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+196, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_TEXTURE]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_TEXTURE], gEditorFont);
   end;
 
 // Подсказка при выборе панели индикации выстрела:
@@ -2790,7 +2801,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+316, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_SHOT]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_SHOT], gEditorFont);
   end;
 
 // Подсказка при выборе панели лифта:
@@ -2798,7 +2809,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+180, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_PANEL_LIFT]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_PANEL_LIFT], gEditorFont);
   end;
 
 // Подсказка при выборе монстра:
@@ -2806,7 +2817,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+120, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_MONSTER]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_MONSTER], gEditorFont);
   end;
 
 // Подсказка при выборе области воздействия:
@@ -2814,7 +2825,7 @@ begin
   begin
     e_DrawFillQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 192, 192, 192, 127);
     e_DrawQuad(MousePos.X, MousePos.Y, MousePos.X+204, MousePos.Y+18, 255, 255, 255);
-    e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(_lc[I_HINT_EXT_AREA]), gEditorFont, 0, 0, 0);
+    PrintBlack(MousePos.X+2, MousePos.Y+2, _glc[I_HINT_EXT_AREA], gEditorFont);
   end;
 
 // Рисуем текстуры, если чертим панель:
@@ -2844,10 +2855,10 @@ begin
 
     if MouseAction in [MOUSEACTION_DRAWPANEL, MOUSEACTION_DRAWTRIGGER] then
       begin // Чертим новый
-        e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(Format(_lc[I_HINT_WIDTH],
-                          [Abs(MousePos.X-MouseLDownPos.X)])), gEditorFont, 0, 0, 0);
-        e_SimpleFontPrint(MousePos.X+8, MousePos.Y+28, PChar(Format(_lc[I_HINT_HEIGHT],
-                          [Abs(MousePos.Y-MouseLDownPos.Y)])), gEditorFont, 0, 0, 0);
+        PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH],
+                          [Abs(MousePos.X-MouseLDownPos.X)]), gEditorFont);
+        PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT],
+                          [Abs(MousePos.Y-MouseLDownPos.Y)]), gEditorFont);
       end
     else // Растягиваем существующий
       if SelectedObjects[GetFirstSelected].ObjectType in [OBJECT_PANEL, OBJECT_TRIGGER] then
@@ -2863,10 +2874,10 @@ begin
             Height := gTriggers[SelectedObjects[GetFirstSelected].ID].Height;
           end;
 
-        e_SimpleFontPrint(MousePos.X+8, MousePos.Y+14, PChar(Format(_lc[I_HINT_WIDTH], [Width])),
-                          gEditorFont, 0, 0, 0);
-        e_SimpleFontPrint(MousePos.X+8, MousePos.Y+28, PChar(Format(_lc[I_HINT_HEIGHT], [Height])),
-                          gEditorFont, 0, 0, 0);
+        PrintBlack(MousePos.X+2, MousePos.Y+2, Format(_glc[I_HINT_WIDTH], [Width]),
+                          gEditorFont);
+        PrintBlack(MousePos.X+2, MousePos.Y+14, Format(_glc[I_HINT_HEIGHT], [Height]),
+                          gEditorFont);
       end;
   end;
 
@@ -2962,8 +2973,7 @@ begin
   end; // Мини-карта
 
   e_EndRender();
-  SwapBuffers(hDC);
-  EndPaint(Handle, ps);
+  RenderPanel.SwapBuffers();
 end;
 
 procedure TMainForm.FormResize(Sender: TObject);
@@ -3616,7 +3626,7 @@ begin
                   trigger.Key := Trigger.Key or KEY_BLUETEAM;
 
               // Параметры триггера:
-                ZeroMemory(@trigger.Data.Default[0], 128);
+                FillByte(trigger.Data.Default[0], 128, 0);
 
                 case trigger.TriggerType of
                 // Переключаемая панель:
@@ -3837,6 +3847,11 @@ begin
     end;
 end;
 
+procedure TMainForm.RenderPanelPaint(Sender: TObject);
+begin
+  Draw();
+end;
+
 procedure TMainForm.RenderPanelMouseMove(Sender: TObject;
   Shift: TShiftState; X, Y: Integer);
 var
@@ -3909,8 +3924,10 @@ begin
       begin
         if DrawRect = nil then
           New(DrawRect);
-        DrawRect.TopLeft := MouseRDownPos;
-        DrawRect.BottomRight := MousePos;
+        DrawRect.Top := MouseRDownPos.y;
+        DrawRect.Left := MouseRDownPos.x;
+        DrawRect.Bottom := MousePos.y;
+        DrawRect.Right := MousePos.x;
       end
     else
     // Двигаем выделенные объекты:
@@ -3959,8 +3976,10 @@ begin
       begin
         if DrawRect = nil then
           New(DrawRect);
-        DrawRect.TopLeft := MouseLDownPos;
-        DrawRect.BottomRight := MousePos;
+        DrawRect.Top := MouseLDownPos.y;
+        DrawRect.Left := MouseLDownPos.x;
+        DrawRect.Bottom := MousePos.y;
+        DrawRect.Right := MousePos.x;
       end
     else // Двигаем карту:
       if MouseAction = MOUSEACTION_MOVEMAP then
@@ -3983,7 +4002,7 @@ begin
   CanClose := MessageBox(0, PChar(_lc[I_MSG_EXIT_PROMT]),
                          PChar(_lc[I_MSG_EXIT]),
                          MB_ICONQUESTION or MB_YESNO or
-                         MB_TASKMODAL or MB_DEFBUTTON1) = idYes;
+                         MB_DEFBUTTON1) = idYes;
 end;
 
 procedure TMainForm.aExitExecute(Sender: TObject);
@@ -4023,8 +4042,6 @@ begin
   config.Free();
 
   slInvalidTextures.Free;
-
-  wglDeleteContext(hRC);
 end;
 
 procedure TMainForm.RenderPanelResize(Sender: TObject);
@@ -4632,9 +4649,9 @@ begin
             TRIGGER_EXIT:
               begin
                 s := vleObjectProperty.Values[_lc[I_PROP_TR_NEXT_MAP]];
-                ZeroMemory(@Data.MapName[0], 16);
+                FillByte(Data.MapName[0], 16, 0);
                 if s <> '' then
-                  CopyMemory(@Data.MapName[0], @s[1], Min(Length(s), 16));
+                  Move(Data.MapName[0], s[1], Min(Length(s), 16));
               end;
 
             TRIGGER_TEXTURE:
@@ -4671,9 +4688,9 @@ begin
             TRIGGER_SOUND:
               begin
                 s := vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_NAME]];
-                ZeroMemory(@Data.SoundName[0], 64);
+                FillByte(Data.SoundName[0], 64, 0);
                 if s <> '' then
-                  CopyMemory(@Data.SoundName[0], @s[1], Min(Length(s), 64));
+                  Move(Data.SoundName[0], s[1], Min(Length(s), 64));
 
                 Data.Volume := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_VOLUME]], 0), 255);
                 Data.Pan := Min(StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_SOUND_PAN]], 0), 255);
@@ -4725,9 +4742,9 @@ begin
             TRIGGER_MUSIC:
               begin
                 s := vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_NAME]];
-                ZeroMemory(@Data.MusicName[0], 64);
+                FillByte(Data.MusicName[0], 64, 0);
                 if s <> '' then
-                  CopyMemory(@Data.MusicName[0], @s[1], Min(Length(s), 64));
+                  Move(Data.MusicName[0], s[1], Min(Length(s), 64));
 
                 if vleObjectProperty.Values[_lc[I_PROP_TR_MUSIC_ACT]] = _lc[I_PROP_TR_MUSIC_ON] then
                   Data.MusicAction := 1
@@ -4785,9 +4802,9 @@ begin
                   Data.MessageSendTo := 5;
 
                 s := vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TEXT]];
-                ZeroMemory(@Data.MessageText[0], 100);
+                FillByte(Data.MessageText[0], 100, 0);
                 if s <> '' then
-                  CopyMemory(@Data.MessageText[0], @s[1], Min(Length(s), 100));
+                  Move(Data.MessageText[0], s[1], Min(Length(s), 100));
 
                 Data.MessageTime := Min(Max(
                   StrToIntDef(vleObjectProperty.Values[_lc[I_PROP_TR_MESSAGE_TIME]], 0), 0), 65535);
@@ -4915,7 +4932,7 @@ begin
                                 [SelectedTexture()])),
                 PChar(_lc[I_MSG_DEL_TEXTURE]),
                 MB_ICONQUESTION or MB_YESNO or
-                MB_TASKMODAL or MB_DEFBUTTON1) <> idYes then
+                MB_DEFBUTTON1) <> idYes then
     Exit;
 
   if gPanels <> nil then
@@ -4940,7 +4957,7 @@ begin
   if (MessageBox(0, PChar(_lc[I_MSG_CLEAR_MAP_PROMT]),
                  PChar(_lc[I_MSG_CLEAR_MAP]),
                  MB_ICONQUESTION or MB_YESNO or
-                 MB_TASKMODAL or MB_DEFBUTTON1) = mrYes) then
+                 MB_DEFBUTTON1) = mrYes) then
     FullClear();
 end;
 
@@ -5761,13 +5778,13 @@ begin
   begin
     str := SelectMapForm.lbMapList.Items[SelectMapForm.lbMapList.ItemIndex];
     MapName := '';
-    CopyMemory(@MapName[0], @str[1], Min(16, Length(str)));
+    Move(MapName[0], str[1], Min(16, Length(str)));
 
     if MessageBox(0, PChar(Format(_lc[I_MSG_DELETE_MAP_PROMT],
                            [MapName, OpenDialog.FileName])),
                   PChar(_lc[I_MSG_DELETE_MAP]),
                   MB_ICONQUESTION or MB_YESNO or
-                  MB_TASKMODAL or MB_DEFBUTTON2) <> mrYes then
+                  MB_DEFBUTTON2) <> mrYes then
       Exit;
 
     WAD.RemoveResource('', MapName);
@@ -5776,7 +5793,7 @@ begin
                                [MapName])),
                PChar(_lc[I_MSG_MAP_DELETED]),
                MB_ICONINFORMATION or MB_OK or
-               MB_TASKMODAL or MB_DEFBUTTON1);
+               MB_DEFBUTTON1);
 
     WAD.SaveTo(OpenDialog.FileName);
 
@@ -6014,6 +6031,17 @@ end;
 
 procedure TMainForm.OnIdle(Sender: TObject; var Done: Boolean);
 begin
+  // FIXME: this is a shitty hack
+  if not gDataLoaded then
+  begin
+    e_WriteLog('Init OpenGL', MSG_NOTIFY);
+    e_InitGL();
+    e_WriteLog('Loading data', MSG_NOTIFY);
+    LoadStdFont('STDTXT', 'STDFONT', gEditorFont);
+    LoadData();
+    gDataLoaded := True;
+    MainForm.FormResize(nil);
+  end;
   Draw();
 end;
 
@@ -6222,10 +6250,7 @@ begin
   Application.Minimize();
   if ExecuteProcess(TestD2dExe, cmd) < 0 then
   begin
-    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
-                  nil, GetLastError(), LANG_SYSTEM_DEFAULT,
-                  @lpMsgBuf, 0, nil);
-    MessageBox(0, lpMsgBuf,
+    MessageBox(0, 'FIXME',
                PChar(_lc[I_MSG_EXEC_ERROR]),
                MB_OK or MB_ICONERROR);
   end;
index 418547a9b35399e201b55c70217de5776512c3b2..f33a7b63f189b2e6dafe1756b7d93349b7cd849a 100644 (file)
 object MapOptionsForm: TMapOptionsForm
   Left = 594
+  Height = 350
   Top = 204
+  Width = 340
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
   Caption = 'Параметры карты'
   ClientHeight = 350
   ClientWidth = 340
   Color = clBtnFace
-  Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
   Font.Height = -11
   Font.Name = 'MS Sans Serif'
-  Font.Style = []
+  OnActivate = FormActivate
   Position = poScreenCenter
   ShowHint = True
-  OnActivate = FormActivate
-  PixelsPerInch = 96
+  LCLVersion = '1.6.0.4'
   object LabelDesc: TLabel
     Left = 3
+    Height = 13
     Top = 43
     Width = 87
-    Height = 13
     Caption = 'Описание карты:'
+    ParentColor = False
   end
   object lCharCountName: TLabel
     Left = 131
+    Height = 13
     Top = 3
     Width = 41
-    Height = 13
     Alignment = taRightJustify
     AutoSize = False
     Caption = '00\32'
+    ParentColor = False
   end
   object lCharCountDescription: TLabel
     Left = 131
+    Height = 13
     Top = 43
     Width = 41
-    Height = 13
     Alignment = taRightJustify
     AutoSize = False
     Caption = '000\256'
+    ParentColor = False
   end
   object LabelName: TLabel
     Left = 3
+    Height = 13
     Top = 3
     Width = 87
-    Height = 13
     Caption = 'Название карты:'
+    ParentColor = False
   end
   object LabelBack: TLabel
     Left = 3
+    Height = 13
     Top = 131
     Width = 26
-    Height = 13
     Caption = 'Фон:'
+    ParentColor = False
   end
   object LabelMusic: TLabel
     Left = 3
+    Height = 13
     Top = 171
     Width = 43
-    Height = 13
     Caption = 'Музыка:'
+    ParentColor = False
   end
   object LabelAuthor: TLabel
     Left = 3
+    Height = 13
     Top = 83
     Width = 33
-    Height = 13
     Caption = 'Автор:'
+    ParentColor = False
   end
   object lCharCountAuthor: TLabel
     Left = 131
+    Height = 13
     Top = 83
     Width = 41
-    Height = 13
     Alignment = taRightJustify
     AutoSize = False
     Caption = '00\32'
+    ParentColor = False
   end
   object GBStats: TGroupBox
     Left = 179
+    Height = 118
     Top = 3
     Width = 158
-    Height = 118
     Caption = 'Статистика:'
+    ClientHeight = 100
+    ClientWidth = 154
     TabOrder = 3
     object lPanelCount: TLabel
       Left = 80
+      Height = 13
       Top = 18
       Width = 64
-      Height = 13
       AutoSize = False
+      ParentColor = False
     end
     object lTextureCount: TLabel
       Left = 80
+      Height = 13
       Top = 2
       Width = 64
-      Height = 13
       AutoSize = False
+      ParentColor = False
     end
     object lItemCount: TLabel
       Left = 80
+      Height = 13
       Top = 34
       Width = 64
-      Height = 13
       AutoSize = False
+      ParentColor = False
     end
     object LabelPanels: TLabel
       Left = 6
+      Height = 13
       Top = 18
       Width = 47
-      Height = 13
       Caption = 'Панелей:'
+      ParentColor = False
     end
     object LabelTexs: TLabel
       Left = 6
+      Height = 13
       Top = 2
       Width = 44
-      Height = 13
       Caption = 'Текстур:'
+      ParentColor = False
     end
     object LabelItems: TLabel
       Left = 6
+      Height = 13
       Top = 34
       Width = 60
-      Height = 13
       Caption = 'Предметов:'
+      ParentColor = False
     end
     object LabelMonsters: TLabel
       Left = 6
+      Height = 13
       Top = 50
       Width = 53
-      Height = 13
       Caption = 'Монстров:'
+      ParentColor = False
     end
     object lMonsterCount: TLabel
       Left = 80
+      Height = 13
       Top = 50
       Width = 64
-      Height = 13
       AutoSize = False
+      ParentColor = False
     end
     object LabelAreas: TLabel
       Left = 6
+      Height = 13
       Top = 66
       Width = 52
-      Height = 13
       Caption = 'Областей:'
+      ParentColor = False
     end
     object lAreaCount: TLabel
       Left = 80
+      Height = 13
       Top = 66
       Width = 64
-      Height = 13
       AutoSize = False
+      ParentColor = False
     end
     object LabelTriggers: TLabel
       Left = 6
+      Height = 13
       Top = 82
       Width = 56
-      Height = 13
       Caption = 'Триггеров:'
+      ParentColor = False
     end
     object lTriggerCount: TLabel
       Left = 80
+      Height = 13
       Top = 82
       Width = 64
-      Height = 13
       AutoSize = False
+      ParentColor = False
     end
   end
   object bOK: TButton
     Left = 163
+    Height = 25
     Top = 323
     Width = 75
-    Height = 25
     Caption = 'ОК'
     Default = True
-    TabOrder = 11
     OnClick = bOKClick
+    TabOrder = 11
   end
   object bCancel: TButton
     Left = 251
+    Height = 25
     Top = 323
     Width = 75
-    Height = 25
     Cancel = True
     Caption = 'Отмена'
-    TabOrder = 12
     OnClick = bCancelClick
+    TabOrder = 12
   end
   object GBSizes: TGroupBox
     Left = 3
+    Height = 105
     Top = 216
     Width = 334
-    Height = 105
     Caption = 'Размеры:'
+    ClientHeight = 87
+    ClientWidth = 330
     TabOrder = 10
     object LabelWidth: TLabel
-      Left = 14
-      Top = 10
-      Width = 42
+      Left = 8
       Height = 13
+      Top = 3
+      Width = 42
       AutoSize = False
       Caption = 'Ширина:'
+      ParentColor = False
     end
     object LabelHeight: TLabel
-      Left = 14
-      Top = 36
-      Width = 41
+      Left = 8
       Height = 13
+      Top = 29
+      Width = 41
       AutoSize = False
       Caption = 'Высота:'
+      ParentColor = False
     end
     object LabelCurSize: TLabel
-      Left = 14
-      Top = 66
-      Width = 48
+      Left = 2
       Height = 13
+      Top = 56
+      Width = 48
       AutoSize = False
       Caption = 'Текущий:'
+      ParentColor = False
     end
     object lCurrentMapSizes: TLabel
-      Left = 67
-      Top = 66
-      Width = 68
+      Left = 56
       Height = 13
+      Top = 59
+      Width = 68
       AutoSize = False
+      ParentColor = False
     end
     object sbMoveCenter: TSpeedButton
-      Left = 262
-      Top = 26
-      Width = 25
+      Left = 280
       Height = 25
-      GroupIndex = 1
+      Top = 20
+      Width = 25
       Down = True
+      GroupIndex = 1
     end
     object sbMoveUpLeft: TSpeedButton
-      Left = 238
-      Top = 2
-      Width = 25
+      Left = 256
       Height = 25
-      GroupIndex = 1
+      Top = -4
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -268,14 +295,15 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object sbMoveUp: TSpeedButton
-      Left = 262
-      Top = 2
-      Width = 25
+      Left = 280
       Height = 25
-      GroupIndex = 1
+      Top = -4
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -302,14 +330,15 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object sbMoveUpRight: TSpeedButton
-      Left = 286
-      Top = 2
-      Width = 25
+      Left = 304
       Height = 25
-      GroupIndex = 1
+      Top = -4
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -336,14 +365,15 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object sbMoveRight: TSpeedButton
-      Left = 286
-      Top = 26
-      Width = 25
+      Left = 304
       Height = 25
-      GroupIndex = 1
+      Top = 20
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -370,14 +400,15 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object sbMoveLeft: TSpeedButton
-      Left = 238
-      Top = 26
-      Width = 25
+      Left = 256
       Height = 25
-      GroupIndex = 1
+      Top = 20
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -404,14 +435,15 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object sbMoveDownLeft: TSpeedButton
-      Left = 238
-      Top = 50
-      Width = 25
+      Left = 256
       Height = 25
-      GroupIndex = 1
+      Top = 44
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -438,14 +470,15 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object sbMoveDown: TSpeedButton
-      Left = 262
-      Top = 50
-      Width = 25
+      Left = 280
       Height = 25
-      GroupIndex = 1
+      Top = 44
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -472,14 +505,15 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object sbMoveDownRight: TSpeedButton
-      Left = 286
-      Top = 50
-      Width = 25
+      Left = 304
       Height = 25
-      GroupIndex = 1
+      Top = 44
+      Width = 25
       Glyph.Data = {
         36030000424D3603000000000000360000002800000010000000100000000100
         18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
@@ -506,67 +540,75 @@ object MapOptionsForm: TMapOptionsForm
         00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
         FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
         FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
-        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF}
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+      }
+      GroupIndex = 1
     end
     object LabelMapMove: TLabel
-      Left = 142
-      Top = 4
-      Width = 85
+      Left = 160
       Height = 39
+      Top = 0
+      Width = 85
       Alignment = taRightJustify
       AutoSize = False
-      BiDiMode = bdLeftToRight
       Caption = 'Направление смещения объектов карты:'
-      ParentBiDiMode = False
+      ParentBidiMode = False
+      ParentColor = False
       WordWrap = True
     end
     object eMapWidth: TEdit
-      Left = 66
-      Top = 7
-      Width = 45
+      Left = 60
       Height = 21
+      Top = 0
+      Width = 45
       MaxLength = 5
+      OnKeyPress = eMapSizeKeyPress
       TabOrder = 0
       Text = '0'
-      OnKeyPress = eMapSizeKeyPress
     end
     object UpDown1: TUpDown
-      Left = 111
-      Top = 7
-      Width = 17
+      Left = 105
       Height = 21
+      Top = 0
+      Width = 17
       Associate = eMapWidth
-      Max = 16384
       Increment = 16
+      Max = 16384
+      Min = 0
+      Position = 0
       TabOrder = 1
       Thousands = False
+      Wrap = False
     end
     object eMapHeight: TEdit
-      Left = 66
-      Top = 33
-      Width = 45
+      Left = 60
       Height = 21
+      Top = 26
+      Width = 45
       MaxLength = 5
+      OnKeyPress = eMapSizeKeyPress
       TabOrder = 2
       Text = '0'
-      OnKeyPress = eMapSizeKeyPress
     end
     object UpDown2: TUpDown
-      Left = 111
-      Top = 33
-      Width = 17
+      Left = 105
       Height = 21
+      Top = 26
+      Width = 17
       Associate = eMapHeight
-      Max = 16384
       Increment = 16
+      Max = 16384
+      Min = 0
+      Position = 0
       TabOrder = 3
       Thousands = False
+      Wrap = False
     end
     object cbSnapping: TCheckBox
-      Left = 158
+      Left = 128
+      Height = 19
       Top = 50
-      Width = 73
-      Height = 33
+      Width = 123
       Alignment = taLeftJustify
       Caption = 'Сохранять привязку'
       Checked = True
@@ -576,89 +618,89 @@ object MapOptionsForm: TMapOptionsForm
   end
   object eMapDescription: TEdit
     Left = 3
+    Height = 21
     Top = 59
     Width = 174
-    Height = 21
     MaxLength = 256
-    TabOrder = 1
     OnChange = eMapDescriptionChange
+    TabOrder = 1
   end
   object eMapName: TEdit
     Left = 3
+    Height = 21
     Top = 19
     Width = 174
-    Height = 21
     MaxLength = 32
-    TabOrder = 0
     OnChange = eMapNameChange
+    TabOrder = 0
   end
   object eBack: TEdit
     Left = 3
+    Height = 21
     Top = 147
     Width = 278
-    Height = 21
-    TabStop = False
     Color = clBtnFace
+    OnChange = eMapDescriptionChange
     ReadOnly = True
+    TabStop = False
     TabOrder = 4
-    OnChange = eMapDescriptionChange
   end
   object eMusic: TEdit
     Left = 3
+    Height = 21
     Top = 187
     Width = 278
-    Height = 21
-    TabStop = False
     Color = clBtnFace
+    OnChange = eMapDescriptionChange
     ReadOnly = True
+    TabStop = False
     TabOrder = 7
-    OnChange = eMapDescriptionChange
   end
   object bSelectBack: TButton
     Left = 311
-    Top = 146
-    Width = 23
     Height = 23
     Hint = 'Выбрать фон'
+    Top = 146
+    Width = 23
     Caption = '...'
-    TabOrder = 5
     OnClick = bSelectBackClick
+    TabOrder = 5
   end
   object bSelectMusic: TButton
     Left = 311
-    Top = 186
-    Width = 23
     Height = 23
     Hint = 'Выбрать музыку'
+    Top = 186
+    Width = 23
     Caption = '...'
-    TabOrder = 8
     OnClick = bSelectMusicClick
+    TabOrder = 8
   end
   object eAuthor: TEdit
     Left = 3
+    Height = 21
     Top = 99
     Width = 174
-    Height = 21
     MaxLength = 32
-    TabOrder = 2
     OnChange = eAuthorChange
+    TabOrder = 2
   end
   object bRemoveBack: TButton
     Left = 285
-    Top = 146
-    Width = 23
     Height = 23
     Hint = 'Убрать фон'
-    TabOrder = 6
+    Top = 146
+    Width = 23
     OnClick = bRemoveBackClick
+    TabOrder = 6
   end
   object bRemoveMusic: TButton
     Left = 285
-    Top = 186
-    Width = 23
     Height = 23
     Hint = 'Убрать музыку'
-    TabOrder = 9
+    Top = 186
+    Width = 23
     OnClick = bRemoveMusicClick
+    TabOrder = 9
   end
 end
index 37d9ec1d18babbcd207d8964b80b01e9a7e7390c..d400d8b7b215853f1e49457b8ac95929fc667b1c 100644 (file)
 object OptionsForm: TOptionsForm
   Left = 202
+  Height = 262
   Top = 174
+  Width = 435
   BorderIcons = [biSystemMenu]
   BorderStyle = bsSingle
   Caption = 'Настройки редактора'
   ClientHeight = 262
-  ClientWidth = 415
+  ClientWidth = 435
   Color = clBtnFace
-  Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
   Font.Height = -11
   Font.Name = 'MS Sans Serif'
-  Font.Style = []
-  Position = poScreenCenter
   OnActivate = FormActivate
-  PixelsPerInch = 96
+  Position = poScreenCenter
+  LCLVersion = '1.6.0.4'
   object GroupBox1: TGroupBox
     Left = 8
-    Top = 0
-    Width = 401
     Height = 225
+    Top = 0
+    Width = 425
+    ClientHeight = 207
+    ClientWidth = 421
     TabOrder = 0
     object sDotColor: TShape
-      Left = 318
+      Left = 344
+      Height = 25
       Top = 2
       Width = 57
-      Height = 25
     end
     object LabelGrid: TLabel
       Left = 6
+      Height = 13
       Top = 74
       Width = 61
-      Height = 13
       Caption = 'Шаги сетки:'
+      ParentColor = False
     end
     object LabelGridCol: TLabel
       Left = 190
+      Height = 13
       Top = 2
       Width = 60
-      Height = 13
       Caption = 'Цвет сетки:'
+      ParentColor = False
     end
     object LabelBack: TLabel
       Left = 190
+      Height = 13
       Top = 43
       Width = 57
-      Height = 13
       Caption = 'Цвет фона:'
+      ParentColor = False
     end
     object sBackColor: TShape
-      Left = 318
+      Left = 344
+      Height = 25
       Top = 43
       Width = 57
-      Height = 25
       Brush.Color = clBlack
     end
     object LabelPreview: TLabel
       Left = 190
-      Top = 73
-      Width = 84
-      Height = 39
+      Height = 13
+      Top = 72
+      Width = 216
       Caption = 'Цвет фона поля предпросмотра текстуры:'
+      ParentColor = False
       WordWrap = True
     end
     object sPreviewColor: TShape
-      Left = 318
-      Top = 83
-      Width = 57
+      Left = 344
       Height = 25
+      Top = 88
+      Width = 57
       Brush.Color = clBlack
     end
     object LabelMinimap: TLabel
       Left = 190
+      Height = 13
       Top = 131
       Width = 112
-      Height = 13
       Caption = 'Масштаб мини-карты:'
+      ParentColor = False
     end
     object LabelRecent: TLabel
       Left = 190
+      Height = 13
       Top = 162
-      Width = 121
-      Height = 26
+      Width = 199
       Caption = 'Запоминать последних открытых карт:'
+      ParentColor = False
       WordWrap = True
     end
     object LabelLanguage: TLabel
       Left = 6
+      Height = 13
       Top = 162
       Width = 31
-      Height = 13
       Caption = 'Язык:'
+      ParentColor = False
     end
     object LabelGridSize: TLabel
       Left = 6
+      Height = 13
       Top = 122
-      Width = 73
-      Height = 26
+      Width = 105
       Caption = 'Размер точек сетки:'
+      ParentColor = False
       WordWrap = True
     end
     object cbShowDots: TCheckBox
       Left = 6
+      Height = 19
       Top = 2
-      Width = 121
-      Height = 17
+      Width = 114
       Caption = 'Показывать сетку'
       TabOrder = 0
     end
     object UpDown1: TUpDown
       Left = 143
+      Height = 21
       Top = 74
       Width = 12
-      Height = 21
       Associate = eDotStepOne
-      Min = 2
       Max = 255
+      Min = 2
       Position = 16
       TabOrder = 6
+      Wrap = False
     end
     object eDotStepOne: TEdit
       Left = 86
+      Height = 21
       Top = 74
       Width = 57
-      Height = 21
       TabOrder = 1
       Text = '16'
     end
     object bGrid: TButton
-      Left = 376
+      Left = 402
+      Height = 25
       Top = 2
       Width = 11
-      Height = 25
       Caption = '..'
-      TabOrder = 2
       OnClick = bGridClick
+      TabOrder = 2
     end
     object bBack: TButton
-      Left = 376
+      Left = 402
+      Height = 25
       Top = 43
       Width = 11
-      Height = 25
       Caption = '..'
-      TabOrder = 3
       OnClick = bBackClick
+      TabOrder = 3
     end
     object bPreview: TButton
-      Left = 376
-      Top = 83
-      Width = 11
+      Left = 402
       Height = 25
+      Top = 88
+      Width = 11
       Caption = '..'
-      TabOrder = 4
       OnClick = bPreviewClick
+      TabOrder = 4
     end
     object cbScale: TComboBox
-      Left = 318
+      Left = 344
+      Height = 21
       Top = 131
       Width = 70
-      Height = 21
-      Style = csDropDownList
       ItemHeight = 13
       ItemIndex = 0
-      TabOrder = 5
-      Text = '1x'
       Items.Strings = (
         '1x'
-        '2x')
+        '2x'
+      )
+      Style = csDropDownList
+      TabOrder = 5
+      Text = '1x'
     end
     object cbShowTexture: TCheckBox
       Left = 6
+      Height = 19
       Top = 18
       Width = 169
-      Height = 17
       Caption = 'Показывать текстуру панели'
       TabOrder = 7
     end
     object cbShowSize: TCheckBox
       Left = 6
+      Height = 19
       Top = 34
-      Width = 169
-      Height = 17
+      Width = 171
       Caption = 'Показывать размеры панели'
       TabOrder = 8
     end
     object eRecent: TEdit
-      Left = 318
-      Top = 166
-      Width = 57
+      Left = 344
       Height = 21
+      Top = 184
+      Width = 57
       TabOrder = 9
       Text = '5'
     end
     object UpDown3: TUpDown
-      Left = 375
-      Top = 166
-      Width = 12
+      Left = 401
       Height = 21
+      Top = 184
+      Width = 12
       Associate = eRecent
-      Min = 2
       Max = 10
+      Min = 2
       Position = 5
       TabOrder = 10
+      Wrap = False
     end
     object eDotStepTwo: TEdit
       Left = 86
+      Height = 21
       Top = 98
       Width = 57
-      Height = 21
       TabOrder = 11
       Text = '8'
     end
     object UpDown2: TUpDown
       Left = 143
+      Height = 21
       Top = 98
       Width = 12
-      Height = 21
       Associate = eDotStepTwo
-      Min = 2
       Max = 255
+      Min = 2
       Position = 8
       TabOrder = 12
+      Wrap = False
     end
     object rbRussian: TRadioButton
       Left = 86
+      Height = 19
       Top = 162
-      Width = 81
-      Height = 17
+      Width = 62
       Caption = 'Русский'
       Checked = True
       TabOrder = 13
@@ -234,47 +248,72 @@ object OptionsForm: TOptionsForm
     end
     object rbEnglish: TRadioButton
       Left = 86
+      Height = 19
       Top = 186
-      Width = 81
-      Height = 17
+      Width = 54
       Caption = 'English'
       TabOrder = 14
     end
     object cbDotSize: TComboBox
-      Left = 86
-      Top = 126
-      Width = 73
+      Left = 82
       Height = 21
+      Top = 136
+      Width = 73
       ItemHeight = 13
-      TabOrder = 15
-      Text = '1'
+      ItemIndex = 0
       Items.Strings = (
         '1'
-        '2')
+        '2'
+      )
+      TabOrder = 15
+      Text = '1'
     end
   end
   object bOK: TButton
-    Left = 240
+    Left = 262
+    Height = 25
     Top = 232
     Width = 75
-    Height = 25
     Caption = 'ОК'
     Default = True
-    TabOrder = 1
     OnClick = bOKClick
+    TabOrder = 1
   end
   object bCancel: TButton
-    Left = 336
+    Left = 358
+    Height = 25
     Top = 232
     Width = 75
-    Height = 25
     Cancel = True
     Caption = 'Отмена'
-    TabOrder = 2
     OnClick = bCancelClick
+    TabOrder = 2
   end
   object ColorDialog: TColorDialog
-    Left = 200
-    Top = 232
+    Color = clBlack
+    CustomColors.Strings = (
+      'ColorA=000000'
+      'ColorB=000080'
+      'ColorC=008000'
+      'ColorD=008080'
+      'ColorE=800000'
+      'ColorF=800080'
+      'ColorG=808000'
+      'ColorH=808080'
+      'ColorI=C0C0C0'
+      'ColorJ=0000FF'
+      'ColorK=00FF00'
+      'ColorL=00FFFF'
+      'ColorM=FF0000'
+      'ColorN=FF00FF'
+      'ColorO=FFFF00'
+      'ColorP=FFFFFF'
+      'ColorQ=C0DCC0'
+      'ColorR=F0CAA6'
+      'ColorS=F0FBFF'
+      'ColorT=A4A0A0'
+    )
+    left = 200
+    top = 232
   end
 end
index 2a99675348972c5a22f5cfaff359af8fa72b4c1a..7a9b194002a0a0f1ca487f542dc44d0307b509be 100644 (file)
@@ -1,4 +1,4 @@
-Unit g_language;
+Unit g_language;
 
 {$MODE Delphi}
 
@@ -602,7 +602,8 @@ Const
   LANGUAGE_ENGLISH_N = 2;
 
 Var
-  _lc: Array [TStrings_Locale] of String;
+  _lc: Array [TStrings_Locale] of String;  // for the GUI (in UTF-8)
+  _glc: Array [TStrings_Locale] of String; // for GL text (in CP1251)
 
   BoolNames: Array [False..True] of String;
   DirNames: Array [D_LEFT..D_RIGHT] of String;
@@ -628,7 +629,7 @@ Uses
   f_addresource_sky, f_addresource_sound,
   f_addresource_texture, f_choosetype, f_keys, f_mapcheck,
   f_mapoptions, f_maptest, f_mapoptimization, f_options,
-  f_packmap, f_savemap, f_saveminimap, f_selectmap, Forms;
+  f_packmap, f_savemap, f_saveminimap, f_selectmap, Forms, utils;
 
 Const
   g_lang_default: Array [TStrings_Locale] of Array [1..3] of String = (
@@ -2441,7 +2442,11 @@ begin
     n := LANGUAGE_RUSSIAN_N;
 
   for i := Low(TStrings_Locale) to High(TStrings_Locale) do
+  begin
     _lc[i] := g_lang_default[i][n];
+    // have to cache a CP1251 version for GL text
+    _glc[i] := utf8to1251(g_lang_default[i][n]);
+  end;
 
   SetupArrays();
   SetupCaptions();
@@ -2463,4 +2468,4 @@ begin
   CloseFile(F);
 end;
 
-End.
\ No newline at end of file
+End.
index d61a0e2c2fc57d1617ca4b2220de416176c749b2..a49b6f9edb7872fcd0d577db2ffad2f1bed88324 100644 (file)
@@ -1378,7 +1378,7 @@ var
   FileName, SectionName, ResName, _fn: String;
   TextureRes: String;
   pData: Pointer;
-  Len: Integer;
+  Len, FrameLen: Integer;
   Error: Boolean;
   NoTextureID: DWORD;
   NW, NH: Word;
@@ -1457,14 +1457,14 @@ begin
         end
       else // Anim
         begin // Анимированная текстура
-          if not GetFrame(TextureRes, Data, Width, Height) then
+          if not GetFrame(TextureRes, Data, FrameLen, Width, Height) then
           begin // Кадры
             e_WriteLog(Format('GetFrame() error, res=%s',
                               [textures[a].Resource]), MSG_WARNING);
             Error := True;
           end;
 
-          if not g_CreateTextureMemorySize(Data, textures[a].Resource, 0, 0, Width, Height, 1) then
+          if not g_CreateTextureMemorySize(Data, FrameLen, textures[a].Resource, 0, 0, Width, Height, 1) then
           begin // Сама текстура
             e_WriteLog(Format('g_CreateTextureMemorySize() error, res=%s',
                               [textures[a].Resource]), MSG_WARNING);
index 5cad990728fdeef920044afd92044e06680ab12e..7c130136b8a53f6a035b92cfac6dcdba877465d8 100644 (file)
@@ -13,7 +13,7 @@ function g_SimpleCreateTextureWADSize(var ID: DWORD; Resource: string;
 function g_CreateTextureWAD(TextureName: ShortString; Resource: string; flag: Byte = 0): Boolean;
 function g_CreateTextureWADSize(TextureName: ShortString; Resource: string;
                                 X, Y, Width, Height: Word; flag: Byte = 0): Boolean;
-function g_CreateTextureMemorySize(pData: Pointer; Name: ShortString; X, Y,
+function g_CreateTextureMemorySize(pData: Pointer; dataLen: Integer; Name: ShortString; X, Y,
                                    Width, Height: Word; flag: Byte = 0): Boolean;
 
 function g_GetTexture(TextureName: ShortString; var ID: DWORD): Boolean;
@@ -82,7 +82,7 @@ begin
 
  if WAD.GetResource(SectionName, ResourceName, TextureData, ResourceLength) then
  begin
-  if e_CreateTextureMem(TextureData, ID) then Result := True;
+  if e_CreateTextureMem(TextureData, ResourceLength, ID) then Result := True;
   FreeMem(TextureData);
  end
   else
@@ -93,7 +93,7 @@ begin
  WAD.Destroy;
 end;
 
-function g_CreateTextureMemorySize(pData: Pointer; Name: ShortString; X, Y,
+function g_CreateTextureMemorySize(pData: Pointer; dataLen: Integer; Name: ShortString; X, Y,
                                    Width, Height: Word; flag: Byte = 0): Boolean;
 var
   find_id: DWORD;
@@ -104,7 +104,7 @@ begin
 
   find_id := FindTexture;
 
-  if not e_CreateTextureMemEx(pData, TexturesArray[find_id].ID, X, Y, Width, Height) then
+  if not e_CreateTextureMemEx(pData, dataLen, TexturesArray[find_id].ID, X, Y, Width, Height) then
   begin
     FreeMem(pData);
     Exit;
@@ -139,7 +139,7 @@ begin
 
  if WAD.GetResource(SectionName, ResourceName, TextureData, ResourceLength) then
  begin
-  Result := e_CreateTextureMem(TextureData, TexturesArray[find_id].ID);
+  Result := e_CreateTextureMem(TextureData, ResourceLength, TexturesArray[find_id].ID);
   FreeMem(TextureData);
   if Result then
   begin
@@ -176,7 +176,7 @@ begin
 
  if WAD.GetResource(SectionName, ResourceName, TextureData, ResourceLength) then
  begin
-  if e_CreateTextureMemEx(TextureData, ID, X, Y, Width, Height) then Result := True;
+  if e_CreateTextureMemEx(TextureData, ResourceLength, ID, X, Y, Width, Height) then Result := True;
   FreeMem(TextureData);
  end
   else
@@ -207,7 +207,7 @@ begin
 
  if WAD.GetResource(SectionName, ResourceName, TextureData, ResourceLength) then
  begin
-  Result := e_CreateTextureMemEx(TextureData, TexturesArray[find_id].ID, X, Y, Width, Height);
+  Result := e_CreateTextureMemEx(TextureData, ResourceLength, TexturesArray[find_id].ID, X, Y, Width, Height);
   FreeMem(TextureData);
   if Result then
   begin
index e4eb35a89ed96385e90571c40c9d4d8d6959f5bc..63a9e5bc113c6569f0cda0a65bcf5bc5d63c9bd6 100644 (file)
@@ -1,9 +1,26 @@
+(* Copyright (C)  DooM 2D:Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$MODE DELPHI}
 unit e_graphics;
 
 interface
 
 uses
-  windows, SysUtils, Math, e_log, e_textures, dglOpenGL;
+  SysUtils, Classes, Math, e_log, e_textures, GL, GLExt, MAPDEF,
+  ImagingTypes, Imaging, ImagingUtility;
 
 type
   TMirrorType=(M_NONE, M_HORIZONTAL, M_VERTICAL);
@@ -13,11 +30,16 @@ type
     X, Y: Integer;
   end;
 
+  TPoint = MAPDEF.TPoint; // TODO: create an utiltypes.pas or something
+                          //       for other types like rect as well
+
   TPoint2f = record
     X, Y: Double;
   end;
 
-  TRect = windows.TRect;
+  TRect = record
+    Left, Top, Right, Bottom: Integer;
+  end;
 
   TRectWH = record
    X, Y: Integer;
@@ -37,7 +59,7 @@ type
 //------------------------------------------------------------------
 // ïðîòîòèïû ôóíêöèé
 //------------------------------------------------------------------
-procedure e_InitGL(VSync: Boolean);
+procedure e_InitGL();
 procedure e_SetViewPort(X, Y, Width, Height: Word);
 procedure e_ResizeWindow(Width, Height: Integer);
 
@@ -57,22 +79,16 @@ procedure e_DrawQuad(X1, Y1, X2, Y2: Integer; Red, Green, Blue: Byte; Alpha: Byt
 procedure e_DrawFillQuad(X1, Y1, X2, Y2: Integer; Red, Green, Blue, Alpha: Byte;
                          Blending: TBlending = B_NONE);
 
+function e_CreateTextureImg (var img: TImageData; var ID: DWORD): Boolean;
 function e_CreateTexture(FileName: string; var ID: DWORD): Boolean;
 function e_CreateTextureEx(FileName: string; var ID: DWORD; fX, fY, fWidth, fHeight: Word): Boolean;
-function e_CreateTextureMem(pData: Pointer; var ID: DWORD): Boolean;
-function e_CreateTextureMemEx(pData: Pointer; var ID: DWORD; fX, fY, fWidth, fHeight: Word): Boolean;
+function e_CreateTextureMem(pData: Pointer; dataSize: LongInt; var ID: DWORD): Boolean;
+function e_CreateTextureMemEx(pData: Pointer; dataSize: LongInt; var ID: DWORD; fX, fY, fWidth, fHeight: Word): Boolean;
 procedure e_GetTextureSize(ID: DWORD; Width, Height: PWord);
 function e_GetTextureSize2(ID: DWORD): TRectWH;
 procedure e_DeleteTexture(ID: DWORD);
 procedure e_RemoveAllTextures();
 
-// SimpleFont
-function e_SimpleFontCreate(FontName: PChar; Size: Byte; Weight: Word; DC: HDC): DWORD;
-procedure e_SimpleFontFree(Font: DWORD);
-procedure e_SimpleFontPrint(X, Y: SmallInt; Text: PChar; Font: Integer; Red, Green, Blue: Byte);
-procedure e_SimpleFontPrintEx(X, Y: SmallInt; Text: PChar; Font: DWORD; Red, Green, Blue,
-                      sRed, sGreen, sBlue, sWidth: Byte);
-
 // CharFont
 function e_CharFont_Create(sp: ShortInt=0): DWORD;
 procedure e_CharFont_AddChar(FontID: DWORD; Texture: Integer; c: Char; w: Byte);
@@ -88,7 +104,7 @@ procedure e_CharFont_Remove(FontID: DWORD);
 procedure e_CharFont_RemoveAll();
 
 // TextureFont
-procedure e_TextureFontBuild(Texture: DWORD; var FontID: DWORD; XCount, YCount: Word;
+procedure e_TextureFontBuild(Tex: DWORD; var FontID: DWORD; XCount, YCount: Word;
                              Space: ShortInt=0);
 procedure e_TextureFontKill(FontID: DWORD);
 procedure e_TextureFontPrint(X, Y: GLint; Text: string; FontID: DWORD);
@@ -98,38 +114,46 @@ procedure e_TextureFontPrintFmt(X, Y: GLint; Text: string; FontID: DWORD; Shadow
 procedure e_TextureFontGetSize(ID: DWORD; var CharWidth, CharHeight: Byte);
 procedure e_RemoveAllTextureFont();
 
+function e_TextureFontCharWidth (ch: Char; FontID: DWORD): Integer;
+procedure e_TextureFontPrintCharEx (X, Y: Integer; Ch: Char; FontID: DWORD; Shadow: Boolean = False);
+
 procedure e_ReleaseEngine();
 procedure e_BeginRender();
-procedure e_Clear(Mask: TGLbitfield; Red, Green, Blue: Single);
+procedure e_Clear(Mask: TGLbitfield; Red, Green, Blue: Single); overload;
+procedure e_Clear(); overload;
 procedure e_EndRender();
 
-function e_GetGamma(DC: HDC): Byte;
-procedure e_SetGamma(Gamma: Byte; DC: HDC);
-
-procedure e_MakeScreenshot(FileName: string; Width, Height: Word);
-
 function _RGB(Red, Green, Blue: Byte): TRGB;
 function _Point(X, Y: Integer): TPoint2i;
 function _Rect(X, Y: Integer; Width, Height: Word): TRectWH;
+function _TRect(L, T, R, B: LongInt): TRect;
 
+//function e_getTextGLId (ID: DWORD): GLuint;
 
 var
   e_Colors: TRGB;
+  e_NoGraphics: Boolean = False;
+  e_FastScreenshots: Boolean = true; // it's REALLY SLOW with `false`
+
 
 implementation
 
+uses
+  paszlib, crc, utils;
+
+
 type
   TTexture = record
-   ID:     DWORD;
-   Width:  Word;
-   Height: Word;
+   tx:     GLTexture;
   end;
 
   TTextureFont = record
-   TextureID:  DWORD;
-   Base:       GLuint;
-   CharWidth:  Byte;
-   CharHeight: Byte;
+   Texture:     DWORD;
+   TextureID:   DWORD;
+   Base:        Uint32;
+   CharWidth:   Byte;
+   CharHeight:  Byte;
+   XC, YC, SPC: Word;
   end;
 
   TCharFont = record
@@ -143,25 +167,35 @@ type
    Live: Boolean;
   end;
 
+  TSavedTexture = record
+    TexID:  DWORD;
+    OldID:  DWORD;
+    Pixels: Pointer;
+  end;
+
 var
   e_Textures: array of TTexture = nil;
   e_TextureFonts: array of TTextureFont = nil;
   e_CharFonts: array of TCharFont;
+  //e_SavedTextures: array of TSavedTexture;
+
+//function e_getTextGLId (ID: DWORD): GLuint; begin result := e_Textures[ID].tx.id; end;
 
 //------------------------------------------------------------------
 // Èíèöèàëèçèðóåò OpenGL
 //------------------------------------------------------------------
-procedure e_InitGL(VSync: Boolean);
+procedure e_InitGL();
 begin
-  if VSync then
-    wglSwapIntervalEXT(1)
-  else
-    wglSwapIntervalEXT(0);
-  glDisable(GL_DEPTH_TEST);
-  glEnable(GL_SCISSOR_TEST);
+  if e_NoGraphics then
+  begin
+    e_DummyTextures := True;
+    Exit;
+  end;
   e_Colors.R := 255;
   e_Colors.G := 255;
   e_Colors.B := 255;
+  glDisable(GL_DEPTH_TEST);
+  glEnable(GL_SCISSOR_TEST);
   glClearColor(0, 0, 0, 0);
 end;
 
@@ -170,6 +204,7 @@ var
   mat: Array [0..15] of GLDouble;
 
 begin
+  if e_NoGraphics then Exit;
   glLoadIdentity();
   glScissor(X, Y, Width, Height);
   glViewport(X, Y, Width, Height);
@@ -200,7 +235,7 @@ begin
   glLoadMatrixd(@mat[0]);
 
   glMatrixMode(GL_MODELVIEW);
-  glLoadIdentity();   
+  glLoadIdentity();
 end;
 
 //------------------------------------------------------------------
@@ -212,7 +247,7 @@ var
 begin
  if e_Textures <> nil then
  for i := 0 to High(e_Textures) do
-  if e_Textures[i].Width = 0 then
+  if e_Textures[i].tx.Width = 0 then
   begin
    Result := i;
    Exit;
@@ -236,6 +271,7 @@ end;
 function e_CreateTexture(FileName: String; var ID: DWORD): Boolean;
 var
   find_id: DWORD;
+  fmt:     Word;
 begin
  Result := False;
 
@@ -243,8 +279,8 @@ begin
 
  find_id := FindTexture();
 
- if not LoadTexture(FileName, e_Textures[find_id].ID, e_Textures[find_id].Width,
-                    e_Textures[find_id].Height) then Exit;
+ if not LoadTexture(FileName, e_Textures[find_id].tx, e_Textures[find_id].tx.Width,
+                    e_Textures[find_id].tx.Height, @fmt) then Exit;
 
  ID := find_id;
 
@@ -254,81 +290,92 @@ end;
 function e_CreateTextureEx(FileName: String; var ID: DWORD; fX, fY, fWidth, fHeight: Word): Boolean;
 var
   find_id: DWORD;
+  fmt:     Word;
 begin
  Result := False;
 
  find_id := FindTexture();
 
- if not LoadTextureEx(FileName, e_Textures[find_id].ID, fX, fY, fWidth, fHeight) then Exit;
-
- e_Textures[find_id].Width := fWidth;
- e_Textures[find_id].Height := fHeight;
+ if not LoadTextureEx(FileName, e_Textures[find_id].tx, fX, fY, fWidth, fHeight, @fmt) then exit;
 
  ID := find_id;
 
  Result := True;
 end;
 
-function e_CreateTextureMem(pData: Pointer; var ID: DWORD): Boolean;
+function e_CreateTextureMem(pData: Pointer; dataSize: LongInt; var ID: DWORD): Boolean;
 var
   find_id: DWORD;
+  fmt:     Word;
 begin
  Result := False;
 
  find_id := FindTexture;
 
- if not LoadTextureMem(pData, e_Textures[find_id].ID, e_Textures[find_id].Width,
-                   e_Textures[find_id].Height) then Exit;
+ if not LoadTextureMem(pData, dataSize, e_Textures[find_id].tx, e_Textures[find_id].tx.Width, e_Textures[find_id].tx.Height, @fmt) then exit;
 
  id := find_id;
 
  Result := True;
 end;
 
-function e_CreateTextureMemEx(pData: Pointer; var ID: DWORD; fX, fY, fWidth, fHeight: Word): Boolean;
+function e_CreateTextureMemEx(pData: Pointer; dataSize: LongInt; var ID: DWORD; fX, fY, fWidth, fHeight: Word): Boolean;
 var
   find_id: DWORD;
+  fmt:     Word;
 begin
  Result := False;
 
  find_id := FindTexture();
 
- if not LoadTextureMemEx(pData, e_Textures[find_id].ID, fX, fY, fWidth, fHeight) then Exit;
-
- e_Textures[find_id].Width := fWidth;
- e_Textures[find_id].Height := fHeight;
+ if not LoadTextureMemEx(pData, dataSize, e_Textures[find_id].tx, fX, fY, fWidth, fHeight, @fmt) then exit;
 
  ID := find_id;
 
  Result := True;
 end;
 
+function e_CreateTextureImg (var img: TImageData; var ID: DWORD): Boolean;
+var
+  find_id: DWORD;
+  fmt, tw, th: Word;
+begin
+  result := false;
+  find_id := FindTexture();
+  if not LoadTextureImg(img, e_Textures[find_id].tx, tw, th, @fmt) then exit;
+  ID := find_id;
+  result := True;
+end;
+
 procedure e_GetTextureSize(ID: DWORD; Width, Height: PWord);
 begin
- if Width <> nil then Width^ := e_Textures[ID].Width;
- if Height <> nil then Height^ := e_Textures[ID].Height;
+ if Width <> nil then Width^ := e_Textures[ID].tx.Width;
+ if Height <> nil then Height^ := e_Textures[ID].tx.Height;
 end;
 
 function e_GetTextureSize2(ID: DWORD): TRectWH;
 var
-  data: Pointer;
+  data: PChar;
   x, y: Integer;
   w, h: Word;
   a: Boolean;
   lastline: Integer;
 begin
- w := e_Textures[ID].Width;
- h := e_Textures[ID].Height;
- data := GetMemory(w*h*4);
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, e_Textures[ID].ID);
- glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ w := e_Textures[ID].tx.Width;
+ h := e_Textures[ID].tx.Height;
 
  Result.Y := 0;
  Result.X := 0;
  Result.Width := w;
  Result.Height := h;
 
+ if e_NoGraphics then Exit;
+
+ data := GetMemory(w*h*4);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, e_Textures[ID].tx.id);
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
  for y := h-1 downto 0 do
  begin
   lastline := y;
@@ -336,7 +383,7 @@ begin
 
   for x := 1 to w-4 do
   begin
-   a := Byte(Pointer(Integer(data)+y*w*4+x*4+3)^) <> 0;
+   a := Byte((data+y*w*4+x*4+3)^) <> 0;
    if a then Break;
   end;
 
@@ -354,7 +401,7 @@ begin
 
   for x := 1 to w-4 do
   begin
-   a := Byte(Pointer(Integer(data)+y*w*4+x*4+3)^) <> 0;
+   a := Byte((data+y*w*4+x*4+3)^) <> 0;
    if a then Break;
   end;
 
@@ -372,7 +419,7 @@ begin
 
   for y := 1 to h-4 do
   begin
-   a := Byte(Pointer(Integer(data)+y*w*4+x*4+3)^) <> 0;
+   a := Byte((data+y*w*4+x*4+3)^) <> 0;
    if a then Break;
   end;
 
@@ -390,7 +437,7 @@ begin
 
   for y := 1 to h-4 do
   begin
-   a := Byte(Pointer(Integer(data)+y*w*4+x*4+3)^) <> 0;
+   a := Byte((data+y*w*4+x*4+3)^) <> 0;
    if a then Break;
   end;
 
@@ -411,11 +458,27 @@ begin
   e_SetViewPort(0, 0, Width, Height);
 end;
 
+procedure drawTxQuad (x0, y0, w, h: Integer; u, v: single; Mirror: TMirrorType);
+var
+  x1, y1, tmp: Integer;
+begin
+  if (w < 1) or (h < 1) then exit;
+  x1 := x0+w;
+  y1 := y0+h;
+       if Mirror = M_HORIZONTAL then begin tmp := x1; x1 := x0; x0 := tmp; end
+  else if Mirror = M_VERTICAL then begin tmp := y1; y1 := y0; y0 := tmp; end;
+  glTexCoord2f(0, v); glVertex2i(x0, y0);
+  glTexCoord2f(0, 0); glVertex2i(x0, y1);
+  glTexCoord2f(u, 0); glVertex2i(x1, y1);
+  glTexCoord2f(u, v); glVertex2i(x1, y0);
+end;
+
 procedure e_Draw(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean;
                  Blending: Boolean; Mirror: TMirrorType = M_NONE);
-begin  
+begin
+  if e_NoGraphics then Exit;
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
-     
+
   if (Alpha > 0) or (AlphaChannel) or (Blending) then
     glEnable(GL_BLEND)
   else
@@ -431,32 +494,39 @@ begin
     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 
   glEnable(GL_TEXTURE_2D);
-  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].ID);
+  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].tx.id);
   glBegin(GL_QUADS);
 
+  drawTxQuad(X, Y, e_Textures[id].tx.width, e_Textures[id].tx.height, e_Textures[ID].tx.u, e_Textures[ID].tx.v, Mirror);
+
+  //u := e_Textures[ID].tx.u;
+  //v := e_Textures[ID].tx.v;
+
+  {
   if Mirror = M_NONE then
     begin
-      glTexCoord2i(1,  0); glVertex2i(X + e_Textures[id].Width, Y);
-      glTexCoord2i(0,  0); glVertex2i(X,                        Y);
-      glTexCoord2i(0, -1); glVertex2i(X,                        Y + e_Textures[id].Height);
-      glTexCoord2i(1, -1); glVertex2i(X + e_Textures[id].Width, Y + e_Textures[id].Height);
+      glTexCoord2f(u,  0); glVertex2i(X + e_Textures[id].tx.Width, Y);
+      glTexCoord2f(0,  0); glVertex2i(X,                        Y);
+      glTexCoord2f(0, -v); glVertex2i(X,                        Y + e_Textures[id].tx.Height);
+      glTexCoord2f(u, -v); glVertex2i(X + e_Textures[id].tx.Width, Y + e_Textures[id].tx.Height);
     end
   else
     if Mirror = M_HORIZONTAL then
       begin
-        glTexCoord2i(1,  0); glVertex2i(X,                        Y);
-        glTexCoord2i(0,  0); glVertex2i(X + e_Textures[id].Width, Y);
-        glTexCoord2i(0, -1); glVertex2i(X + e_Textures[id].Width, Y + e_Textures[id].Height);
-        glTexCoord2i(1, -1); glVertex2i(X,                        Y + e_Textures[id].Height);
+        glTexCoord2f(u,  0); glVertex2i(X,                        Y);
+        glTexCoord2f(0,  0); glVertex2i(X + e_Textures[id].tx.Width, Y);
+        glTexCoord2f(0, -v); glVertex2i(X + e_Textures[id].tx.Width, Y + e_Textures[id].tx.Height);
+        glTexCoord2f(u, -v); glVertex2i(X,                        Y + e_Textures[id].tx.Height);
       end
     else
       if Mirror = M_VERTICAL then
       begin
-        glTexCoord2i(1, -1); glVertex2i(X + e_Textures[id].Width, Y);
-        glTexCoord2i(0, -1); glVertex2i(X,                        Y);
-        glTexCoord2i(0,  0); glVertex2i(X,                        Y + e_Textures[id].Height);
-        glTexCoord2i(1,  0); glVertex2i(X + e_Textures[id].Width, Y + e_Textures[id].Height);
+        glTexCoord2f(u, -v); glVertex2i(X + e_Textures[id].tx.Width, Y);
+        glTexCoord2f(0, -v); glVertex2i(X,                        Y);
+        glTexCoord2f(0,  0); glVertex2i(X,                        Y + e_Textures[id].tx.Height);
+        glTexCoord2f(u,  0); glVertex2i(X + e_Textures[id].tx.Width, Y + e_Textures[id].tx.Height);
       end;
+  }
 
   glEnd();
 
@@ -465,7 +535,10 @@ end;
 
 procedure e_DrawSize(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean;
                      Blending: Boolean; Width, Height: Word; Mirror: TMirrorType = M_NONE);
+var
+  u, v: Single;
 begin
+  if e_NoGraphics then Exit;
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
 
   if (Alpha > 0) or (AlphaChannel) or (Blending) then
@@ -483,13 +556,16 @@ begin
     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 
   glEnable(GL_TEXTURE_2D);
-  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].ID);
+  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].tx.id);
+
+  u := e_Textures[ID].tx.u;
+  v := e_Textures[ID].tx.v;
 
   glBegin(GL_QUADS);
-    glTexCoord2i(0, 1); glVertex2i(X,         Y);
-    glTexCoord2i(1, 1); glVertex2i(X + Width, Y);
-    glTexCoord2i(1, 0); glVertex2i(X + Width, Y + Height);
-    glTexCoord2i(0, 0); glVertex2i(X,         Y + Height);
+    glTexCoord2f(0, v); glVertex2i(X,         Y);
+    glTexCoord2f(u, v); glVertex2i(X + Width, Y);
+    glTexCoord2f(u, 0); glVertex2i(X + Width, Y + Height);
+    glTexCoord2f(0, 0); glVertex2i(X,         Y + Height);
   glEnd();
 
   glDisable(GL_BLEND);
@@ -498,6 +574,7 @@ end;
 procedure e_DrawSizeMirror(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean;
                            Blending: Boolean; Width, Height: Word; Mirror: TMirrorType = M_NONE);
 begin
+  if e_NoGraphics then Exit;
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
 
   if (Alpha > 0) or (AlphaChannel) or (Blending) then
@@ -515,33 +592,9 @@ begin
     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 
   glEnable(GL_TEXTURE_2D);
-  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].ID);
+  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].tx.id);
   glBegin(GL_QUADS);
-
-  if Mirror = M_NONE then
-    begin
-      glTexCoord2i(1,  0); glVertex2i(X + Width, Y);
-      glTexCoord2i(0,  0); glVertex2i(X,         Y);
-      glTexCoord2i(0, -1); glVertex2i(X,         Y + Height);
-      glTexCoord2i(1, -1); glVertex2i(X + Width, Y + Height);
-    end
-  else
-    if Mirror = M_HORIZONTAL then
-      begin
-        glTexCoord2i(1,  0); glVertex2i(X,         Y);
-        glTexCoord2i(0,  0); glVertex2i(X + Width, Y);
-        glTexCoord2i(0, -1); glVertex2i(X + Width, Y + Height);
-        glTexCoord2i(1, -1); glVertex2i(X,         Y + Height);
-      end
-    else
-      if Mirror = M_VERTICAL then
-      begin
-        glTexCoord2i(1, -1); glVertex2i(X + Width, Y);
-        glTexCoord2i(0, -1); glVertex2i(X,         Y);
-        glTexCoord2i(0,  0); glVertex2i(X,         Y + Height);
-        glTexCoord2i(1,  0); glVertex2i(X + Width, Y + Height);
-      end;
-
+  drawTxQuad(X, Y, Width, Height, e_Textures[ID].tx.u, e_Textures[ID].tx.v, Mirror);
   glEnd();
 
   glDisable(GL_BLEND);
@@ -550,9 +603,10 @@ end;
 procedure e_DrawFill(ID: DWORD; X, Y: Integer; XCount, YCount: Word; Alpha: Integer;
                      AlphaChannel: Boolean; Blending: Boolean);
 var
-  X2, Y2: Integer;
-  
+  X2, Y2, dx, w, h: Integer;
+  u, v: Single;
 begin
+  if e_NoGraphics then Exit;
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
 
   if (Alpha > 0) or (AlphaChannel) or (Blending) then
@@ -576,31 +630,64 @@ begin
     YCount := 1;
 
   glEnable(GL_TEXTURE_2D);
-  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].ID);
+  glBindTexture(GL_TEXTURE_2D, e_Textures[ID].tx.id);
 
-  X2 := X + e_Textures[ID].Width * XCount;
-  Y2 := Y + e_Textures[ID].Height * YCount;
-  glBegin(GL_QUADS);
-    glTexCoord2i(0,      YCount); glVertex2i(X,  Y);
-    glTexCoord2i(XCount, YCount); glVertex2i(X2, Y);
-    glTexCoord2i(XCount, 0);      glVertex2i(X2, Y2);
-    glTexCoord2i(0,      0);      glVertex2i(X,  Y2);
-  glEnd();
+  X2 := X + e_Textures[ID].tx.width * XCount;
+  Y2 := Y + e_Textures[ID].tx.height * YCount;
+
+  //k8: this SHOULD work... i hope
+  if (e_Textures[ID].tx.width = e_Textures[ID].tx.glwidth) and (e_Textures[ID].tx.height = e_Textures[ID].tx.glheight) then
+  begin
+    glBegin(GL_QUADS);
+      glTexCoord2i(0,      YCount); glVertex2i(X,  Y);
+      glTexCoord2i(XCount, YCount); glVertex2i(X2, Y);
+      glTexCoord2i(XCount, 0);      glVertex2i(X2, Y2);
+      glTexCoord2i(0,      0);      glVertex2i(X,  Y2);
+    glEnd();
+  end
+  else
+  begin
+    glBegin(GL_QUADS);
+    // hard day's night
+    u := e_Textures[ID].tx.u;
+    v := e_Textures[ID].tx.v;
+    w := e_Textures[ID].tx.width;
+    h := e_Textures[ID].tx.height;
+    while YCount > 0 do
+    begin
+      dx := XCount;
+      x2 := X;
+      while dx > 0 do
+      begin
+        glTexCoord2f(0, v); glVertex2i(X,  Y);
+        glTexCoord2f(u, v); glVertex2i(X+w, Y);
+        glTexCoord2f(u, 0); glVertex2i(X+w, Y+h);
+        glTexCoord2f(0, 0); glVertex2i(X,  Y+h);
+        Inc(X, w);
+        Dec(dx);
+      end;
+      X := x2;
+      Inc(Y, h);
+      Dec(YCount);
+    end;
+    glEnd();
+  end;
 
   glDisable(GL_BLEND);
 end;
 
 procedure e_DrawAdv(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean;
                     Blending: Boolean; Angle: Single; RC: PPoint; Mirror: TMirrorType = M_NONE);
-begin  
+begin
+  if e_NoGraphics then Exit;
+
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
 
   if (Alpha > 0) or (AlphaChannel) or (Blending) then
     glEnable(GL_BLEND)
   else
     glDisable(GL_BLEND);
-      
+
   if (AlphaChannel) or (Alpha > 0) then
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
@@ -619,33 +706,10 @@ begin
   end;
 
   glEnable(GL_TEXTURE_2D);
-  glBindTexture(GL_TEXTURE_2D, e_Textures[id].ID);
+  glBindTexture(GL_TEXTURE_2D, e_Textures[id].tx.id);
   glBegin(GL_QUADS);                           //0-1        1-1
                                                //00         10
-  if Mirror = M_NONE then
-    begin
-      glTexCoord2i(1,  0); glVertex2i(X + e_Textures[id].Width, Y);
-      glTexCoord2i(0,  0); glVertex2i(X,                        Y);
-      glTexCoord2i(0, -1); glVertex2i(X,                        Y + e_Textures[id].Height);
-      glTexCoord2i(1, -1); glVertex2i(X + e_Textures[id].Width, Y + e_Textures[id].Height);
-    end
-  else
-    if Mirror = M_HORIZONTAL then
-      begin
-        glTexCoord2i(1,  0); glVertex2i(X,                        Y);
-        glTexCoord2i(0,  0); glVertex2i(X + e_Textures[id].Width, Y);
-        glTexCoord2i(0, -1); glVertex2i(X + e_Textures[id].Width, Y + e_Textures[id].Height);
-        glTexCoord2i(1, -1); glVertex2i(X,                        Y + e_Textures[id].Height);
-      end
-    else
-      if Mirror = M_VERTICAL then
-      begin
-        glTexCoord2i(1, -1); glVertex2i(X + e_Textures[id].Width, Y);
-        glTexCoord2i(0, -1); glVertex2i(X,                        Y);
-        glTexCoord2i(0,  0); glVertex2i(X,                        Y + e_Textures[id].Height);
-        glTexCoord2i(1,  0); glVertex2i(X + e_Textures[id].Width, Y + e_Textures[id].Height);
-      end;
-
+  drawTxQuad(X, Y, e_Textures[id].tx.width, e_Textures[id].tx.height, e_Textures[ID].tx.u, e_Textures[ID].tx.v, Mirror);
   glEnd();
 
   if Angle <> 0 then
@@ -656,10 +720,11 @@ end;
 
 procedure e_DrawPoint(Size: Byte; X, Y: Integer; Red, Green, Blue: Byte);
 begin
+  if e_NoGraphics then Exit;
   glDisable(GL_TEXTURE_2D);
   glColor3ub(Red, Green, Blue);
   glPointSize(Size);
-  
+
   if (Size = 2) or (Size = 4) then
     X := X + 1;
 
@@ -670,45 +735,9 @@ begin
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
 end;
 
-procedure e_LineCorrection(var X1, Y1, X2, Y2: Integer);
-begin
-  // Make lines only top-left/bottom-right and top-right/bottom-left
-  if Y2 < Y1 then
-  begin
-    X1 := X1 xor X2;
-    X2 := X1 xor X2;
-    X1 := X1 xor X2;
-
-    Y1 := Y1 xor Y2;
-    Y2 := Y1 xor Y2;
-    Y1 := Y1 xor Y2;
-  end;
-
-  // Pixel-perfect hack
-  if X1 < X2 then
-    Inc(X2)
-  else
-    Inc(X1);
-  Inc(Y2);
-end;
-
 procedure e_DrawQuad(X1, Y1, X2, Y2: Integer; Red, Green, Blue: Byte; Alpha: Byte = 0);
-var
-  nX1, nY1, nX2, nY2: Integer;
 begin
-  // Only top-left/bottom-right quad
-  if X1 > X2 then
-  begin
-    X1 := X1 xor X2;
-    X2 := X1 xor X2;
-    X1 := X1 xor X2;
-  end;
-  if Y1 > Y2 then
-  begin
-    Y1 := Y1 xor Y2;
-    Y2 := Y1 xor Y2;
-    Y1 := Y1 xor Y2;
-  end;
+  if e_NoGraphics then Exit;
 
   if Alpha > 0 then
   begin
@@ -721,30 +750,11 @@ begin
   glColor4ub(Red, Green, Blue, 255-Alpha);
   glLineWidth(1);
 
-  glBegin(GL_LINES);
-    nX1 := X1; nY1 := Y1;
-    nX2 := X2; nY2 := Y1;
-    e_LineCorrection(nX1, nY1, nX2, nY2); // Pixel-perfect lines
-    glVertex2i(nX1, nY1);
-    glVertex2i(nX2, nY2);
-
-    nX1 := X2; nY1 := Y1;
-    nX2 := X2; nY2 := Y2;
-    e_LineCorrection(nX1, nY1, nX2, nY2);
-    glVertex2i(nX1, nY1);
-    glVertex2i(nX2, nY2);
-
-    nX1 := X2; nY1 := Y2;
-    nX2 := X1; nY2 := Y2;
-    e_LineCorrection(nX1, nY1, nX2, nY2);
-    glVertex2i(nX1, nY1);
-    glVertex2i(nX2, nY2);
-
-    nX1 := X1; nY1 := Y2;
-    nX2 := X1; nY2 := Y1;
-    e_LineCorrection(nX1, nY1, nX2, nY2);
-    glVertex2i(nX1, nY1);
-    glVertex2i(nX2, nY2);
+  glBegin(GL_LINE_LOOP);
+    glVertex2f(X1 + 0.5, Y1 + 0.5);
+    glVertex2f(X2 + 0.5, Y1 + 0.5);
+    glVertex2f(X2 + 0.5, Y2 + 0.5);
+    glVertex2f(X1 + 0.5, Y2 + 0.5);
   glEnd();
 
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
@@ -755,6 +765,7 @@ end;
 procedure e_DrawFillQuad(X1, Y1, X2, Y2: Integer; Red, Green, Blue, Alpha: Byte;
                          Blending: TBlending = B_NONE);
 begin
+  if e_NoGraphics then Exit;
   if (Alpha > 0) or (Blending <> B_NONE) then
     glEnable(GL_BLEND)
   else
@@ -792,9 +803,10 @@ end;
 
 procedure e_DrawLine(Width: Byte; X1, Y1, X2, Y2: Integer; Red, Green, Blue: Byte; Alpha: Byte = 0);
 begin
+  if e_NoGraphics then Exit;
   // Pixel-perfect lines
-  if Width = 1 then
-    e_LineCorrection(X1, Y1, X2, Y2);
+  //if Width = 1 then
+  //  e_LineCorrection(X1, Y1, X2, Y2);
 
   if Alpha > 0 then
   begin
@@ -822,10 +834,11 @@ end;
 //------------------------------------------------------------------
 procedure e_DeleteTexture(ID: DWORD);
 begin
-  glDeleteTextures(1, @e_Textures[ID].ID);
-  e_Textures[ID].ID := 0;
-  e_Textures[ID].Width := 0;
-  e_Textures[ID].Height := 0;
+  if not e_NoGraphics then
+    glDeleteTextures(1, @e_Textures[ID].tx.id);
+  e_Textures[ID].tx.id := 0;
+  e_Textures[ID].tx.Width := 0;
+  e_Textures[ID].tx.Height := 0;
 end;
 
 //------------------------------------------------------------------
@@ -838,7 +851,7 @@ begin
  if e_Textures = nil then Exit;
 
  for i := 0 to High(e_Textures) do
-  if e_Textures[i].Width <> 0 then e_DeleteTexture(i);
+  if e_Textures[i].tx.Width <> 0 then e_DeleteTexture(i);
  e_Textures := nil;
 end;
 
@@ -853,196 +866,29 @@ end;
 
 procedure e_BeginRender();
 begin
+  if e_NoGraphics then Exit;
   glEnable(GL_ALPHA_TEST);
   glAlphaFunc(GL_GREATER, 0.0);
 end;
 
-procedure e_Clear(Mask: TGLbitfield; Red, Green, Blue: Single);
-begin
- glClearColor(Red, Green, Blue, 0);
- glClear(Mask);
-end;
-
-procedure e_EndRender();
-begin
-  glPopMatrix();
-end;
-
-procedure e_MakeScreenshot(FileName: String; Width, Height: Word);
-type
-  aRGB  = Array [0..1] of TRGB;
-  PaRGB = ^aRGB;
-
-  TByteArray = Array [0..1] of Byte;
-  PByteArray = ^TByteArray;
-
-var
-  FILEHEADER: BITMAPFILEHEADER;
-  INFOHEADER: BITMAPINFOHEADER;
-  pixels: PByteArray;
-  tmp:    Byte;
-  i:      Integer;
-  F:      File of Byte;
-
-begin
-  if (Width mod 4) > 0 then
-    Width := Width + 4 - (Width mod 4);
-
-  GetMem(pixels, Width*Height*3);
-  glReadPixels(0, 0, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
-
-  {$R-}
-  for i := 0 to Width * Height - 1 do
-    with PaRGB(pixels)[i] do
-    begin
-      tmp := R;
-      R := B;
-      B := tmp;
-    end;
-  {$R+}
-
-  with FILEHEADER do
-  begin
-    bfType := $4D42; // "BM"
-    bfSize := Width*Height*3 + SizeOf(BITMAPFILEHEADER) + SizeOf(BITMAPINFOHEADER);
-    bfReserved1 := 0;
-    bfReserved2 := 0;
-    bfOffBits := SizeOf(BITMAPFILEHEADER) + SizeOf(BITMAPINFOHEADER);
-  end;
-
-  with INFOHEADER do
-  begin
-    biSize := SizeOf(BITMAPINFOHEADER);
-    biWidth := Width;
-    biHeight := Height;
-    biPlanes := 1;
-    biBitCount := 24;
-    biCompression := 0;
-    biSizeImage := Width*Height*3;
-    biXPelsPerMeter := 0;
-    biYPelsPerMeter := 0;
-    biClrUsed := 0;
-    biClrImportant := 0;
-  end;
-
-  AssignFile(F, FileName);
-  Rewrite(F);
-
-  BlockWrite(F, FILEHEADER, SizeOf(FILEHEADER));
-  BlockWrite(F, INFOHEADER, SizeOf(INFOHEADER));
-  BlockWrite(F, pixels[0], Width*Height*3);
-
-  CloseFile(F);
-
-  FreeMem(pixels);
-end;
-
-function e_GetGamma(DC: HDC): Byte;
-var
-  ramp: array [0..256*3-1] of Word;
-  rgb: array [0..2] of Double;
-  sum: double;
-  count: integer;
-  min: integer;
-  max: integer;
-  A, B: double;
-  i, j: integer;
-begin
- rgb[0] := 1.0;
- rgb[1] := 1.0;
- rgb[2] := 1.0;
-
- GetDeviceGammaRamp(DC, ramp);
-
- for i := 0 to 2 do
- begin
-  sum := 0;
-  count := 0;
-  min := 256 * i;
-  max := min + 256;
-
-  for j := min to max - 1 do
-  if ramp[j] > 0 then
-  begin
-   B := (j mod 256)/256;
-   A := ramp[j]/65536;
-   sum := sum + ln(A)/ln(B);
-   inc(count);
-  end;
-  rgb[i] := sum / count;
- end;
-
- Result := 100 - Trunc(((rgb[0] + rgb[1] + rgb[2])/3 - 0.23) * 100/(2.7 - 0.23));
-end;
-
-procedure e_SetGamma(Gamma: Byte; DC: HDC);
-var
-  ramp: array [0..256*3-1] of Word;
-  i: integer;
-  r: double;
-  g: double;
-begin
- g := (100 - Gamma)*(2.7 - 0.23)/100 + 0.23;
-
- for i := 0 to 255 do
- begin
-  r := Exp(g * ln(i/256))*65536;
-  if r < 0 then r := 0
-   else if r > 65535 then r := 65535;
-  ramp[i] := trunc(r);
-  ramp[i + 256] := trunc(r);
-  ramp[i + 512] := trunc(r);
- end;
-
- SetDeviceGammaRamp(DC, ramp);
-end;
-
-function e_SimpleFontCreate(FontName: PChar; Size: Byte; Weight: Word; DC: HDC): DWORD;
-var
- font: HFONT;
-begin
- Result := glGenLists(96);                           // Generate enough display lists to hold
- font := CreateFont(-Size,                             // height of font
-                    0,                             // average character width
-                    0,                             // angle of escapement
-                               0,                             // base-line orientation angle
-                               Weight,                       // font weight
-                    0,                             // italic
-                               0,                             // underline
-                               0,                                  // strikeout
-                               RUSSIAN_CHARSET,               // character set
-                               OUT_TT_PRECIS,              // output precision
-                    CLIP_DEFAULT_PRECIS,           // clipping precision
-                    ANTIALIASED_QUALITY,           // output quality
-                               FF_DONTCARE or DEFAULT_PITCH,  // pitch and family
-                               FontName);                      // font
- SelectObject(DC, font);                   // Sets the new font as the current font in the device context
- wglUseFontBitmaps(DC, 32, 224, Result); // Creates a set display lists containing the bitmap fonts
-end;
-
-procedure e_SimpleFontFree(Font: DWORD);
+procedure e_Clear(Mask: TGLbitfield; Red, Green, Blue: Single); overload;
 begin
- glDeleteLists(Font, 223);             // Delete the font display lists, returning used memory
+  if e_NoGraphics then Exit;
+  glClearColor(Red, Green, Blue, 0);
+  glClear(Mask);
 end;
 
-procedure e_SimpleFontPrint(X, Y: SmallInt; Text: PChar; Font: Integer; Red, Green, Blue: Byte);
+procedure e_Clear(); overload;
 begin
- glPopAttrib(); // Rendering bug workaround
-
- glColor3ub(Red, Green, Blue);
- glDisable(GL_TEXTURE_2D);     // Turn off textures, don't want our text textured
- glRasterPos2i(X, Y);                                // Position the Text
- glPushAttrib(GL_LIST_BIT);                          // Save's the current base list
-  glListBase(DWORD(Font-32));                              // Set the base list to our character list
-  glCallLists(Length(Text), GL_UNSIGNED_BYTE, Text);  // Display the text
- glPopAttrib();                                     // Restore the old base list
+  if e_NoGraphics then Exit;
+  glClearColor(0, 0, 0, 0);
+  glClear(GL_COLOR_BUFFER_BIT);
 end;
 
-procedure e_SimpleFontPrintEx(X, Y: SmallInt; Text: PChar; Font: DWORD; Red, Green, Blue,
-                      sRed, sGreen, sBlue, sWidth: Byte);
+procedure e_EndRender();
 begin
e_SimpleFontPrint(X, Y, Text, Font, Red, Green, Blue);
e_SimpleFontPrint(X+sWidth, Y+sWidth, Text, Font, sRed, sGreen, sBlue);
 if e_NoGraphics then Exit;
 glPopMatrix();
 end;
 
 function e_CharFont_Create(sp: ShortInt=0): DWORD;
@@ -1096,6 +942,7 @@ procedure e_CharFont_Print(FontID: DWORD; X, Y: Integer; Text: string);
 var
   a: Integer;
 begin
+ if e_NoGraphics then Exit;
  if Text = '' then Exit;
  if e_CharFonts = nil then Exit;
  if Integer(FontID) > High(e_CharFonts) then Exit;
@@ -1118,6 +965,7 @@ var
   a: Integer;
   c: TRGB;
 begin
+ if e_NoGraphics then Exit;
  if Text = '' then Exit;
  if e_CharFonts = nil then Exit;
  if Integer(FontID) > High(e_CharFonts) then Exit;
@@ -1152,6 +1000,7 @@ var
   tc, c: TRGB;
   w, h: Word;
 begin
+  if e_NoGraphics then Exit;
   if Text = '' then Exit;
   if e_CharFonts = nil then Exit;
   if Integer(FontID) > High(e_CharFonts) then Exit;
@@ -1356,18 +1205,19 @@ begin
  if e_CharFonts = nil then Exit;
 
  for a := 0 to High(e_CharFonts) do
-  e_CharFont_Remove(a); 
+  e_CharFont_Remove(a);
 
  e_CharFonts := nil;
 end;
 
-procedure e_TextureFontBuild(Texture: DWORD; var FontID: DWORD; XCount, YCount: Word;
+procedure e_TextureFontBuild(Tex: DWORD; var FontID: DWORD; XCount, YCount: Word;
                              Space: ShortInt=0);
 var
   loop1 : GLuint;
   cx, cy : real;
   i, id: DWORD;
 begin
+ if e_NoGraphics then Exit;
  e_WriteLog('Creating texture font...', MSG_NOTIFY);
 
  id := DWORD(-1);
@@ -1389,33 +1239,37 @@ begin
  with e_TextureFonts[id] do
  begin
   Base := glGenLists(XCount*YCount);
-  TextureID := e_Textures[Texture].ID;
-  CharWidth := (e_Textures[Texture].Width div XCount)+Space;
-  CharHeight := e_Textures[Texture].Height div YCount;
+  TextureID := e_Textures[Tex].tx.id;
+  CharWidth := (e_Textures[Tex].tx.Width div XCount)+Space;
+  CharHeight := e_Textures[Tex].tx.Height div YCount;
+  XC := XCount;
+  YC := YCount;
+  Texture := Tex;
+  SPC := Space;
  end;
- glBindTexture(GL_TEXTURE_2D, e_Textures[Texture].ID);
+
+ glBindTexture(GL_TEXTURE_2D, e_Textures[Tex].tx.id);
  for loop1 := 0 to XCount*YCount-1 do
  begin
   cx := (loop1 mod XCount)/XCount;
-       cy := (loop1 div YCount)/YCount;
+  cy := (loop1 div YCount)/YCount;
 
-       glNewList(e_TextureFonts[id].Base+loop1, GL_COMPILE);
-        glBegin(GL_QUADS);
+  glNewList(e_TextureFonts[id].Base+loop1, GL_COMPILE);
+   glBegin(GL_QUADS);
     glTexCoord2f(cx, 1.0-cy-1/YCount);
-    glVertex2d(0, e_Textures[Texture].Height div YCount);
+    glVertex2d(0, e_Textures[Tex].tx.Height div YCount);
 
-         glTexCoord2f(cx+1/XCount, 1.0-cy-1/YCount);
-    glVertex2i(e_Textures[Texture].Width div XCount, e_Textures[Texture].Height div YCount);
+    glTexCoord2f(cx+1/XCount, 1.0-cy-1/YCount);
+    glVertex2i(e_Textures[Tex].tx.Width div XCount, e_Textures[Tex].tx.Height div YCount);
 
-               glTexCoord2f(cx+1/XCount, 1.0-cy);
-    glVertex2i(e_Textures[Texture].Width div XCount, 0);
+    glTexCoord2f(cx+1/XCount, 1.0-cy);
+    glVertex2i(e_Textures[Tex].tx.Width div XCount, 0);
 
-               glTexCoord2f(cx, 1.0-cy);
+    glTexCoord2f(cx, 1.0-cy);
     glVertex2i(0, 0);
    glEnd();
-        glTranslated((e_Textures[Texture].Width div XCount)+Space, 0, 0);
-       glEndList();
+   glTranslated((e_Textures[Tex].tx.Width div XCount)+Space, 0, 0);
+  glEndList();
  end;
 
  FontID := id;
@@ -1423,12 +1277,14 @@ end;
 
 procedure e_TextureFontKill(FontID: DWORD);
 begin
-       glDeleteLists(e_TextureFonts[FontID].Base, 256);
+  if e_NoGraphics then Exit;
+  glDeleteLists(e_TextureFonts[FontID].Base, 256);
   e_TextureFonts[FontID].Base := 0;
 end;
 
 procedure e_TextureFontPrint(X, Y: GLint; Text: string; FontID: DWORD);
 begin
+  if e_NoGraphics then Exit;
   if Integer(FontID) > High(e_TextureFonts) then Exit;
   if Text = '' then Exit;
 
@@ -1452,6 +1308,7 @@ end;
 // god forgive me for this, but i cannot figure out how to do it without lists
 procedure e_TextureFontPrintChar(X, Y: Integer; Ch: Char; FontID: DWORD; Shadow: Boolean = False);
 begin
+  if e_NoGraphics then Exit;
   glPushMatrix;
 
   if Shadow then
@@ -1470,12 +1327,31 @@ begin
   glPopMatrix;
 end;
 
+procedure e_TextureFontPrintCharEx (X, Y: Integer; Ch: Char; FontID: DWORD; Shadow: Boolean = False);
+begin
+  glBindTexture(GL_TEXTURE_2D, e_TextureFonts[FontID].TextureID);
+  glEnable(GL_TEXTURE_2D);
+  //glListBase(DWORD(Integer(e_TextureFonts[FontID].Base)-32));
+
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  glEnable(GL_BLEND);
+  e_TextureFontPrintChar(X, Y, Ch, FontID, Shadow);
+  glDisable(GL_TEXTURE_2D);
+  glDisable(GL_BLEND);
+end;
+
+function e_TextureFontCharWidth (ch: Char; FontID: DWORD): Integer;
+begin
+  result := e_TextureFonts[FontID].CharWidth;
+end;
+
 procedure e_TextureFontPrintFmt(X, Y: Integer; Text: string; FontID: DWORD; Shadow: Boolean = False);
 var
   a, TX, TY, len: Integer;
   tc, c: TRGB;
   w: Word;
 begin
+  if e_NoGraphics then Exit;
   if Text = '' then Exit;
   if e_TextureFonts = nil then Exit;
   if Integer(FontID) > High(e_TextureFonts) then Exit;
@@ -1565,6 +1441,7 @@ end;
 procedure e_TextureFontPrintEx(X, Y: GLint; Text: string; FontID: DWORD; Red, Green,
                     Blue: Byte; Scale: Single; Shadow: Boolean = False);
 begin
+  if e_NoGraphics then Exit;
   if Text = '' then Exit;
 
   glPushMatrix;
@@ -1598,6 +1475,9 @@ end;
 
 procedure e_TextureFontGetSize(ID: DWORD; var CharWidth, CharHeight: Byte);
 begin
+  CharWidth := 16;
+  CharHeight := 16;
+  if e_NoGraphics then Exit;
   if Integer(ID) > High(e_TextureFonts) then
     Exit;
   CharWidth := e_TextureFonts[ID].CharWidth;
@@ -1608,6 +1488,7 @@ procedure e_RemoveAllTextureFont();
 var
  i: integer;
 begin
+ if e_NoGraphics then Exit;
  if e_TextureFonts = nil then Exit;
 
  for i := 0 to High(e_TextureFonts) do
@@ -1641,6 +1522,12 @@ begin
  Result.Height := Height;
 end;
 
+function _TRect(L, T, R, B: LongInt): TRect;
+begin
+ Result.Top := T;
+ Result.Left := L;
+ Result.Right := R;
+ Result.Bottom := B;
+end;
 
 end.
-
index 9dd9192c6128331dac154c196071e97afcac172c..e6246bcc0f833de66dd39080ce5893b272d2f8ad 100644 (file)
@@ -1,3 +1,19 @@
+(* Copyright (C)  DooM 2D:Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$MODE DELPHI}
 unit e_textures;
 
 { This unit provides interface to load 24-bit and 32-bit uncompressed images
@@ -7,53 +23,98 @@ unit e_textures;
 interface
 
 uses
-  Windows, dglOpenGL, SysUtils, e_log;
+  GL, GLExt, SysUtils, e_log,
+  ImagingTypes, Imaging, ImagingUtility;
+
+type
+  GLTexture = record
+    id: GLuint;
+    width, height: Word; // real
+    glwidth, glheight: Word; // powerof2
+    u, v: Single; // usually 1.0
+    fmt: GLuint;
+  end;
 
 var
-  fUseMipmaps: Boolean = False;
+  e_DummyTextures: Boolean = False;
+  e_glLegacyNPOT: Boolean = False;
   TEXTUREFILTER: Integer = GL_NEAREST;
 
-// Standard set of images loading functions
-function LoadTexture( Filename: String; var Texture: GLuint;
-                      var pWidth, pHeight: Word ): Boolean;
+function CreateTexture (var tex: GLTexture; Width, Height, aFormat: Word; pData: Pointer): Boolean;
 
-function LoadTextureEx( Filename: String; var Texture: GLuint;
-                        fX, fY, fWidth, fHeight: Word ): Boolean;
+// Standard set of images loading functions
+function LoadTexture (Filename: String; var Texture: GLTexture; var pWidth, pHeight: Word; Fmt: PWord=nil): Boolean;
+function LoadTextureEx (Filename: String; var Texture: GLTexture; fX, fY, fWidth, fHeight: Word; Fmt: PWord=nil): Boolean;
+function LoadTextureMem (pData: Pointer; dataSize: LongInt; var Texture: GLTexture; var pWidth, pHeight: Word; Fmt: PWord=nil): Boolean;
+function LoadTextureMemEx (pData: Pointer; dataSize: LongInt; var Texture: GLTexture; fX, fY, fWidth, fHeight: Word; Fmt: PWord=nil): Boolean;
 
-function LoadTextureMem( pData: Pointer; var Texture: GLuint;
-                         var pWidth, pHeight: Word ): Boolean;
+// `img` must be valid!
+function LoadTextureImg (var img: TImageData; var Texture: GLTexture; var pWidth, pHeight: Word; Fmt: PWord=nil): Boolean;
 
-function LoadTextureMemEx( pData: Pointer; var Texture: GLuint;
-                           fX, fY, fWidth, fHeight: Word ): Boolean;
 
 implementation
 
-type
-  TTGAHeader = packed record
-    FileType:     Byte;
-    ColorMapType: Byte;
-    ImageType:    Byte;
-    ColorMapSpec: array[0..4] of Byte;
-    OrigX:        array[0..1] of Byte;
-    OrigY:        array[0..1] of Byte;
-    Width:        array[0..1] of Byte;
-    Height:       array[0..1] of Byte;
-    BPP:          Byte;
-    ImageInfo:    Byte;
-  end;
+uses
+  Classes, BinEditor, utils;
+
+
+function AlignP2 (n: Word): Word;
+begin
+  Dec(n);
+  n := n or (n shr 1);
+  n := n or (n shr 2);
+  n := n or (n shr 4);
+  n := n or (n shr 8);
+  n := n or (n shr 16);
+  Inc(n);
+  Result := n;
+end;
+
 
 // This is auxiliary function that creates OpenGL texture from raw image data
-function CreateTexture( Width, Height, Format: Word; pData: Pointer ): Integer;
+function CreateTexture (var tex: GLTexture; Width, Height, aFormat: Word; pData: Pointer): Boolean;
 var
   Texture: GLuint;
+  fmt: GLenum;
+  buf: PByte;
+  f, c: Integer;
 begin
-  glGenTextures( 1, @Texture );
-  glBindTexture( GL_TEXTURE_2D, Texture );
+  tex.width := Width;
+  tex.height := Height;
+  tex.glwidth := Width;
+  tex.glheight := Height;
+  tex.u := 1;
+  tex.v := 1;
+
+  if e_glLegacyNPOT then
+  begin
+    tex.glwidth := AlignP2(Width);
+    tex.glheight := AlignP2(Height);
+    if tex.glwidth <> tex.width then tex.u := (tex.width+0.0)/(tex.glwidth+0.0);
+    if tex.glheight <> tex.height then tex.v := (tex.height+0.0)/(tex.glheight+0.0);
+  end;
 
-    {Texture blends with object background}
-  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-    {Texture does NOT blend with object background}
- // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+  //if (tex.glwidth <> tex.width) or (tex.glheight <> tex.height) then
+  //  e_WriteLog(Format('NPOT: orig is %ux%u; gl is %ux%u; u=%f; v=%f', [Width, Height, tex.glwidth, tex.glheight, tex.u, tex.v]), MSG_NOTIFY);
+
+  if e_DummyTextures then
+  begin
+    tex.id := GLuint(-1);
+    Result := True;
+    Exit;
+  end;
+
+  glGenTextures(1, @Texture);
+  tex.id := Texture;
+  glBindTexture(GL_TEXTURE_2D, Texture);
+
+  if (tex.glwidth <> tex.width) or (tex.glheight <> tex.height) then
+    e_WriteLog(Format('NPOT: %u is %ux%u; gl is %ux%u; u=%f; v=%f', [tex.id, Width, Height, tex.glwidth, tex.glheight, tex.u, tex.v]), MSG_NOTIFY);
+
+  // texture blends with object background
+  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+  // texture does NOT blend with object background
+  //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 
   {
     Select a filtering type.
@@ -66,370 +127,249 @@ begin
   }
 
   // for GL_TEXTURE_MAG_FILTER only first two can be used
-  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXTUREFILTER );
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, TEXTUREFILTER);
   // for GL_TEXTURE_MIN_FILTER all of the above can be used
-  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXTUREFILTER );
-
-  if Format = GL_RGBA then
-  begin
-    if fUseMipmaps then
-      gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, Width, Height, GL_RGBA,
-                         GL_UNSIGNED_BYTE, pData )
-    else
-      glTexImage2D( GL_TEXTURE_2D, 0, 4, Width, Height,
-                    0, GL_RGBA, GL_UNSIGNED_BYTE, pData );
-  end else
-  begin
-    if fUseMipmaps then
-      gluBuild2DMipmaps( GL_TEXTURE_2D, 3, Width, Height, GL_RGB,
-                         GL_UNSIGNED_BYTE, pData )
-    else
-      glTexImage2D( GL_TEXTURE_2D, 0, 3, Width, Height,
-                    0, GL_RGB, GL_UNSIGNED_BYTE, pData );
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, TEXTUREFILTER);
+
+  // create empty texture
+  if aFormat = GL_RGBA then fmt := GL_RGBA else fmt := GL_RGB; // silly, yeah?
+  glTexImage2D(GL_TEXTURE_2D, 0, fmt, tex.glwidth, tex.glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
+
+  (*
+  GetMem(buf, tex.glwidth*4*tex.glheight);
+  try
+    FillChar(buf^, tex.glwidth*4*tex.glheight, 255);
+    glTexSubImage2D(GL_TEXTURE_2D, 0,  0, 0, tex.glwidth, tex.glheight, fmt, GL_UNSIGNED_BYTE, buf);
+    if (tex.glheight = 128) and (tex.height = 80) then
+    begin
+      for f := 0 to tex.glheight-1 do
+      begin
+        for c := 0 to tex.glwidth-1 do
+        begin
+          buf[f*(tex.glwidth*4)+c*4+0] := 255;
+          buf[f*(tex.glwidth*4)+c*4+1] := 127;
+          buf[f*(tex.glwidth*4)+c*4+2] := 0;
+        end;
+      end;
+      glTexSubImage2D(GL_TEXTURE_2D, 0,  0, 82, tex.glwidth, {tex.glheight}1, fmt, GL_UNSIGNED_BYTE, buf);
+    end;
+  finally
+    FreeMem(buf);
   end;
+  *)
 
-  Result := Texture;
+  glTexSubImage2D(GL_TEXTURE_2D, 0,  0, 0, Width, Height, fmt, GL_UNSIGNED_BYTE, pData);
+  //glTexSubImage2D(GL_TEXTURE_2D, 0,  0, tex.glheight-tex.height, Width, Height, fmt, GL_UNSIGNED_BYTE, pData);
+
+  glBindTexture(GL_TEXTURE_2D, 0);
+
+  Result := true;
 end;
 
-function LoadTextureMem( pData: Pointer; var Texture: GLuint;
-                         var pWidth, pHeight: Word ): Boolean;
+// `img` must be valid!
+function LoadTextureImg (var img: TImageData; var Texture: GLTexture; var pWidth, pHeight: Word; Fmt: PWord=nil): Boolean;
 var
-  TGAHeader:     TTGAHeader;
-  image:         Pointer;
-  Width, Height: Integer;
-  ImageSize:     Integer;
-  i:             Integer;
-  Front:         ^Byte;
-  Back:          ^Byte;
-  Temp:          Byte;
-  BPP:           Byte;
-
+  image, ii: PByte;
+  width, height: Integer;
+  imageSize: Integer;
+  x, y: Integer;
+  clr: TColor32Rec;
 begin
-  Result := False;
+  result := false;
   pWidth := 0;
   pHeight := 0;
+  if Fmt <> nil then Fmt^ := GL_RGBA; // anyway
 
-  CopyMemory( @TGAHeader, pData, SizeOf(TGAHeader) );
-
-  if ( TGAHeader.ImageType <> 2 ) then
+  if (img.width < 1) or (img.width > 32768) or (img.height < 1) or (img.height > 32768) then
   begin
-    e_WriteLog( 'Error loading texture: Bad ImageType', MSG_WARNING );
-    Exit;
+    e_WriteLog('Error loading texture: invalid image dimensions', MSG_WARNING);
+    exit;
   end;
-
-  if ( TGAHeader.ColorMapType <> 0 ) then
-  begin
-    e_WriteLog( 'Error loading texture: Bad ColorMapType', MSG_WARNING );
-    Exit;
+  //ConvertImage(img, ifA8R8G8B8);
+  width := img.width;
+  height := img.height;
+  pWidth := width;
+  pHeight := height;
+  imageSize := Width*Height*4;
+  GetMem(image, imageSize);
+  try
+    // it's slow, but i don't care for now
+    ii := image;
+    for y := height-1 downto 0 do
+    begin
+      for x := 0 to width-1 do
+      begin
+        clr := GetPixel32(img, x, y);
+        ii^ := clr.r; Inc(ii);
+        ii^ := clr.g; Inc(ii);
+        ii^ := clr.b; Inc(ii);
+        ii^ := clr.a; Inc(ii);
+      end;
+    end;
+    CreateTexture(Texture, width, height, GL_RGBA, image);
+    result := true;
+  finally
+    FreeMem(image);
   end;
-
-  if ( TGAHeader.BPP < 24 ) then
-  begin
-    e_WriteLog( 'Error loading texture: BPP less than 24', MSG_WARNING );
-    Exit;
-  end;
-
-  Width  := TGAHeader.Width[0]  + TGAHeader.Width[1]  * 256;
-  Height := TGAHeader.Height[0] + TGAHeader.Height[1] * 256;
-  BPP := TGAHeader.BPP;
-
-  ImageSize := Width * Height * (BPP div 8);
-
-  GetMem( Image, ImageSize );
-  CopyMemory( Image, Pointer( Integer(pData) + SizeOf(TGAHeader) ), ImageSize );
-
-  for i := 0 to Width * Height - 1 do
-  begin
-    Front := Pointer( Integer(Image) + i*(BPP div 8) );
-    Back  := Pointer( Integer(Image) + i*(BPP div 8) + 2 );
-    Temp   := Front^;
-    Front^ := Back^;
-    Back^  := Temp;
-  end;
-
-  if ( BPP = 24 ) then
-    Texture := CreateTexture( Width, Height, GL_RGB, Image )
-  else
-    Texture := CreateTexture( Width, Height, GL_RGBA, Image );
-
-  FreeMem( Image );
-
-  pWidth := Width;
-  pHeight := Height;
-
-  Result := True;
 end;
 
-function LoadTextureMemEx( pData: Pointer; var Texture: GLuint;
-                           fX, fY, fWidth, fHeight: Word ): Boolean;
-var
-  TGAHeader:     TTGAHeader;
-  image, image2: Pointer;
-  Width, Height: Integer;
-  ImageSize:     Integer;
-  i, a, b:       Integer;
-  Front:         ^Byte;
-  Back:          ^Byte;
-  Temp:          Byte;
-  BPP:           Byte;
-  Base:          Integer;
 
+function LoadTextureMem (pData: Pointer; dataSize: LongInt; var Texture: GLTexture; var pWidth, pHeight: Word; Fmt: PWord=nil): Boolean;
+var
+  image, ii: PByte;
+  width, height: Integer;
+  imageSize: Integer;
+  img: TImageData;
+  x, y: Integer;
+  clr: TColor32Rec;
 begin
-  Result := False;
-
-  CopyMemory( @TGAHeader, pData, SizeOf(TGAHeader) );
-
-  if ( TGAHeader.ImageType <> 2 ) then
-  begin
-    e_WriteLog( 'Error loading texture: Bad ImageType', MSG_WARNING );
-    Exit;
-  end;
+  result := false;
+  pWidth := 0;
+  pHeight := 0;
+  if Fmt <> nil then Fmt^ := GL_RGBA; // anyway
 
-  if ( TGAHeader.ColorMapType <> 0 ) then
+  InitImage(img);
+  if not LoadImageFromMemory(pData, dataSize, img) then
   begin
-    e_WriteLog( 'Error loading texture: Bad ColorMapType', MSG_WARNING );
-    Exit;
+    e_WriteLog('Error loading texture: unknown image format', MSG_WARNING);
+    exit;
   end;
-
-  if ( TGAHeader.BPP < 24 ) then
-  begin
-    e_WriteLog( 'Error loading texture: BPP less than 24', MSG_WARNING );
-    Exit;
+  try
+    result := LoadTextureImg(img, Texture, pWidth, pHeight, Fmt);
+  finally
+    FreeImage(img);
   end;
+end;
 
-  Width  := TGAHeader.Width[0]  + TGAHeader.Width[1]  * 256;
-  Height := TGAHeader.Height[0] + TGAHeader.Height[1] * 256;
-  BPP := TGAHeader.BPP;
-
-  if fX > Width then Exit;
-  if fY > Height then Exit;
-  if fX+fWidth > Width then Exit;
-  if fY+fHeight > Height then Exit;
-
-  ImageSize := Width * Height * (BPP div 8);
-  GetMem( Image2, ImageSize );
-  CopyMemory( Image2, Pointer( Integer(pData) + SizeOf(TGAHeader) ), ImageSize );
 
-  a := BPP div 8;
+function LoadTextureMemEx (pData: Pointer; dataSize: LongInt; var Texture: GLTexture; fX, fY, fWidth, fHeight: Word; Fmt: PWord=nil): Boolean;
+var
+  image, ii: PByte;
+  width, height: Integer;
+  imageSize: Integer;
+  img: TImageData;
+  x, y: Integer;
+  clr: TColor32Rec;
+begin
+  result := false;
+  if Fmt <> nil then Fmt^ := GL_RGBA; // anyway
 
-  for i := 0 to Width * Height - 1 do
+  InitImage(img);
+  if not LoadImageFromMemory(pData, dataSize, img) then
   begin
-    Front := Pointer( Integer(Image2) + i * a );
-    Back  := Pointer( Integer(Image2) + i * a + 2 );
-    Temp   := Front^;
-    Front^ := Back^;
-    Back^  := Temp;
+    e_WriteLog('Error loading texture: unknown image format', MSG_WARNING);
+    exit;
+  end;
+  try
+    if (img.width < 1) or (img.width > 32768) or (img.height < 1) or (img.height > 32768) then
+    begin
+      e_WriteLog('Error loading texture: invalid image dimensions', MSG_WARNING);
+      exit;
+    end;
+    //ConvertImage(img, ifA8R8G8B8);
+    if fX > img.width then exit;
+    if fY > img.height then exit;
+    if fX+fWidth > img.width then exit;
+    if fY+fHeight > img.height then exit;
+    //writeln('fX=', fX, '; fY=', fY, '; fWidth=', fWidth, '; fHeight=', fHeight);
+    imageSize := img.width*img.height*4;
+    GetMem(image, imageSize);
+    try
+      // it's slow, but i don't care for now
+      ii := image;
+      for y := fY+fHeight-1 downto fY do
+      begin
+        for x := fX to fX+fWidth-1 do
+        begin
+          clr := GetPixel32(img, x, y);
+          ii^ := clr.r; Inc(ii);
+          ii^ := clr.g; Inc(ii);
+          ii^ := clr.b; Inc(ii);
+          ii^ := clr.a; Inc(ii);
+        end;
+      end;
+      CreateTexture(Texture, fWidth, fHeight, GL_RGBA, image);
+      result := true;
+    finally
+      FreeMem(image);
+    end;
+  finally
+    FreeImage(img);
   end;
-
-  fY := Height - (fY + fHeight);
-
-  ImageSize := fHeight * fWidth * (BPP div 8);
-  GetMem( Image, ImageSize );
-
-  Base := Integer( Image2 ) + fY * Width * (BPP div 8) + fX * (BPP div 8);
-  a := fWidth * (BPP div 8);
-  b := Width * (BPP div 8);
-
-  for i := 0 to fHeight-1 do
-    CopyMemory( Pointer( Integer(image) + a*i ), Pointer( Base + b*i ), a );
-
-  if ( BPP = 24 ) then
-    Texture := CreateTexture( fWidth, fHeight, GL_RGB, image )
-  else
-    Texture := CreateTexture( fWidth, fHeight, GL_RGBA, image );
-
-  FreeMem( Image );
-  FreeMem( Image2 );
-
-  Result := True;
 end;
 
-function LoadTexture( Filename: String; var Texture: GLuint;
-                      var pWidth, pHeight: Word ): Boolean;
-var
-  TGAHeader:     TTGAHeader;
-  TGAFile:       File;
-  bytesRead:     Integer;
-  image:         Pointer;
-  Width, Height: Integer;
-  ImageSize:     Integer;
-  i:             Integer;
-  Front:         ^Byte;
-  Back:          ^Byte;
-  Temp:          Byte;
-  BPP:           Byte;
 
+function LoadTexture (filename: AnsiString; var Texture: GLTexture; var pWidth, pHeight: Word; Fmt: PWord=nil): Boolean;
+var
+  fs: TStream;
+  img: Pointer;
+  imageSize: LongInt;
 begin
-  Result := False;
+  result := False;
   pWidth := 0;
   pHeight := 0;
+  if Fmt <> nil then Fmt^ := GL_RGBA; // anyway
+  fs := nil;
 
-  if not FileExists(Filename) then
-  begin
-    e_WriteLog('Texture ' + Filename + ' not found', MSG_WARNING);
-    Exit;
+  try
+    fs := openDiskFileRO(filename);
+  except
+    fs := nil;
   end;
-
-  AssignFile( TGAFile, Filename );
-  Reset( TGAFile, 1 );
-  BlockRead( TGAFile, TGAHeader, SizeOf(TGAHeader) );
-
-  if ( TGAHeader.ImageType <> 2 ) then
+  if fs = nil then
   begin
-    CloseFile( TGAFile );
-    e_WriteLog( 'Error loading texture: Bad ImageType', MSG_WARNING );
-    Exit;
+    e_WriteLog('Texture "'+filename+'" not found', MSG_WARNING);
+    exit;
   end;
 
-  if ( TGAHeader.ColorMapType <> 0 ) then
-  begin
-    CloseFile( TGAFile );
-    e_WriteLog( 'Error loading texture: Bad ColorMapType', MSG_WARNING );
-    Exit;
+  try
+    imageSize := fs.size;
+    GetMem(img, imageSize);
+    try
+      fs.readBuffer(img^, imageSize);
+      result := LoadTextureMem(img, imageSize, Texture, pWidth, pHeight, Fmt);
+    finally
+      FreeMem(img);
+    end;
+  finally
+    fs.Free();
   end;
-
-  if ( TGAHeader.BPP < 24 ) then
-  begin
-    CloseFile( TGAFile );
-    e_WriteLog( 'Error loading texture: BPP less than 24', MSG_WARNING );
-    Exit;
-  end;
-
-  Width  := TGAHeader.Width[0]  + TGAHeader.Width[1]  * 256;
-  Height := TGAHeader.Height[0] + TGAHeader.Height[1] * 256;
-  BPP := TGAHeader.BPP;
-
-  ImageSize := Width * Height * (BPP div 8);
-
-  GetMem( Image, ImageSize );
-
-  BlockRead( TGAFile, image^, ImageSize, bytesRead );
-  if ( bytesRead <> ImageSize ) then
-  begin
-    CloseFile( TGAFile );
-    Exit;
-  end;
-
-  CloseFile( TGAFile );
-
-  for i := 0 to Width * Height - 1 do
-  begin
-    Front := Pointer( Integer(Image) + i * (BPP div 8) );
-    Back  := Pointer( Integer(Image) + i * (BPP div 8) + 2 );
-    Temp   := Front^;
-    Front^ := Back^;
-    Back^  := Temp;
-  end;
-
-  if ( BPP = 24 ) then
-    Texture := CreateTexture( Width, Height, GL_RGB, Image )
-  else
-    Texture := CreateTexture( Width, Height, GL_RGBA, Image );
-
-  FreeMem( Image );
-
-  pWidth := Width;
-  pHeight := Height;
-
-  Result := True;
 end;
 
-function LoadTextureEx( Filename: String; var Texture: GLuint;
-                        fX, fY, fWidth, fHeight: Word ): Boolean;
+
+function LoadTextureEx (filename: AnsiString; var Texture: GLTexture; fX, fY, fWidth, fHeight: Word; Fmt: PWord=nil): Boolean;
 var
-  TGAHeader:     TTGAHeader;
-  TGAFile:       File;
-  image, image2: Pointer;
-  Width, Height: Integer;
-  ImageSize:     Integer;
-  i:             Integer;
-  Front:         ^Byte;
-  Back:          ^Byte;
-  Temp:          Byte;
-  BPP:           Byte;
-  Base:          Integer;
-  
+  fs: TStream;
+  img: Pointer;
+  imageSize: LongInt;
 begin
-  Result := False;
-
-  if not FileExists(Filename) then
-  begin
-    e_WriteLog( 'Texture ' + Filename + ' not found', MSG_WARNING );
-    Exit;
-  end;
-
-  AssignFile( TGAFile, Filename );
-  Reset( TGAFile, 1 );
-  BlockRead( TGAFile, TGAHeader, SizeOf(TGAHeader) );
-
-  if ( TGAHeader.ImageType <> 2 ) then
-  begin
-    CloseFile( TGAFile );
-    e_WriteLog( 'Error loading texture: Bad ImageType', MSG_WARNING );
-    Exit;
-  end;
-
-  if ( TGAHeader.ColorMapType <> 0 ) then
-  begin
-    CloseFile( TGAFile );
-    e_WriteLog( 'Error loading texture: Bad ColorMapType', MSG_WARNING );
-    Exit;
+  result := False;
+  if Fmt <> nil then Fmt^ := GL_RGBA; // anyway
+  fs := nil;
+
+  try
+    fs := openDiskFileRO(filename);
+  except
+    fs := nil;
   end;
-
-  if ( TGAHeader.BPP < 24 ) then
+  if fs = nil then
   begin
-    CloseFile( TGAFile );
-    e_WriteLog( 'Error loading texture: BPP less than 24', MSG_WARNING );
-    Exit;
+    e_WriteLog('Texture "'+filename+'" not found', MSG_WARNING);
+    exit;
   end;
 
-  Width  := TGAHeader.Width[0]  + TGAHeader.Width[1]  * 256;
-  Height := TGAHeader.Height[0] + TGAHeader.Height[1] * 256;
-  BPP := TGAHeader.BPP;
-
-  if fX > Width then Exit;
-  if fY > Height then Exit;
-  if fX+fWidth > Width then Exit;
-  if fY+fHeight > Height then Exit;
-
-  ImageSize := Width * Height * (BPP div 8);
-  GetMem( Image2, ImageSize );
-  BlockRead( TGAFile, Image2^, ImageSize );
-
-  CloseFile( TGAFile );
-
-  for i := 0 to Width * Height - 1 do
-  begin
-    Front := Pointer( Integer(Image2) + i * (BPP div 8) );
-    Back  := Pointer( Integer(Image2) + i * (BPP div 8) + 2 );
-    Temp   := Front^;
-    Front^ := Back^;
-    Back^  := Temp;
+  try
+    imageSize := fs.size;
+    GetMem(img, imageSize);
+    try
+      fs.readBuffer(img^, imageSize);
+      result := LoadTextureMemEx(img, imageSize, Texture, fX, fY, fWidth, fHeight, Fmt);
+    finally
+      FreeMem(img);
+    end;
+  finally
+    fs.Free();
   end;
-
-  fY := Height - (fY + fHeight);
-
-  ImageSize := fHeight * fWidth * (BPP div 8);
-  GetMem( Image, ImageSize );
-
-  Base := Integer(Image2) + fY * Width * (BPP div 8) + fX * (BPP div 8);
-
-  for i := 0 to fHeight-1 do
-  begin
-    CopyMemory( Pointer( Integer(image) + fWidth * (BPP div 8) * i ),
-                Pointer( Base + Width * (BPP div 8) * i), fWidth * (BPP div 8) );
-  end;                                                
-
-  if ( BPP = 24 ) then
-    Texture := CreateTexture( fWidth, fHeight, GL_RGB, Image )
-  else
-    Texture := CreateTexture( fWidth, fHeight, GL_RGBA, Image );
-
-  FreeMem( Image );
-  FreeMem( Image2 );
-
-  Result := True;
 end;
 
 end.
-
diff --git a/src/lib/dgl/GL.pas b/src/lib/dgl/GL.pas
deleted file mode 100644 (file)
index c3eda2f..0000000
+++ /dev/null
@@ -1,2226 +0,0 @@
-(*++ BUILD Version: 0004    // Increment this if a change has global effects
-
-Copyright (c) 1985-96, Microsoft Corporation
-
-Module Name:
-
-    gl.h
-
-Abstract:
-
-    Procedure declarations, constant definitions and macros for the OpenGL
-    component.
-
---*)
-
-(*
-** Copyright 1996 Silicon Graphics, Inc.
-** All Rights Reserved.
-**
-** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
-** the contents of this file may not be disclosed to third parties, copied or
-** duplicated in any form, in whole or in part, without the prior written
-** permission of Silicon Graphics, Inc.
-**
-** RESTRICTED RIGHTS LEGEND:
-** Use, duplication or disclosure by the Government is subject to restrictions
-** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
-** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
-** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
-** rights reserved under the Copyright Laws of the United States.
-*)
-
-{******************************************************************************}
-{ Converted to Delphi by Tom Nuydens (tom@delphi3d.net)                        }
-{ For the latest updates, visit Delphi3D: http://www.delphi3d.net              }
-{******************************************************************************}
-
-unit GL;
-
-interface
-
-uses
-  SysUtils, Windows;
-
-type
-  GLenum     = Cardinal;      PGLenum     = ^GLenum;
-  GLboolean  = Byte;          PGLboolean  = ^GLboolean;
-  GLbitfield = Cardinal;      PGLbitfield = ^GLbitfield;
-  GLbyte     = ShortInt;      PGLbyte     = ^GLbyte;
-  GLshort    = SmallInt;      PGLshort    = ^GLshort;
-  GLint      = Integer;       PGLint      = ^GLint;
-  GLsizei    = Integer;       PGLsizei    = ^GLsizei;
-  GLubyte    = Byte;          PGLubyte    = ^GLubyte;
-  GLushort   = Word;          PGLushort   = ^GLushort;
-  GLuint     = Cardinal;      PGLuint     = ^GLuint;
-  GLfloat    = Single;        PGLfloat    = ^GLfloat;
-  GLclampf   = Single;        PGLclampf   = ^GLclampf;
-  GLdouble   = Double;        PGLdouble   = ^GLdouble;
-  GLclampd   = Double;        PGLclampd   = ^GLclampd;
-{ GLvoid     = void; }        PGLvoid     = Pointer;
-
-{******************************************************************************}
-
-const
-  // Version
-  GL_VERSION_1_1                    = 1;
-
-  // AccumOp
-  GL_ACCUM                          = $0100;
-  GL_LOAD                           = $0101;
-  GL_RETURN                         = $0102;
-  GL_MULT                           = $0103;
-  GL_ADD                            = $0104;
-
-  // AlphaFunction
-  GL_NEVER                          = $0200;
-  GL_LESS                           = $0201;
-  GL_EQUAL                          = $0202;
-  GL_LEQUAL                         = $0203;
-  GL_GREATER                        = $0204;
-  GL_NOTEQUAL                       = $0205;
-  GL_GEQUAL                         = $0206;
-  GL_ALWAYS                         = $0207;
-
-  // AttribMask
-  GL_CURRENT_BIT                    = $00000001;
-  GL_POINT_BIT                      = $00000002;
-  GL_LINE_BIT                       = $00000004;
-  GL_POLYGON_BIT                    = $00000008;
-  GL_POLYGON_STIPPLE_BIT            = $00000010;
-  GL_PIXEL_MODE_BIT                 = $00000020;
-  GL_LIGHTING_BIT                   = $00000040;
-  GL_FOG_BIT                        = $00000080;
-  GL_DEPTH_BUFFER_BIT               = $00000100;
-  GL_ACCUM_BUFFER_BIT               = $00000200;
-  GL_STENCIL_BUFFER_BIT             = $00000400;
-  GL_VIEWPORT_BIT                   = $00000800;
-  GL_TRANSFORM_BIT                  = $00001000;
-  GL_ENABLE_BIT                     = $00002000;
-  GL_COLOR_BUFFER_BIT               = $00004000;
-  GL_HINT_BIT                       = $00008000;
-  GL_EVAL_BIT                       = $00010000;
-  GL_LIST_BIT                       = $00020000;
-  GL_TEXTURE_BIT                    = $00040000;
-  GL_SCISSOR_BIT                    = $00080000;
-  GL_ALL_ATTRIB_BITS                = $000FFFFF;
-
-  // BeginMode
-  GL_POINTS                         = $0000;
-  GL_LINES                          = $0001;
-  GL_LINE_LOOP                      = $0002;
-  GL_LINE_STRIP                     = $0003;
-  GL_TRIANGLES                      = $0004;
-  GL_TRIANGLE_STRIP                 = $0005;
-  GL_TRIANGLE_FAN                   = $0006;
-  GL_QUADS                          = $0007;
-  GL_QUAD_STRIP                     = $0008;
-  GL_POLYGON                        = $0009;
-
-  // BlendingFactorDest
-  GL_ZERO                           = 0;
-  GL_ONE                            = 1;
-  GL_SRC_COLOR                      = $0300;
-  GL_ONE_MINUS_SRC_COLOR            = $0301;
-  GL_SRC_ALPHA                      = $0302;
-  GL_ONE_MINUS_SRC_ALPHA            = $0303;
-  GL_DST_ALPHA                      = $0304;
-  GL_ONE_MINUS_DST_ALPHA            = $0305;
-
-  // BlendingFactorSrc
-  //      GL_ZERO
-  //      GL_ONE
-  GL_DST_COLOR                      = $0306;
-  GL_ONE_MINUS_DST_COLOR            = $0307;
-  GL_SRC_ALPHA_SATURATE             = $0308;
-  //      GL_SRC_ALPHA
-  //      GL_ONE_MINUS_SRC_ALPHA
-  //      GL_DST_ALPHA
-  //      GL_ONE_MINUS_DST_ALPHA
-
-  // Boolean
-  GL_TRUE                           = 1;
-  GL_FALSE                          = 0;
-
-  // ClearBufferMask
-  //      GL_COLOR_BUFFER_BIT
-  //      GL_ACCUM_BUFFER_BIT
-  //      GL_STENCIL_BUFFER_BIT
-  //      GL_DEPTH_BUFFER_BIT
-
-  // ClientArrayType
-  //      GL_VERTEX_ARRAY
-  //      GL_NORMAL_ARRAY
-  //      GL_COLOR_ARRAY
-  //      GL_INDEX_ARRAY
-  //      GL_TEXTURE_COORD_ARRAY
-  //      GL_EDGE_FLAG_ARRAY
-
-  // ClipPlaneName
-  GL_CLIP_PLANE0                    = $3000;
-  GL_CLIP_PLANE1                    = $3001;
-  GL_CLIP_PLANE2                    = $3002;
-  GL_CLIP_PLANE3                    = $3003;
-  GL_CLIP_PLANE4                    = $3004;
-  GL_CLIP_PLANE5                    = $3005;
-
-  // ColorMaterialFace
-  //      GL_FRONT
-  //      GL_BACK
-  //      GL_FRONT_AND_BACK
-
-  // ColorMaterialParameter
-  //      GL_AMBIENT
-  //      GL_DIFFUSE
-  //      GL_SPECULAR
-  //      GL_EMISSION
-  //      GL_AMBIENT_AND_DIFFUSE
-
-  // ColorPointerType
-  //      GL_BYTE
-  //      GL_UNSIGNED_BYTE
-  //      GL_SHORT
-  //      GL_UNSIGNED_SHORT
-  //      GL_INT
-  //      GL_UNSIGNED_INT
-  //      GL_FLOAT
-  //      GL_DOUBLE
-
-  // CullFaceMode
-  //      GL_FRONT
-  //      GL_BACK
-  //      GL_FRONT_AND_BACK
-
-  // DataType
-  GL_BYTE                           = $1400;
-  GL_UNSIGNED_BYTE                  = $1401;
-  GL_SHORT                          = $1402;
-  GL_UNSIGNED_SHORT                 = $1403;
-  GL_INT                            = $1404;
-  GL_UNSIGNED_INT                   = $1405;
-  GL_FLOAT                          = $1406;
-  GL_2_BYTES                        = $1407;
-  GL_3_BYTES                        = $1408;
-  GL_4_BYTES                        = $1409;
-  GL_DOUBLE                         = $140A;
-
-  // DepthFunction
-  //      GL_NEVER
-  //      GL_LESS
-  //      GL_EQUAL
-  //      GL_LEQUAL
-  //      GL_GREATER
-  //      GL_NOTEQUAL
-  //      GL_GEQUAL
-  //      GL_ALWAYS
-
-  // DrawBufferMode
-  GL_NONE                           = 0;
-  GL_FRONT_LEFT                     = $0400;
-  GL_FRONT_RIGHT                    = $0401;
-  GL_BACK_LEFT                      = $0402;
-  GL_BACK_RIGHT                     = $0403;
-  GL_FRONT                          = $0404;
-  GL_BACK                           = $0405;
-  GL_LEFT                           = $0406;
-  GL_RIGHT                          = $0407;
-  GL_FRONT_AND_BACK                 = $0408;
-  GL_AUX0                           = $0409;
-  GL_AUX1                           = $040A;
-  GL_AUX2                           = $040B;
-  GL_AUX3                           = $040C;
-
-  // Enable
-  //      GL_FOG
-  //      GL_LIGHTING
-  //      GL_TEXTURE_1D
-  //      GL_TEXTURE_2D
-  //      GL_LINE_STIPPLE
-  //      GL_POLYGON_STIPPLE
-  //      GL_CULL_FACE
-  //      GL_ALPHA_TEST
-  //      GL_BLEND
-  //      GL_INDEX_LOGIC_OP
-  //      GL_COLOR_LOGIC_OP
-  //      GL_DITHER
-  //      GL_STENCIL_TEST
-  //      GL_DEPTH_TEST
-  //      GL_CLIP_PLANE0
-  //      GL_CLIP_PLANE1
-  //      GL_CLIP_PLANE2
-  //      GL_CLIP_PLANE3
-  //      GL_CLIP_PLANE4
-  //      GL_CLIP_PLANE5
-  //      GL_LIGHT0
-  //      GL_LIGHT1
-  //      GL_LIGHT2
-  //      GL_LIGHT3
-  //      GL_LIGHT4
-  //      GL_LIGHT5
-  //      GL_LIGHT6
-  //      GL_LIGHT7
-  //      GL_TEXTURE_GEN_S
-  //      GL_TEXTURE_GEN_T
-  //      GL_TEXTURE_GEN_R
-  //      GL_TEXTURE_GEN_Q
-  //      GL_MAP1_VERTEX_3
-  //      GL_MAP1_VERTEX_4
-  //      GL_MAP1_COLOR_4
-  //      GL_MAP1_INDEX
-  //      GL_MAP1_NORMAL
-  //      GL_MAP1_TEXTURE_COORD_1
-  //      GL_MAP1_TEXTURE_COORD_2
-  //      GL_MAP1_TEXTURE_COORD_3
-  //      GL_MAP1_TEXTURE_COORD_4
-  //      GL_MAP2_VERTEX_3
-  //      GL_MAP2_VERTEX_4
-  //      GL_MAP2_COLOR_4
-  //      GL_MAP2_INDEX
-  //      GL_MAP2_NORMAL
-  //      GL_MAP2_TEXTURE_COORD_1
-  //      GL_MAP2_TEXTURE_COORD_2
-  //      GL_MAP2_TEXTURE_COORD_3
-  //      GL_MAP2_TEXTURE_COORD_4
-  //      GL_POINT_SMOOTH
-  //      GL_LINE_SMOOTH
-  //      GL_POLYGON_SMOOTH
-  //      GL_SCISSOR_TEST
-  //      GL_COLOR_MATERIAL
-  //      GL_NORMALIZE
-  //      GL_AUTO_NORMAL
-  //      GL_VERTEX_ARRAY
-  //      GL_NORMAL_ARRAY
-  //      GL_COLOR_ARRAY
-  //      GL_INDEX_ARRAY
-  //      GL_TEXTURE_COORD_ARRAY
-  //      GL_EDGE_FLAG_ARRAY
-  //      GL_POLYGON_OFFSET_POINT
-  //      GL_POLYGON_OFFSET_LINE
-  //      GL_POLYGON_OFFSET_FILL
-
-  // ErrorCode
-  GL_NO_ERROR                       = 0;
-  GL_INVALID_ENUM                   = $0500;
-  GL_INVALID_VALUE                  = $0501;
-  GL_INVALID_OPERATION              = $0502;
-  GL_STACK_OVERFLOW                 = $0503;
-  GL_STACK_UNDERFLOW                = $0504;
-  GL_OUT_OF_MEMORY                  = $0505;
-
-  // FeedBackMode
-  GL_2D                             = $0600;
-  GL_3D                             = $0601;
-  GL_3D_COLOR                       = $0602;
-  GL_3D_COLOR_TEXTURE               = $0603;
-  GL_4D_COLOR_TEXTURE               = $0604;
-
-  // FeedBackToken
-  GL_PASS_THROUGH_TOKEN             = $0700;
-  GL_POINT_TOKEN                    = $0701;
-  GL_LINE_TOKEN                     = $0702;
-  GL_POLYGON_TOKEN                  = $0703;
-  GL_BITMAP_TOKEN                   = $0704;
-  GL_DRAW_PIXEL_TOKEN               = $0705;
-  GL_COPY_PIXEL_TOKEN               = $0706;
-  GL_LINE_RESET_TOKEN               = $0707;
-
-  // FogMode
-  //      GL_LINEAR
-  GL_EXP                            = $0800;
-  GL_EXP2                           = $0801;
-
-  // FogParameter
-  //      GL_FOG_COLOR
-  //      GL_FOG_DENSITY
-  //      GL_FOG_END
-  //      GL_FOG_INDEX
-  //      GL_FOG_MODE
-  //      GL_FOG_START
-
-  // FrontFaceDirection
-  GL_CW                             = $0900;
-  GL_CCW                            = $0901;
-
-  // GetMapTarget
-  GL_COEFF                          = $0A00;
-  GL_ORDER                          = $0A01;
-  GL_DOMAIN                         = $0A02;
-
-  // GetPixelMap
-  //      GL_PIXEL_MAP_I_TO_I 
-  //      GL_PIXEL_MAP_S_TO_S 
-  //      GL_PIXEL_MAP_I_TO_R 
-  //      GL_PIXEL_MAP_I_TO_G 
-  //      GL_PIXEL_MAP_I_TO_B 
-  //      GL_PIXEL_MAP_I_TO_A
-  //      GL_PIXEL_MAP_R_TO_R
-  //      GL_PIXEL_MAP_G_TO_G 
-  //      GL_PIXEL_MAP_B_TO_B 
-  //      GL_PIXEL_MAP_A_TO_A 
-
-  // GetPointerTarget 
-  //      GL_VERTEX_ARRAY_POINTER 
-  //      GL_NORMAL_ARRAY_POINTER 
-  //      GL_COLOR_ARRAY_POINTER 
-  //      GL_INDEX_ARRAY_POINTER 
-  //      GL_TEXTURE_COORD_ARRAY_POINTER 
-  //      GL_EDGE_FLAG_ARRAY_POINTER 
-
-  // GetTarget 
-  GL_CURRENT_COLOR                  = $0B00;
-  GL_CURRENT_INDEX                  = $0B01;
-  GL_CURRENT_NORMAL                 = $0B02;
-  GL_CURRENT_TEXTURE_COORDS         = $0B03;
-  GL_CURRENT_RASTER_COLOR           = $0B04;
-  GL_CURRENT_RASTER_INDEX           = $0B05;
-  GL_CURRENT_RASTER_TEXTURE_COORDS  = $0B06;
-  GL_CURRENT_RASTER_POSITION        = $0B07;
-  GL_CURRENT_RASTER_POSITION_VALID  = $0B08;
-  GL_CURRENT_RASTER_DISTANCE        = $0B09;
-  GL_POINT_SMOOTH                   = $0B10;
-  GL_POINT_SIZE                     = $0B11;
-  GL_POINT_SIZE_RANGE               = $0B12;
-  GL_POINT_SIZE_GRANULARITY         = $0B13;
-  GL_LINE_SMOOTH                    = $0B20;
-  GL_LINE_WIDTH                     = $0B21;
-  GL_LINE_WIDTH_RANGE               = $0B22;
-  GL_LINE_WIDTH_GRANULARITY         = $0B23;
-  GL_LINE_STIPPLE                   = $0B24;
-  GL_LINE_STIPPLE_PATTERN           = $0B25;
-  GL_LINE_STIPPLE_REPEAT            = $0B26;
-  GL_LIST_MODE                      = $0B30;
-  GL_MAX_LIST_NESTING               = $0B31;
-  GL_LIST_BASE                      = $0B32;
-  GL_LIST_INDEX                     = $0B33;
-  GL_POLYGON_MODE                   = $0B40;
-  GL_POLYGON_SMOOTH                 = $0B41;
-  GL_POLYGON_STIPPLE                = $0B42;
-  GL_EDGE_FLAG                      = $0B43;
-  GL_CULL_FACE                      = $0B44;
-  GL_CULL_FACE_MODE                 = $0B45;
-  GL_FRONT_FACE                     = $0B46;
-  GL_LIGHTING                       = $0B50;
-  GL_LIGHT_MODEL_LOCAL_VIEWER       = $0B51;
-  GL_LIGHT_MODEL_TWO_SIDE           = $0B52;
-  GL_LIGHT_MODEL_AMBIENT            = $0B53;
-  GL_SHADE_MODEL                    = $0B54;
-  GL_COLOR_MATERIAL_FACE            = $0B55;
-  GL_COLOR_MATERIAL_PARAMETER       = $0B56;
-  GL_COLOR_MATERIAL                 = $0B57;
-  GL_FOG                            = $0B60;
-  GL_FOG_INDEX                      = $0B61;
-  GL_FOG_DENSITY                    = $0B62;
-  GL_FOG_START                      = $0B63;
-  GL_FOG_END                        = $0B64;
-  GL_FOG_MODE                       = $0B65;
-  GL_FOG_COLOR                      = $0B66;
-  GL_DEPTH_RANGE                    = $0B70;
-  GL_DEPTH_TEST                     = $0B71;
-  GL_DEPTH_WRITEMASK                = $0B72;
-  GL_DEPTH_CLEAR_VALUE              = $0B73;
-  GL_DEPTH_FUNC                     = $0B74;
-  GL_ACCUM_CLEAR_VALUE              = $0B80;
-  GL_STENCIL_TEST                   = $0B90;
-  GL_STENCIL_CLEAR_VALUE            = $0B91;
-  GL_STENCIL_FUNC                   = $0B92;
-  GL_STENCIL_VALUE_MASK             = $0B93;
-  GL_STENCIL_FAIL                   = $0B94;
-  GL_STENCIL_PASS_DEPTH_FAIL        = $0B95;
-  GL_STENCIL_PASS_DEPTH_PASS        = $0B96;
-  GL_STENCIL_REF                    = $0B97;
-  GL_STENCIL_WRITEMASK              = $0B98;
-  GL_MATRIX_MODE                    = $0BA0;
-  GL_NORMALIZE                      = $0BA1;
-  GL_VIEWPORT                       = $0BA2;
-  GL_MODELVIEW_STACK_DEPTH          = $0BA3;
-  GL_PROJECTION_STACK_DEPTH         = $0BA4;
-  GL_TEXTURE_STACK_DEPTH            = $0BA5;
-  GL_MODELVIEW_MATRIX               = $0BA6;
-  GL_PROJECTION_MATRIX              = $0BA7;
-  GL_TEXTURE_MATRIX                 = $0BA8;
-  GL_ATTRIB_STACK_DEPTH             = $0BB0;
-  GL_CLIENT_ATTRIB_STACK_DEPTH      = $0BB1;
-  GL_ALPHA_TEST                     = $0BC0;
-  GL_ALPHA_TEST_FUNC                = $0BC1;
-  GL_ALPHA_TEST_REF                 = $0BC2;
-  GL_DITHER                         = $0BD0;
-  GL_BLEND_DST                      = $0BE0;
-  GL_BLEND_SRC                      = $0BE1;
-  GL_BLEND                          = $0BE2;
-  GL_LOGIC_OP_MODE                  = $0BF0;
-  GL_INDEX_LOGIC_OP                 = $0BF1;
-  GL_COLOR_LOGIC_OP                 = $0BF2;
-  GL_AUX_BUFFERS                    = $0C00;
-  GL_DRAW_BUFFER                    = $0C01;
-  GL_READ_BUFFER                    = $0C02;
-  GL_SCISSOR_BOX                    = $0C10;
-  GL_SCISSOR_TEST                   = $0C11;
-  GL_INDEX_CLEAR_VALUE              = $0C20;
-  GL_INDEX_WRITEMASK                = $0C21;
-  GL_COLOR_CLEAR_VALUE              = $0C22;
-  GL_COLOR_WRITEMASK                = $0C23;
-  GL_INDEX_MODE                     = $0C30;
-  GL_RGBA_MODE                      = $0C31;
-  GL_DOUBLEBUFFER                   = $0C32;
-  GL_STEREO                         = $0C33;
-  GL_RENDER_MODE                    = $0C40;
-  GL_PERSPECTIVE_CORRECTION_HINT    = $0C50;
-  GL_POINT_SMOOTH_HINT              = $0C51;
-  GL_LINE_SMOOTH_HINT               = $0C52;
-  GL_POLYGON_SMOOTH_HINT            = $0C53;
-  GL_FOG_HINT                       = $0C54;
-  GL_TEXTURE_GEN_S                  = $0C60;
-  GL_TEXTURE_GEN_T                  = $0C61;
-  GL_TEXTURE_GEN_R                  = $0C62;
-  GL_TEXTURE_GEN_Q                  = $0C63;
-  GL_PIXEL_MAP_I_TO_I               = $0C70;
-  GL_PIXEL_MAP_S_TO_S               = $0C71;
-  GL_PIXEL_MAP_I_TO_R               = $0C72;
-  GL_PIXEL_MAP_I_TO_G               = $0C73;
-  GL_PIXEL_MAP_I_TO_B               = $0C74;
-  GL_PIXEL_MAP_I_TO_A               = $0C75;
-  GL_PIXEL_MAP_R_TO_R               = $0C76;
-  GL_PIXEL_MAP_G_TO_G               = $0C77;
-  GL_PIXEL_MAP_B_TO_B               = $0C78;
-  GL_PIXEL_MAP_A_TO_A               = $0C79;
-  GL_PIXEL_MAP_I_TO_I_SIZE          = $0CB0;
-  GL_PIXEL_MAP_S_TO_S_SIZE          = $0CB1;
-  GL_PIXEL_MAP_I_TO_R_SIZE          = $0CB2;
-  GL_PIXEL_MAP_I_TO_G_SIZE          = $0CB3;
-  GL_PIXEL_MAP_I_TO_B_SIZE          = $0CB4;
-  GL_PIXEL_MAP_I_TO_A_SIZE          = $0CB5;
-  GL_PIXEL_MAP_R_TO_R_SIZE          = $0CB6;
-  GL_PIXEL_MAP_G_TO_G_SIZE          = $0CB7;
-  GL_PIXEL_MAP_B_TO_B_SIZE          = $0CB8;
-  GL_PIXEL_MAP_A_TO_A_SIZE          = $0CB9;
-  GL_UNPACK_SWAP_BYTES              = $0CF0;
-  GL_UNPACK_LSB_FIRST               = $0CF1;
-  GL_UNPACK_ROW_LENGTH              = $0CF2;
-  GL_UNPACK_SKIP_ROWS               = $0CF3;
-  GL_UNPACK_SKIP_PIXELS             = $0CF4;
-  GL_UNPACK_ALIGNMENT               = $0CF5;
-  GL_PACK_SWAP_BYTES                = $0D00;
-  GL_PACK_LSB_FIRST                 = $0D01;
-  GL_PACK_ROW_LENGTH                = $0D02;
-  GL_PACK_SKIP_ROWS                 = $0D03;
-  GL_PACK_SKIP_PIXELS               = $0D04;
-  GL_PACK_ALIGNMENT                 = $0D05;
-  GL_MAP_COLOR                      = $0D10;
-  GL_MAP_STENCIL                    = $0D11;
-  GL_INDEX_SHIFT                    = $0D12;
-  GL_INDEX_OFFSET                   = $0D13;
-  GL_RED_SCALE                      = $0D14;
-  GL_RED_BIAS                       = $0D15;
-  GL_ZOOM_X                         = $0D16;
-  GL_ZOOM_Y                         = $0D17;
-  GL_GREEN_SCALE                    = $0D18;
-  GL_GREEN_BIAS                     = $0D19;
-  GL_BLUE_SCALE                     = $0D1A;
-  GL_BLUE_BIAS                      = $0D1B;
-  GL_ALPHA_SCALE                    = $0D1C;
-  GL_ALPHA_BIAS                     = $0D1D;
-  GL_DEPTH_SCALE                    = $0D1E;
-  GL_DEPTH_BIAS                     = $0D1F;
-  GL_MAX_EVAL_ORDER                 = $0D30;
-  GL_MAX_LIGHTS                     = $0D31;
-  GL_MAX_CLIP_PLANES                = $0D32;
-  GL_MAX_TEXTURE_SIZE               = $0D33;
-  GL_MAX_PIXEL_MAP_TABLE            = $0D34;
-  GL_MAX_ATTRIB_STACK_DEPTH         = $0D35;
-  GL_MAX_MODELVIEW_STACK_DEPTH      = $0D36;
-  GL_MAX_NAME_STACK_DEPTH           = $0D37;
-  GL_MAX_PROJECTION_STACK_DEPTH     = $0D38;
-  GL_MAX_TEXTURE_STACK_DEPTH        = $0D39;
-  GL_MAX_VIEWPORT_DIMS              = $0D3A;
-  GL_MAX_CLIENT_ATTRIB_STACK_DEPTH  = $0D3B;
-  GL_SUBPIXEL_BITS                  = $0D50;
-  GL_INDEX_BITS                     = $0D51;
-  GL_RED_BITS                       = $0D52;
-  GL_GREEN_BITS                     = $0D53;
-  GL_BLUE_BITS                      = $0D54;
-  GL_ALPHA_BITS                     = $0D55;
-  GL_DEPTH_BITS                     = $0D56;
-  GL_STENCIL_BITS                   = $0D57;
-  GL_ACCUM_RED_BITS                 = $0D58;
-  GL_ACCUM_GREEN_BITS               = $0D59;
-  GL_ACCUM_BLUE_BITS                = $0D5A;
-  GL_ACCUM_ALPHA_BITS               = $0D5B;
-  GL_NAME_STACK_DEPTH               = $0D70;
-  GL_AUTO_NORMAL                    = $0D80;
-  GL_MAP1_COLOR_4                   = $0D90;
-  GL_MAP1_INDEX                     = $0D91;
-  GL_MAP1_NORMAL                    = $0D92;
-  GL_MAP1_TEXTURE_COORD_1           = $0D93;
-  GL_MAP1_TEXTURE_COORD_2           = $0D94;
-  GL_MAP1_TEXTURE_COORD_3           = $0D95;
-  GL_MAP1_TEXTURE_COORD_4           = $0D96;
-  GL_MAP1_VERTEX_3                  = $0D97;
-  GL_MAP1_VERTEX_4                  = $0D98;
-  GL_MAP2_COLOR_4                   = $0DB0;
-  GL_MAP2_INDEX                     = $0DB1;
-  GL_MAP2_NORMAL                    = $0DB2;
-  GL_MAP2_TEXTURE_COORD_1           = $0DB3;
-  GL_MAP2_TEXTURE_COORD_2           = $0DB4;
-  GL_MAP2_TEXTURE_COORD_3           = $0DB5;
-  GL_MAP2_TEXTURE_COORD_4           = $0DB6;
-  GL_MAP2_VERTEX_3                  = $0DB7;
-  GL_MAP2_VERTEX_4                  = $0DB8;
-  GL_MAP1_GRID_DOMAIN               = $0DD0;
-  GL_MAP1_GRID_SEGMENTS             = $0DD1;
-  GL_MAP2_GRID_DOMAIN               = $0DD2;
-  GL_MAP2_GRID_SEGMENTS             = $0DD3;
-  GL_TEXTURE_1D                     = $0DE0;
-  GL_TEXTURE_2D                     = $0DE1;
-  GL_FEEDBACK_BUFFER_POINTER        = $0DF0;
-  GL_FEEDBACK_BUFFER_SIZE           = $0DF1;
-  GL_FEEDBACK_BUFFER_TYPE           = $0DF2;
-  GL_SELECTION_BUFFER_POINTER       = $0DF3;
-  GL_SELECTION_BUFFER_SIZE          = $0DF4;
-  //      GL_TEXTURE_BINDING_1D
-  //      GL_TEXTURE_BINDING_2D 
-  //      GL_VERTEX_ARRAY 
-  //      GL_NORMAL_ARRAY 
-  //      GL_COLOR_ARRAY 
-  //      GL_INDEX_ARRAY 
-  //      GL_TEXTURE_COORD_ARRAY 
-  //      GL_EDGE_FLAG_ARRAY
-  //      GL_VERTEX_ARRAY_SIZE
-  //      GL_VERTEX_ARRAY_TYPE 
-  //      GL_VERTEX_ARRAY_STRIDE 
-  //      GL_NORMAL_ARRAY_TYPE 
-  //      GL_NORMAL_ARRAY_STRIDE 
-  //      GL_COLOR_ARRAY_SIZE 
-  //      GL_COLOR_ARRAY_TYPE 
-  //      GL_COLOR_ARRAY_STRIDE 
-  //      GL_INDEX_ARRAY_TYPE 
-  //      GL_INDEX_ARRAY_STRIDE 
-  //      GL_TEXTURE_COORD_ARRAY_SIZE 
-  //      GL_TEXTURE_COORD_ARRAY_TYPE 
-  //      GL_TEXTURE_COORD_ARRAY_STRIDE 
-  //      GL_EDGE_FLAG_ARRAY_STRIDE 
-  //      GL_POLYGON_OFFSET_FACTOR 
-  //      GL_POLYGON_OFFSET_UNITS 
-
-  // GetTextureParameter 
-  //      GL_TEXTURE_MAG_FILTER 
-  //      GL_TEXTURE_MIN_FILTER 
-  //      GL_TEXTURE_WRAP_S
-  //      GL_TEXTURE_WRAP_T
-  GL_TEXTURE_WIDTH                  = $1000;
-  GL_TEXTURE_HEIGHT                 = $1001;
-  GL_TEXTURE_INTERNAL_FORMAT        = $1003;
-  GL_TEXTURE_BORDER_COLOR           = $1004;
-  GL_TEXTURE_BORDER                 = $1005;
-  //      GL_TEXTURE_RED_SIZE
-  //      GL_TEXTURE_GREEN_SIZE
-  //      GL_TEXTURE_BLUE_SIZE
-  //      GL_TEXTURE_ALPHA_SIZE
-  //      GL_TEXTURE_LUMINANCE_SIZE
-  //      GL_TEXTURE_INTENSITY_SIZE
-  //      GL_TEXTURE_PRIORITY
-  //      GL_TEXTURE_RESIDENT
-
-  // HintMode
-  GL_DONT_CARE                      = $1100;
-  GL_FASTEST                        = $1101;
-  GL_NICEST                         = $1102;
-
-  // HintTarget
-  //      GL_PERSPECTIVE_CORRECTION_HINT
-  //      GL_POINT_SMOOTH_HINT
-  //      GL_LINE_SMOOTH_HINT
-  //      GL_POLYGON_SMOOTH_HINT
-  //      GL_FOG_HINT
-
-  // IndexPointerType
-  //      GL_SHORT
-  //      GL_INT
-  //      GL_FLOAT
-  //      GL_DOUBLE
-
-  // LightModelParameter
-  //      GL_LIGHT_MODEL_AMBIENT
-  //      GL_LIGHT_MODEL_LOCAL_VIEWER
-  //      GL_LIGHT_MODEL_TWO_SIDE
-
-  // LightName
-  GL_LIGHT0                         = $4000;
-  GL_LIGHT1                         = $4001;
-  GL_LIGHT2                         = $4002;
-  GL_LIGHT3                         = $4003;
-  GL_LIGHT4                         = $4004;
-  GL_LIGHT5                         = $4005;
-  GL_LIGHT6                         = $4006;
-  GL_LIGHT7                         = $4007;
-
-  // LightParameter
-  GL_AMBIENT                        = $1200;
-  GL_DIFFUSE                        = $1201;
-  GL_SPECULAR                       = $1202;
-  GL_POSITION                       = $1203;
-  GL_SPOT_DIRECTION                 = $1204;
-  GL_SPOT_EXPONENT                  = $1205;
-  GL_SPOT_CUTOFF                    = $1206;
-  GL_CONSTANT_ATTENUATION           = $1207;
-  GL_LINEAR_ATTENUATION             = $1208;
-  GL_QUADRATIC_ATTENUATION          = $1209;
-
-  // InterleavedArrays
-  //      GL_V2F
-  //      GL_V3F
-  //      GL_C4UB_V2F
-  //      GL_C4UB_V3F
-  //      GL_C3F_V3F
-  //      GL_N3F_V3F
-  //      GL_C4F_N3F_V3F
-  //      GL_T2F_V3F
-  //      GL_T4F_V4F
-  //      GL_T2F_C4UB_V3F
-  //      GL_T2F_C3F_V3F
-  //      GL_T2F_N3F_V3F
-  //      GL_T2F_C4F_N3F_V3F
-  //      GL_T4F_C4F_N3F_V4F
-
-  // ListMode
-  GL_COMPILE                        = $1300;
-  GL_COMPILE_AND_EXECUTE            = $1301;
-
-  // ListNameType
-  //      GL_BYTE
-  //      GL_UNSIGNED_BYTE
-  //      GL_SHORT
-  //      GL_UNSIGNED_SHORT
-  //      GL_INT
-  //      GL_UNSIGNED_INT
-  //      GL_FLOAT
-  //      GL_2_BYTES
-  //      GL_3_BYTES
-  //      GL_4_BYTES
-
-  // LogicOp
-  GL_CLEAR                          = $1500;
-  GL_AND                            = $1501;
-  GL_AND_REVERSE                    = $1502;
-  GL_COPY                           = $1503;
-  GL_AND_INVERTED                   = $1504;
-  GL_NOOP                           = $1505;
-  GL_XOR                            = $1506;
-  GL_OR                             = $1507;
-  GL_NOR                            = $1508;
-  GL_EQUIV                          = $1509;
-  GL_INVERT                         = $150A;
-  GL_OR_REVERSE                     = $150B;
-  GL_COPY_INVERTED                  = $150C;
-  GL_OR_INVERTED                    = $150D;
-  GL_NAND                           = $150E;
-  GL_SET                            = $150F;
-
-  // MapTarget
-  //      GL_MAP1_COLOR_4
-  //      GL_MAP1_INDEX
-  //      GL_MAP1_NORMAL
-  //      GL_MAP1_TEXTURE_COORD_1
-  //      GL_MAP1_TEXTURE_COORD_2
-  //      GL_MAP1_TEXTURE_COORD_3
-  //      GL_MAP1_TEXTURE_COORD_4
-  //      GL_MAP1_VERTEX_3
-  //      GL_MAP1_VERTEX_4
-  //      GL_MAP2_COLOR_4
-  //      GL_MAP2_INDEX
-  //      GL_MAP2_NORMAL
-  //      GL_MAP2_TEXTURE_COORD_1
-  //      GL_MAP2_TEXTURE_COORD_2
-  //      GL_MAP2_TEXTURE_COORD_3
-  //      GL_MAP2_TEXTURE_COORD_4
-  //      GL_MAP2_VERTEX_3
-  //      GL_MAP2_VERTEX_4
-
-  // MaterialFace
-  //      GL_FRONT
-  //      GL_BACK
-  //      GL_FRONT_AND_BACK
-
-  // MaterialParameter
-  GL_EMISSION                       = $1600;
-  GL_SHININESS                      = $1601;
-  GL_AMBIENT_AND_DIFFUSE            = $1602;
-  GL_COLOR_INDEXES                  = $1603;
-  //      GL_AMBIENT
-  //      GL_DIFFUSE
-  //      GL_SPECULAR
-
-  // MatrixMode
-  GL_MODELVIEW                      = $1700;
-  GL_PROJECTION                     = $1701;
-  GL_TEXTURE                        = $1702;
-
-  // MeshMode1
-  //      GL_POINT
-  //      GL_LINE
-
-  // MeshMode2
-  //      GL_POINT
-  //      GL_LINE
-  //      GL_FILL
-
-  // NormalPointerType
-  //      GL_BYTE
-  //      GL_SHORT
-  //      GL_INT
-  //      GL_FLOAT
-  //      GL_DOUBLE
-
-  // PixelCopyType
-  GL_COLOR                          = $1800;
-  GL_DEPTH                          = $1801;
-  GL_STENCIL                        = $1802;
-
-  // PixelFormat
-  GL_COLOR_INDEX                    = $1900;
-  GL_STENCIL_INDEX                  = $1901;
-  GL_DEPTH_COMPONENT                = $1902;
-  GL_RED                            = $1903;
-  GL_GREEN                          = $1904;
-  GL_BLUE                           = $1905;
-  GL_ALPHA                          = $1906;
-  GL_RGB                            = $1907;
-  GL_RGBA                           = $1908;
-  GL_LUMINANCE                      = $1909;
-  GL_LUMINANCE_ALPHA                = $190A;
-
-  // PixelMap
-  //      GL_PIXEL_MAP_I_TO_I
-  //      GL_PIXEL_MAP_S_TO_S
-  //      GL_PIXEL_MAP_I_TO_R
-  //      GL_PIXEL_MAP_I_TO_G
-  //      GL_PIXEL_MAP_I_TO_B
-  //      GL_PIXEL_MAP_I_TO_A
-  //      GL_PIXEL_MAP_R_TO_R
-  //      GL_PIXEL_MAP_G_TO_G
-  //      GL_PIXEL_MAP_B_TO_B
-  //      GL_PIXEL_MAP_A_TO_A
-
-  // PixelStore
-  //      GL_UNPACK_SWAP_BYTES
-  //      GL_UNPACK_LSB_FIRST
-  //      GL_UNPACK_ROW_LENGTH
-  //      GL_UNPACK_SKIP_ROWS
-  //      GL_UNPACK_SKIP_PIXELS
-  //      GL_UNPACK_ALIGNMENT
-  //      GL_PACK_SWAP_BYTES
-  //      GL_PACK_LSB_FIRST
-  //      GL_PACK_ROW_LENGTH
-  //      GL_PACK_SKIP_ROWS
-  //      GL_PACK_SKIP_PIXELS
-  //      GL_PACK_ALIGNMENT
-
-  // PixelTransfer
-  //      GL_MAP_COLOR
-  //      GL_MAP_STENCIL
-  //      GL_INDEX_SHIFT
-  //      GL_INDEX_OFFSET
-  //      GL_RED_SCALE
-  //      GL_RED_BIAS
-  //      GL_GREEN_SCALE
-  //      GL_GREEN_BIAS
-  //      GL_BLUE_SCALE
-  //      GL_BLUE_BIAS
-  //      GL_ALPHA_SCALE
-  //      GL_ALPHA_BIAS
-  //      GL_DEPTH_SCALE
-  //      GL_DEPTH_BIAS
-
-  // PixelType
-  GL_BITMAP                         = $1A00;
-  //      GL_BYTE
-  //      GL_UNSIGNED_BYTE
-  //      GL_SHORT
-  //      GL_UNSIGNED_SHORT
-  //      GL_INT
-  //      GL_UNSIGNED_INT
-  //      GL_FLOAT
-
-  // PolygonMode
-  GL_POINT                          = $1B00;
-  GL_LINE                           = $1B01;
-  GL_FILL                           = $1B02;
-
-  // ReadBufferMode
-  //      GL_FRONT_LEFT
-  //      GL_FRONT_RIGHT
-  //      GL_BACK_LEFT
-  //      GL_BACK_RIGHT
-  //      GL_FRONT
-  //      GL_BACK
-  //      GL_LEFT
-  //      GL_RIGHT
-  //      GL_AUX0
-  //      GL_AUX1
-  //      GL_AUX2
-  //      GL_AUX3
-
-  // RenderingMode
-  GL_RENDER                         = $1C00;
-  GL_FEEDBACK                       = $1C01;
-  GL_SELECT                         = $1C02;
-
-  // ShadingModel
-  GL_FLAT                           = $1D00;
-  GL_SMOOTH                         = $1D01;
-
-  // StencilFunction
-  //      GL_NEVER
-  //      GL_LESS
-  //      GL_EQUAL
-  //      GL_LEQUAL
-  //      GL_GREATER
-  //      GL_NOTEQUAL
-  //      GL_GEQUAL
-  //      GL_ALWAYS
-
-  // StencilOp
-  //      GL_ZERO
-  GL_KEEP                           = $1E00;
-  GL_REPLACE                        = $1E01;
-  GL_INCR                           = $1E02;
-  GL_DECR                           = $1E03;
-  //      GL_INVERT
-
-  // StringName
-  GL_VENDOR                         = $1F00;
-  GL_RENDERER                       = $1F01;
-  GL_VERSION                        = $1F02;
-  GL_EXTENSIONS                     = $1F03;
-
-  // TextureCoordName
-  GL_S                              = $2000;
-  GL_T                              = $2001;
-  GL_R                              = $2002;
-  GL_Q                              = $2003;
-
-  // TexCoordPointerType
-  //      GL_SHORT
-  //      GL_INT
-  //      GL_FLOAT
-  //      GL_DOUBLE
-
-  // TextureEnvMode
-  GL_MODULATE                       = $2100;
-  GL_DECAL                          = $2101;
-  //      GL_BLEND
-  //      GL_REPLACE
-
-  // TextureEnvParameter
-  GL_TEXTURE_ENV_MODE               = $2200;
-  GL_TEXTURE_ENV_COLOR              = $2201;
-
-  // TextureEnvTarget
-  GL_TEXTURE_ENV                    = $2300;
-
-  // TextureGenMode
-  GL_EYE_LINEAR                     = $2400;
-  GL_OBJECT_LINEAR                  = $2401;
-  GL_SPHERE_MAP                     = $2402;
-
-  // TextureGenParameter
-  GL_TEXTURE_GEN_MODE               = $2500;
-  GL_OBJECT_PLANE                   = $2501;
-  GL_EYE_PLANE                      = $2502;
-
-  // TextureMagFilter
-  GL_NEAREST                        = $2600;
-  GL_LINEAR                         = $2601;
-
-  // TextureMinFilter
-  //      GL_NEAREST
-  //      GL_LINEAR
-  GL_NEAREST_MIPMAP_NEAREST         = $2700;
-  GL_LINEAR_MIPMAP_NEAREST          = $2701;
-  GL_NEAREST_MIPMAP_LINEAR          = $2702;
-  GL_LINEAR_MIPMAP_LINEAR           = $2703;
-
-  // TextureParameterName
-  GL_TEXTURE_MAG_FILTER             = $2800;
-  GL_TEXTURE_MIN_FILTER             = $2801;
-  GL_TEXTURE_WRAP_S                 = $2802;
-  GL_TEXTURE_WRAP_T                 = $2803;
-  //      GL_TEXTURE_BORDER_COLOR
-  //      GL_TEXTURE_PRIORITY
-
-  // TextureTarget
-  //      GL_TEXTURE_1D
-  //      GL_TEXTURE_2D
-  //      GL_PROXY_TEXTURE_1D
-  //      GL_PROXY_TEXTURE_2D
-
-  // TextureWrapMode
-  GL_CLAMP                          = $2900;
-  GL_REPEAT                         = $2901;
-
-  // VertexPointerType
-  //      GL_SHORT
-  //      GL_INT
-  //      GL_FLOAT
-  //      GL_DOUBLE
-
-  // ClientAttribMask
-  GL_CLIENT_PIXEL_STORE_BIT         = $00000001;
-  GL_CLIENT_VERTEX_ARRAY_BIT        = $00000002;
-  GL_CLIENT_ALL_ATTRIB_BITS         = $FFFFFFFF;
-
-  // polygon_offset
-  GL_POLYGON_OFFSET_FACTOR          = $8038;
-  GL_POLYGON_OFFSET_UNITS           = $2A00;
-  GL_POLYGON_OFFSET_POINT           = $2A01;
-  GL_POLYGON_OFFSET_LINE            = $2A02;
-  GL_POLYGON_OFFSET_FILL            = $8037;
-
-  // texture
-  GL_ALPHA4                         = $803B;
-  GL_ALPHA8                         = $803C;
-  GL_ALPHA12                        = $803D;
-  GL_ALPHA16                        = $803E;
-  GL_LUMINANCE4                     = $803F;
-  GL_LUMINANCE8                     = $8040;
-  GL_LUMINANCE12                    = $8041;
-  GL_LUMINANCE16                    = $8042;
-  GL_LUMINANCE4_ALPHA4              = $8043;
-  GL_LUMINANCE6_ALPHA2              = $8044;
-  GL_LUMINANCE8_ALPHA8              = $8045;
-  GL_LUMINANCE12_ALPHA4             = $8046;
-  GL_LUMINANCE12_ALPHA12            = $8047;
-  GL_LUMINANCE16_ALPHA16            = $8048;
-  GL_INTENSITY                      = $8049;
-  GL_INTENSITY4                     = $804A;
-  GL_INTENSITY8                     = $804B;
-  GL_INTENSITY12                    = $804C;
-  GL_INTENSITY16                    = $804D;
-  GL_R3_G3_B2                       = $2A10;
-  GL_RGB4                           = $804F;
-  GL_RGB5                           = $8050;
-  GL_RGB8                           = $8051;
-  GL_RGB10                          = $8052;
-  GL_RGB12                          = $8053;
-  GL_RGB16                          = $8054;
-  GL_RGBA2                          = $8055;
-  GL_RGBA4                          = $8056;
-  GL_RGB5_A1                        = $8057;
-  GL_RGBA8                          = $8058;
-  GL_RGB10_A2                       = $8059;
-  GL_RGBA12                         = $805A;
-  GL_RGBA16                         = $805B;
-  GL_TEXTURE_RED_SIZE               = $805C;
-  GL_TEXTURE_GREEN_SIZE             = $805D;
-  GL_TEXTURE_BLUE_SIZE              = $805E;
-  GL_TEXTURE_ALPHA_SIZE             = $805F;
-  GL_TEXTURE_LUMINANCE_SIZE         = $8060;
-  GL_TEXTURE_INTENSITY_SIZE         = $8061;
-  GL_PROXY_TEXTURE_1D               = $8063;
-  GL_PROXY_TEXTURE_2D               = $8064;
-
-  // texture_object
-  GL_TEXTURE_PRIORITY               = $8066;
-  GL_TEXTURE_RESIDENT               = $8067;
-  GL_TEXTURE_BINDING_1D             = $8068;
-  GL_TEXTURE_BINDING_2D             = $8069;
-
-  // vertex_array
-  GL_VERTEX_ARRAY                   = $8074;
-  GL_NORMAL_ARRAY                   = $8075;
-  GL_COLOR_ARRAY                    = $8076;
-  GL_INDEX_ARRAY                    = $8077;
-  GL_TEXTURE_COORD_ARRAY            = $8078;
-  GL_EDGE_FLAG_ARRAY                = $8079;
-  GL_VERTEX_ARRAY_SIZE              = $807A;
-  GL_VERTEX_ARRAY_TYPE              = $807B;
-  GL_VERTEX_ARRAY_STRIDE            = $807C;
-  GL_NORMAL_ARRAY_TYPE              = $807E;
-  GL_NORMAL_ARRAY_STRIDE            = $807F;
-  GL_COLOR_ARRAY_SIZE               = $8081;
-  GL_COLOR_ARRAY_TYPE               = $8082;
-  GL_COLOR_ARRAY_STRIDE             = $8083;
-  GL_INDEX_ARRAY_TYPE               = $8085;
-  GL_INDEX_ARRAY_STRIDE             = $8086;
-  GL_TEXTURE_COORD_ARRAY_SIZE       = $8088;
-  GL_TEXTURE_COORD_ARRAY_TYPE       = $8089;
-  GL_TEXTURE_COORD_ARRAY_STRIDE     = $808A;
-  GL_EDGE_FLAG_ARRAY_STRIDE         = $808C;
-  GL_VERTEX_ARRAY_POINTER           = $808E;
-  GL_NORMAL_ARRAY_POINTER           = $808F;
-  GL_COLOR_ARRAY_POINTER            = $8090;
-  GL_INDEX_ARRAY_POINTER            = $8091;
-  GL_TEXTURE_COORD_ARRAY_POINTER    = $8092;
-  GL_EDGE_FLAG_ARRAY_POINTER        = $8093;
-  GL_V2F                            = $2A20;
-  GL_V3F                            = $2A21;
-  GL_C4UB_V2F                       = $2A22;
-  GL_C4UB_V3F                       = $2A23;
-  GL_C3F_V3F                        = $2A24;
-  GL_N3F_V3F                        = $2A25;
-  GL_C4F_N3F_V3F                    = $2A26;
-  GL_T2F_V3F                        = $2A27;
-  GL_T4F_V4F                        = $2A28;
-  GL_T2F_C4UB_V3F                   = $2A29;
-  GL_T2F_C3F_V3F                    = $2A2A;
-  GL_T2F_N3F_V3F                    = $2A2B;
-  GL_T2F_C4F_N3F_V3F                = $2A2C;
-  GL_T4F_C4F_N3F_V4F                = $2A2D;
-
-  // Extensions
-  GL_EXT_vertex_array               = 1;
-  GL_WIN_swap_hint                  = 1;
-  GL_EXT_bgra                       = 1;
-  GL_EXT_paletted_texture           = 1;
-
-  // EXT_vertex_array
-  GL_VERTEX_ARRAY_EXT               = $8074;
-  GL_NORMAL_ARRAY_EXT               = $8075;
-  GL_COLOR_ARRAY_EXT                = $8076;
-  GL_INDEX_ARRAY_EXT                = $8077;
-  GL_TEXTURE_COORD_ARRAY_EXT        = $8078;
-  GL_EDGE_FLAG_ARRAY_EXT            = $8079;
-  GL_VERTEX_ARRAY_SIZE_EXT          = $807A;
-  GL_VERTEX_ARRAY_TYPE_EXT          = $807B;
-  GL_VERTEX_ARRAY_STRIDE_EXT        = $807C;
-  GL_VERTEX_ARRAY_COUNT_EXT         = $807D;
-  GL_NORMAL_ARRAY_TYPE_EXT          = $807E;
-  GL_NORMAL_ARRAY_STRIDE_EXT        = $807F;
-  GL_NORMAL_ARRAY_COUNT_EXT         = $8080;
-  GL_COLOR_ARRAY_SIZE_EXT           = $8081;
-  GL_COLOR_ARRAY_TYPE_EXT           = $8082;
-  GL_COLOR_ARRAY_STRIDE_EXT         = $8083;
-  GL_COLOR_ARRAY_COUNT_EXT          = $8084;
-  GL_INDEX_ARRAY_TYPE_EXT           = $8085;
-  GL_INDEX_ARRAY_STRIDE_EXT         = $8086;
-  GL_INDEX_ARRAY_COUNT_EXT          = $8087;
-  GL_TEXTURE_COORD_ARRAY_SIZE_EXT   = $8088;
-  GL_TEXTURE_COORD_ARRAY_TYPE_EXT   = $8089;
-  GL_TEXTURE_COORD_ARRAY_STRIDE_EXT = $808A;
-  GL_TEXTURE_COORD_ARRAY_COUNT_EXT  = $808B;
-  GL_EDGE_FLAG_ARRAY_STRIDE_EXT     = $808C;
-  GL_EDGE_FLAG_ARRAY_COUNT_EXT      = $808D;
-  GL_VERTEX_ARRAY_POINTER_EXT       = $808E;
-  GL_NORMAL_ARRAY_POINTER_EXT       = $808F;
-  GL_COLOR_ARRAY_POINTER_EXT        = $8090;
-  GL_INDEX_ARRAY_POINTER_EXT        = $8091;
-  GL_TEXTURE_COORD_ARRAY_POINTER_EXT = $8092;
-  GL_EDGE_FLAG_ARRAY_POINTER_EXT    = $8093;
-  GL_DOUBLE_EXT                     = GL_DOUBLE;
-
-  // EXT_bgra 
-  GL_BGR_EXT                        = $80E0;
-  GL_BGRA_EXT                       = $80E1;
-
-  // EXT_paletted_texture
-
-  // These must match the GL_COLOR_TABLE_*_SGI enumerants
-  GL_COLOR_TABLE_FORMAT_EXT         = $80D8;
-  GL_COLOR_TABLE_WIDTH_EXT          = $80D9;
-  GL_COLOR_TABLE_RED_SIZE_EXT       = $80DA;
-  GL_COLOR_TABLE_GREEN_SIZE_EXT     = $80DB;
-  GL_COLOR_TABLE_BLUE_SIZE_EXT      = $80DC;
-  GL_COLOR_TABLE_ALPHA_SIZE_EXT     = $80DD;
-  GL_COLOR_TABLE_LUMINANCE_SIZE_EXT = $80DE;
-  GL_COLOR_TABLE_INTENSITY_SIZE_EXT = $80DF;
-
-  GL_COLOR_INDEX1_EXT               = $80E2;
-  GL_COLOR_INDEX2_EXT               = $80E3;
-  GL_COLOR_INDEX4_EXT               = $80E4;
-  GL_COLOR_INDEX8_EXT               = $80E5;
-  GL_COLOR_INDEX12_EXT              = $80E6;
-  GL_COLOR_INDEX16_EXT              = $80E7;
-
-  // For compatibility with OpenGL v1.0
-  GL_LOGIC_OP                       = GL_INDEX_LOGIC_OP;
-  GL_TEXTURE_COMPONENTS             = GL_TEXTURE_INTERNAL_FORMAT;
-
-{******************************************************************************}
-
-var
-  glAccum: procedure(op: GLenum; value: GLfloat); stdcall;
-  glAlphaFunc: procedure(func: GLenum; ref: GLclampf); stdcall;
-  glAreTexturesResident: function (n: GLsizei; const textures: PGLuint; residences: PGLboolean): GLboolean; stdcall;
-  glArrayElement: procedure(i: GLint); stdcall;
-  glBegin: procedure(mode: GLenum); stdcall;
-  glBindTexture: procedure(target: GLenum; texture: GLuint); stdcall;
-  glBitmap: procedure (width, height: GLsizei; xorig, yorig: GLfloat; xmove, ymove: GLfloat; const bitmap: PGLubyte); stdcall;
-  glBlendFunc: procedure(sfactor, dfactor: GLenum); stdcall;
-  glCallList: procedure(list: GLuint); stdcall;
-  glCallLists: procedure(n: GLsizei; atype: GLenum; const lists: Pointer); stdcall;
-  glClear: procedure(mask: GLbitfield); stdcall;
-  glClearAccum: procedure(red, green, blue, alpha: GLfloat); stdcall;
-  glClearColor: procedure(red, green, blue, alpha: GLclampf); stdcall;
-  glClearDepth: procedure(depth: GLclampd); stdcall;
-  glClearIndex: procedure(c: GLfloat); stdcall;
-  glClearStencil: procedure(s: GLint); stdcall;
-  glClipPlane: procedure(plane: GLenum; const equation: PGLdouble); stdcall;
-  glColor3b: procedure(red, green, blue: GLbyte); stdcall;
-  glColor3bv: procedure(const v: PGLbyte); stdcall;
-  glColor3d: procedure(red, green, blue: GLdouble); stdcall;
-  glColor3dv: procedure(const v: PGLdouble); stdcall;
-  glColor3f: procedure(red, green, blue: GLfloat); stdcall;
-  glColor3fv: procedure(const v: PGLfloat); stdcall;
-  glColor3i: procedure(red, green, blue: GLint); stdcall;
-  glColor3iv: procedure(const v: PGLint); stdcall;
-  glColor3s: procedure(red, green, blue: GLshort); stdcall;
-  glColor3sv: procedure(const v: PGLshort); stdcall;
-  glColor3ub: procedure(red, green, blue: GLubyte); stdcall;
-  glColor3ubv: procedure(const v: PGLubyte); stdcall;
-  glColor3ui: procedure(red, green, blue: GLuint); stdcall;
-  glColor3uiv: procedure(const v: PGLuint); stdcall;
-  glColor3us: procedure(red, green, blue: GLushort); stdcall;
-  glColor3usv: procedure(const v: PGLushort); stdcall;
-  glColor4b: procedure(red, green, blue, alpha: GLbyte); stdcall;
-  glColor4bv: procedure(const v: PGLbyte); stdcall;
-  glColor4d: procedure(red, green, blue, alpha: GLdouble); stdcall;
-  glColor4dv: procedure(const v: PGLdouble); stdcall;
-  glColor4f: procedure(red, green, blue, alpha: GLfloat); stdcall;
-  glColor4fv: procedure(const v: PGLfloat); stdcall;
-  glColor4i: procedure(red, green, blue, alpha: GLint); stdcall;
-  glColor4iv: procedure(const v: PGLint); stdcall;
-  glColor4s: procedure(red, green, blue, alpha: GLshort); stdcall;
-  glColor4sv: procedure(const v: PGLshort); stdcall;
-  glColor4ub: procedure(red, green, blue, alpha: GLubyte); stdcall;
-  glColor4ubv: procedure(const v: PGLubyte); stdcall;
-  glColor4ui: procedure(red, green, blue, alpha: GLuint); stdcall;
-  glColor4uiv: procedure(const v: PGLuint); stdcall;
-  glColor4us: procedure(red, green, blue, alpha: GLushort); stdcall;
-  glColor4usv: procedure(const v: PGLushort); stdcall;
-  glColorMask: procedure(red, green, blue, alpha: GLboolean); stdcall;
-  glColorMaterial: procedure(face, mode: GLenum); stdcall;
-  glColorPointer: procedure(size: GLint; atype: GLenum; stride: GLsizei; const pointer: Pointer); stdcall;
-  glCopyPixels: procedure(x, y: GLint; width, height: GLsizei; atype: GLenum); stdcall;
-  glCopyTexImage1D: procedure (target: GLenum; level: GLint; internalFormat: GLenum; x, y: GLint; width: GLsizei; border: GLint); stdcall;
-  glCopyTexImage2D: procedure(target: GLenum; level: GLint; internalFormat: GLenum; x, y: GLint; width, height: GLsizei; border: GLint); stdcall;
-  glCopyTexSubImage1D: procedure(target: GLenum; level, xoffset, x, y: GLint; width: GLsizei); stdcall;
-  glCopyTexSubImage2D: procedure(target: GLenum; level, xoffset, yoffset, x, y: GLint; width, height: GLsizei); stdcall;
-  glCullFace: procedure(mode: GLenum); stdcall;
-  glDeleteLists: procedure(list: GLuint; range: GLsizei); stdcall;
-  glDeleteTextures: procedure(n: GLsizei; const textures: PGLuint); stdcall;
-  glDepthFunc: procedure(func: GLenum); stdcall;
-  glDepthMask: procedure(flag: GLboolean); stdcall;
-  glDepthRange: procedure(zNear, zFar: GLclampd); stdcall;
-  glDisable: procedure(cap: GLenum); stdcall;
-  glDisableClientState: procedure(aarray: GLenum); stdcall;
-  glDrawArrays: procedure(mode: GLenum; first: GLint; count: GLsizei); stdcall;
-  glDrawBuffer: procedure(mode: GLenum); stdcall;
-  glDrawElements: procedure(mode: GLenum; count: GLsizei; atype: GLenum; const indices: Pointer); stdcall;
-  glDrawPixels: procedure(width, height: GLsizei; format, atype: GLenum; const pixels: Pointer); stdcall;
-  glEdgeFlag: procedure(flag: GLboolean); stdcall;
-  glEdgeFlagPointer: procedure(stride: GLsizei; const pointer: Pointer); stdcall;
-  glEdgeFlagv: procedure(const flag: PGLboolean); stdcall;
-  glEnable: procedure(cap: GLenum); stdcall;
-  glEnableClientState: procedure(aarray: GLenum); stdcall;
-  glEnd: procedure; stdcall;
-  glEndList: procedure; stdcall;
-  glEvalCoord1d: procedure(u: GLdouble); stdcall;
-  glEvalCoord1dv: procedure(const u: PGLdouble); stdcall;
-  glEvalCoord1f: procedure(u: GLfloat); stdcall;
-  glEvalCoord1fv: procedure(const u: PGLfloat); stdcall;
-  glEvalCoord2d: procedure(u, v: GLdouble); stdcall;
-  glEvalCoord2dv: procedure(const u: PGLdouble); stdcall;
-  glEvalCoord2f: procedure(u, v: GLfloat); stdcall;
-  glEvalCoord2fv: procedure(const u: PGLfloat); stdcall;
-  glEvalMesh1: procedure(mode: GLenum; i1, i2: GLint); stdcall;
-  glEvalMesh2: procedure(mode: GLenum; i1, i2, j1, j2: GLint); stdcall;
-  glEvalPoint1: procedure(i: GLint); stdcall;
-  glEvalPoint2: procedure(i, j: GLint); stdcall;
-  glFeedbackBuffer: procedure(size: GLsizei; atype: GLenum; buffer: PGLfloat); stdcall;
-  glFinish: procedure; stdcall;
-  glFlush: procedure; stdcall;
-  glFogf: procedure(pname: GLenum; param: GLfloat); stdcall;
-  glFogfv: procedure(pname: GLenum; const params: PGLfloat); stdcall;
-  glFogi: procedure(pname: GLenum; param: GLint); stdcall;
-  glFogiv: procedure(pname: GLenum; const params: PGLint); stdcall;
-  glFrontFace: procedure(mode: GLenum); stdcall;
-  glFrustum: procedure(left, right, bottom, top, zNear, zFar: GLdouble); stdcall;
-  glGenLists: function(range: GLsizei): GLuint; stdcall;
-  glGenTextures: procedure(n: GLsizei; textures: PGLuint); stdcall;
-  glGetBooleanv: procedure(pname: GLenum; params: PGLboolean); stdcall;
-  glGetClipPlane: procedure(plane: GLenum; equation: PGLdouble); stdcall;
-  glGetDoublev: procedure(pname: GLenum; params: PGLdouble); stdcall;
-  glGetError: function: GLenum; stdcall;
-  glGetFloatv: procedure(pname: GLenum; params: PGLfloat); stdcall;
-  glGetIntegerv: procedure(pname: GLenum; params: PGLint); stdcall;
-  glGetLightfv: procedure(light, pname: GLenum; params: PGLfloat); stdcall;
-  glGetLightiv: procedure(light, pname: GLenum; params: PGLint); stdcall;
-  glGetMapdv: procedure(target, query: GLenum; v: PGLdouble); stdcall;
-  glGetMapfv: procedure(target, query: GLenum; v: PGLfloat); stdcall;
-  glGetMapiv: procedure(target, query: GLenum; v: GLint); stdcall;
-  glGetMaterialfv: procedure(face, pname: GLenum; params: PGLfloat); stdcall;
-  glGetMaterialiv: procedure(face, pname: GLenum; params: GLint); stdcall;
-  glGetPixelMapfv: procedure(map: GLenum; values: PGLfloat); stdcall;
-  glGetPixelMapuiv: procedure(map: GLenum; values: PGLuint); stdcall;
-  glGetPixelMapusv: procedure(map: GLenum; values: PGLushort); stdcall;
-  glGetPointerv: procedure(pname: GLenum; params: Pointer); stdcall;
-  glGetPolygonStipple: procedure(mask: PGLubyte); stdcall;
-  glGetString: function(name: GLenum): PGLubyte; stdcall;
-  glGetTexEnvfv: procedure(target, pname: GLenum; params: PGLfloat); stdcall;
-  glGetTexEnviv: procedure(target, pname: GLenum; params: PGLint); stdcall;
-  glGetTexGendv: procedure(coord, pname: GLenum; params: PGLdouble); stdcall;
-  glGetTexGenfv: procedure(coord, pname: GLenum; params: PGLfloat); stdcall;
-  glGetTexGeniv: procedure(coord, pname: GLenum; params: PGLint); stdcall;
-  glGetTexImage: procedure(target: GLenum; level: GLint; format: GLenum; atype: GLenum; pixels: Pointer); stdcall;
-  glGetTexLevelParameterfv: procedure(target: GLenum; level: GLint; pname: GLenum; params: Pointer); stdcall;
-  glGetTexLevelParameteriv: procedure(target: GLenum; level: GLint; pname: GLenum; params: PGLint); stdcall;
-  glGetTexParameterfv: procedure(target, pname: GLenum; params: PGLfloat); stdcall;
-  glGetTexParameteriv: procedure(target, pname: GLenum; params: PGLint); stdcall;
-  glHint: procedure(target, mode: GLenum); stdcall;
-  glIndexMask: procedure(mask: GLuint); stdcall;
-  glIndexPointer: procedure(atype: GLenum; stride: GLsizei; const pointer: Pointer); stdcall;
-  glIndexd: procedure(c: GLdouble); stdcall;
-  glIndexdv: procedure(const c: PGLdouble); stdcall;
-  glIndexf: procedure(c: GLfloat); stdcall;
-  glIndexfv: procedure(const c: PGLfloat); stdcall;
-  glIndexi: procedure(c: GLint); stdcall;
-  glIndexiv: procedure(const c: PGLint); stdcall;
-  glIndexs: procedure(c: GLshort); stdcall;
-  glIndexsv: procedure(const c: PGLshort); stdcall;
-  glIndexub: procedure(c: GLubyte); stdcall;
-  glIndexubv: procedure(const c: PGLubyte); stdcall;
-  glInitNames: procedure; stdcall;
-  glInterleavedArrays: procedure(format: GLenum; stride: GLsizei; const pointer: Pointer); stdcall;
-  glIsEnabled: function(cap: GLenum): GLboolean; stdcall;
-  glIsList: function(list: GLuint): GLboolean; stdcall;
-  glIsTexture: function(texture: GLuint): GLboolean; stdcall;
-  glLightModelf: procedure(pname: GLenum; param: GLfloat); stdcall;
-  glLightModelfv: procedure(pname: GLenum; const params: PGLfloat); stdcall;
-  glLightModeli: procedure(pname: GLenum; param: GLint); stdcall;
-  glLightModeliv: procedure(pname: GLenum; const params: PGLint); stdcall;
-  glLightf: procedure(light, pname: GLenum; param: GLfloat); stdcall;
-  glLightfv: procedure(light, pname: GLenum; const params: PGLfloat); stdcall;
-  glLighti: procedure(light, pname: GLenum; param: GLint); stdcall;
-  glLightiv: procedure(light, pname: GLenum; const params: GLint); stdcall;
-  glLineStipple: procedure(factor: GLint; pattern: GLushort); stdcall;
-  glLineWidth: procedure(width: GLfloat); stdcall;
-  glListBase: procedure(base: GLuint); stdcall;
-  glLoadIdentity: procedure; stdcall;
-  glLoadMatrixd: procedure(const m: PGLdouble); stdcall;
-  glLoadMatrixf: procedure(const m: PGLfloat); stdcall;
-  glLoadName: procedure(name: GLuint); stdcall;
-  glLogicOp: procedure(opcode: GLenum); stdcall;
-  glMap1d: procedure(target: GLenum; u1, u2: GLdouble; stride, order: GLint; const points: PGLdouble); stdcall;
-  glMap1f: procedure(target: GLenum; u1, u2: GLfloat; stride, order: GLint; const points: PGLfloat); stdcall;
-  glMap2d: procedure(target: GLenum; u1, u2: GLdouble; ustride, uorder: GLint; v1, v2: GLdouble; vstride, vorder: GLint; const points: PGLdouble); stdcall;
-  glMap2f: procedure(target: GLenum; u1, u2: GLfloat; ustride, uorder: GLint; v1, v2: GLfloat; vstride, vorder: GLint; const points: PGLfloat); stdcall;
-  glMapGrid1d: procedure(un: GLint; u1, u2: GLdouble); stdcall;
-  glMapGrid1f: procedure(un: GLint; u1, u2: GLfloat); stdcall;
-  glMapGrid2d: procedure(un: GLint; u1, u2: GLdouble; vn: GLint; v1, v2: GLdouble); stdcall;
-  glMapGrid2f: procedure(un: GLint; u1, u2: GLfloat; vn: GLint; v1, v2: GLfloat); stdcall;
-  glMaterialf: procedure(face, pname: GLenum; param: GLfloat); stdcall;
-  glMaterialfv: procedure(face, pname: GLenum; const params: PGLfloat); stdcall;
-  glMateriali: procedure(face, pname: GLenum; param: GLint); stdcall;
-  glMaterialiv: procedure(face, pname: GLenum; const params: PGLint); stdcall;
-  glMatrixMode: procedure(mode: GLenum); stdcall;
-  glMultMatrixd: procedure(const m: PGLdouble); stdcall;
-  glMultMatrixf: procedure(const m: PGLfloat); stdcall;
-  glNewList: procedure(list: GLuint; mode: GLenum); stdcall;
-  glNormal3b: procedure(nx, ny, nz: GLbyte); stdcall;
-  glNormal3bv: procedure(const v: PGLbyte); stdcall;
-  glNormal3d: procedure(nx, ny, nz: GLdouble); stdcall;
-  glNormal3dv: procedure(const v: PGLdouble); stdcall;
-  glNormal3f: procedure(nx, ny, nz: GLfloat); stdcall;
-  glNormal3fv: procedure(const v: PGLfloat); stdcall;
-  glNormal3i: procedure(nx, ny, nz: GLint); stdcall;
-  glNormal3iv: procedure(const v: PGLint); stdcall;
-  glNormal3s: procedure(nx, ny, nz: GLshort); stdcall;
-  glNormal3sv: procedure(const v: PGLshort); stdcall;
-  glNormalPointer: procedure(atype: GLenum; stride: GLsizei; const pointer: Pointer); stdcall;
-  glOrtho: procedure(left, right, bottom, top, zNear, zFar: GLdouble); stdcall;
-  glPassThrough: procedure(token: GLfloat); stdcall;
-  glPixelMapfv: procedure(map: GLenum; mapsize: GLsizei; const values: PGLfloat); stdcall;
-  glPixelMapuiv: procedure(map: GLenum; mapsize: GLsizei; const values: PGLuint); stdcall;
-  glPixelMapusv: procedure(map: GLenum; mapsize: GLsizei; const values: PGLushort); stdcall;
-  glPixelStoref: procedure(pname: GLenum; param: GLfloat); stdcall;
-  glPixelStorei: procedure(pname: GLenum; param: GLint); stdcall;
-  glPixelTransferf: procedure(pname: GLenum; param: GLfloat); stdcall;
-  glPixelTransferi: procedure(pname: GLenum; param: GLint); stdcall;
-  glPixelZoom: procedure(xfactor, yfactor: GLfloat); stdcall;
-  glPointSize: procedure(size: GLfloat); stdcall;
-  glPolygonMode: procedure(face, mode: GLenum); stdcall;
-  glPolygonOffset: procedure(factor, units: GLfloat); stdcall;
-  glPolygonStipple: procedure(const mask: PGLubyte); stdcall;
-  glPopAttrib: procedure; stdcall;
-  glPopClientAttrib: procedure; stdcall;
-  glPopMatrix: procedure; stdcall;
-  glPopName: procedure; stdcall;
-  glPrioritizeTextures: procedure(n: GLsizei; const textures: PGLuint; const priorities: PGLclampf); stdcall;
-  glPushAttrib: procedure(mask: GLbitfield); stdcall;
-  glPushClientAttrib: procedure(mask: GLbitfield); stdcall;
-  glPushMatrix: procedure; stdcall;
-  glPushName: procedure(name: GLuint); stdcall;
-  glRasterPos2d: procedure(x, y: GLdouble); stdcall;
-  glRasterPos2dv: procedure(const v: PGLdouble); stdcall;
-  glRasterPos2f: procedure(x, y: GLfloat); stdcall;
-  glRasterPos2fv: procedure(const v: PGLfloat); stdcall;
-  glRasterPos2i: procedure(x, y: GLint); stdcall;
-  glRasterPos2iv: procedure(const v: PGLint); stdcall;
-  glRasterPos2s: procedure(x, y: GLshort); stdcall;
-  glRasterPos2sv: procedure(const v: PGLshort); stdcall;
-  glRasterPos3d: procedure(x, y, z: GLdouble); stdcall;
-  glRasterPos3dv: procedure(const v: PGLdouble); stdcall;
-  glRasterPos3f: procedure(x, y, z: GLfloat); stdcall;
-  glRasterPos3fv: procedure(const v: PGLfloat); stdcall;
-  glRasterPos3i: procedure(x, y, z: GLint); stdcall;
-  glRasterPos3iv: procedure(const v: PGLint); stdcall;
-  glRasterPos3s: procedure(x, y, z: GLshort); stdcall;
-  glRasterPos3sv: procedure(const v: PGLshort); stdcall;
-  glRasterPos4d: procedure(x, y, z, w: GLdouble); stdcall;
-  glRasterPos4dv: procedure(const v: PGLdouble); stdcall;
-  glRasterPos4f: procedure(x, y, z, w: GLfloat); stdcall;
-  glRasterPos4fv: procedure(const v: PGLfloat); stdcall;
-  glRasterPos4i: procedure(x, y, z, w: GLint); stdcall;
-  glRasterPos4iv: procedure(const v: PGLint); stdcall;
-  glRasterPos4s: procedure(x, y, z, w: GLshort); stdcall;
-  glRasterPos4sv: procedure(const v: PGLshort); stdcall;
-  glReadBuffer: procedure(mode: GLenum); stdcall;
-  glReadPixels: procedure(x, y: GLint; width, height: GLsizei; format, atype: GLenum; pixels: Pointer); stdcall;
-  glRectd: procedure(x1, y1, x2, y2: GLdouble); stdcall;
-  glRectdv: procedure(const v1: PGLdouble; const v2: PGLdouble); stdcall;
-  glRectf: procedure(x1, y1, x2, y2: GLfloat); stdcall;
-  glRectfv: procedure(const v1: PGLfloat; const v2: PGLfloat); stdcall;
-  glRecti: procedure(x1, y1, x2, y2: GLint); stdcall;
-  glRectiv: procedure(const v1: PGLint; const v2: PGLint); stdcall;
-  glRects: procedure(x1, y1, x2, y2: GLshort); stdcall;
-  glRectsv: procedure(const v1: PGLshort; const v2: PGLshort); stdcall;
-  glRenderMode: function(mode: GLint): GLint; stdcall;
-  glRotated: procedure(angle, x, y, z: GLdouble); stdcall;
-  glRotatef: procedure(angle, x, y, z: GLfloat); stdcall;
-  glScaled: procedure(x, y, z: GLdouble); stdcall;
-  glScalef: procedure(x, y, z: GLfloat); stdcall;
-  glScissor: procedure(x, y: GLint; width, height: GLsizei); stdcall;
-  glSelectBuffer: procedure(size: GLsizei; buffer: PGLuint); stdcall;
-  glShadeModel: procedure(mode: GLenum); stdcall;
-  glStencilFunc: procedure(func: GLenum; ref: GLint; mask: GLuint); stdcall;
-  glStencilMask: procedure(mask: GLuint); stdcall;
-  glStencilOp: procedure(fail, zfail, zpass: GLenum); stdcall;
-  glTexCoord1d: procedure(s: GLdouble); stdcall;
-  glTexCoord1dv: procedure(const v: PGLdouble); stdcall;
-  glTexCoord1f: procedure(s: GLfloat); stdcall;
-  glTexCoord1fv: procedure(const v: PGLfloat); stdcall;
-  glTexCoord1i: procedure(s: GLint); stdcall;
-  glTexCoord1iv: procedure(const v: PGLint); stdcall;
-  glTexCoord1s: procedure(s: GLshort); stdcall;
-  glTexCoord1sv: procedure(const v: PGLshort); stdcall;
-  glTexCoord2d: procedure(s, t: GLdouble); stdcall;
-  glTexCoord2dv: procedure(const v: PGLdouble); stdcall;
-  glTexCoord2f: procedure(s, t: GLfloat); stdcall;
-  glTexCoord2fv: procedure(const v: PGLfloat); stdcall;
-  glTexCoord2i: procedure(s, t: GLint); stdcall;
-  glTexCoord2iv: procedure(const v: PGLint); stdcall;
-  glTexCoord2s: procedure(s, t: GLshort); stdcall;
-  glTexCoord2sv: procedure(const v: PGLshort); stdcall;
-  glTexCoord3d: procedure(s, t, r: GLdouble); stdcall;
-  glTexCoord3dv: procedure(const v: PGLdouble); stdcall;
-  glTexCoord3f: procedure(s, t, r: GLfloat); stdcall;
-  glTexCoord3fv: procedure(const v: PGLfloat); stdcall;
-  glTexCoord3i: procedure(s, t, r: GLint); stdcall;
-  glTexCoord3iv: procedure(const v: PGLint); stdcall;
-  glTexCoord3s: procedure(s, t, r: GLshort); stdcall;
-  glTexCoord3sv: procedure(const v: PGLshort); stdcall;
-  glTexCoord4d: procedure(s, t, r, q: GLdouble); stdcall;
-  glTexCoord4dv: procedure(const v: PGLdouble); stdcall;
-  glTexCoord4f: procedure(s, t, r, q: GLfloat); stdcall;
-  glTexCoord4fv: procedure(const v: PGLfloat); stdcall;
-  glTexCoord4i: procedure(s, t, r, q: GLint); stdcall;
-  glTexCoord4iv: procedure(const v: PGLint); stdcall;
-  glTexCoord4s: procedure(s, t, r, q: GLshort); stdcall;
-  glTexCoord4sv: procedure(const v: PGLshort); stdcall;
-  glTexCoordPointer: procedure(size: GLint; atype: GLenum; stride: GLsizei; const pointer: Pointer); stdcall;
-  glTexEnvf: procedure(target: GLenum; pname: GLenum; param: GLfloat); stdcall;
-  glTexEnvfv: procedure(target: GLenum; pname: GLenum; const params: PGLfloat); stdcall;
-  glTexEnvi: procedure(target: GLenum; pname: GLenum; param: GLint); stdcall;
-  glTexEnviv: procedure(target: GLenum; pname: GLenum; const params: PGLint); stdcall;
-  glTexGend: procedure(coord: GLenum; pname: GLenum; param: GLdouble); stdcall;
-  glTexGendv: procedure(coord: GLenum; pname: GLenum; const params: PGLdouble); stdcall;
-  glTexGenf: procedure(coord: GLenum; pname: GLenum; param: GLfloat); stdcall;
-  glTexGenfv: procedure(coord: GLenum; pname: GLenum; const params: PGLfloat); stdcall;
-  glTexGeni: procedure(coord: GLenum; pname: GLenum; param: GLint); stdcall;
-  glTexGeniv: procedure(coord: GLenum; pname: GLenum; const params: PGLint); stdcall;
-  glTexImage1D: procedure(target: GLenum; level, internalformat: GLint; width: GLsizei; border: GLint; format, atype: GLenum; const pixels: Pointer); stdcall;
-  glTexImage2D: procedure(target: GLenum; level, internalformat: GLint; width, height: GLsizei; border: GLint; format, atype: GLenum; const pixels: Pointer); stdcall;
-  glTexParameterf: procedure(target: GLenum; pname: GLenum; param: GLfloat); stdcall;
-  glTexParameterfv: procedure(target: GLenum; pname: GLenum; const params: PGLfloat); stdcall;
-  glTexParameteri: procedure(target: GLenum; pname: GLenum; param: GLint); stdcall;
-  glTexParameteriv: procedure(target: GLenum; pname: GLenum; const params: PGLint); stdcall;
-  glTexSubImage1D: procedure(target: GLenum; level, xoffset: GLint; width: GLsizei; format, atype: GLenum; const pixels: Pointer); stdcall;
-  glTexSubImage2D: procedure(target: GLenum; level, xoffset, yoffset: GLint; width, height: GLsizei; format, atype: GLenum; const pixels: Pointer); stdcall;
-  glTranslated: procedure(x, y, z: GLdouble); stdcall;
-  glTranslatef: procedure(x, y, z: GLfloat); stdcall;
-  glVertex2d: procedure(x, y: GLdouble); stdcall;
-  glVertex2dv: procedure(const v: PGLdouble); stdcall;
-  glVertex2f: procedure(x, y: GLfloat); stdcall;
-  glVertex2fv: procedure(const v: PGLfloat); stdcall;
-  glVertex2i: procedure(x, y: GLint); stdcall;
-  glVertex2iv: procedure(const v: PGLint); stdcall;
-  glVertex2s: procedure(x, y: GLshort); stdcall;
-  glVertex2sv: procedure(const v: PGLshort); stdcall;
-  glVertex3d: procedure(x, y, z: GLdouble); stdcall;
-  glVertex3dv: procedure(const v: PGLdouble); stdcall;
-  glVertex3f: procedure(x, y, z: GLfloat); stdcall;
-  glVertex3fv: procedure(const v: PGLfloat); stdcall;
-  glVertex3i: procedure(x, y, z: GLint); stdcall;
-  glVertex3iv: procedure(const v: PGLint); stdcall;
-  glVertex3s: procedure(x, y, z: GLshort); stdcall;
-  glVertex3sv: procedure(const v: PGLshort); stdcall;
-  glVertex4d: procedure(x, y, z, w: GLdouble); stdcall;
-  glVertex4dv: procedure(const v: PGLdouble); stdcall;
-  glVertex4f: procedure(x, y, z, w: GLfloat); stdcall;
-  glVertex4fv: procedure(const v: PGLfloat); stdcall;
-  glVertex4i: procedure(x, y, z, w: GLint); stdcall;
-  glVertex4iv: procedure(const v: PGLint); stdcall;
-  glVertex4s: procedure(x, y, z, w: GLshort); stdcall;
-  glVertex4sv: procedure(const v: PGLshort); stdcall;
-  glVertexPointer: procedure(size: GLint; atype: GLenum; stride: GLsizei; const pointer: Pointer); stdcall;
-  glViewport: procedure(x, y: GLint; width, height: GLsizei); stdcall;
-  ChoosePixelFormat: function(DC: HDC; p2: PPixelFormatDescriptor): Integer; stdcall;
-
-type
-  // EXT_vertex_array
-  PFNGLARRAYELEMENTEXTPROC = procedure(i: GLint); stdcall;
-  PFNGLDRAWARRAYSEXTPROC = procedure(mode: GLenum; first: GLint; count: GLsizei); stdcall;
-  PFNGLVERTEXPOINTEREXTPROC = procedure(size: GLint; atype: GLenum;
-                                        stride, count: GLsizei; const pointer: Pointer); stdcall;
-  PFNGLNORMALPOINTEREXTPROC = procedure(atype: GLenum; stride, count: GLsizei;
-                                        const pointer: Pointer); stdcall;
-  PFNGLCOLORPOINTEREXTPROC = procedure(size: GLint; atype: GLenum; stride, count: GLsizei;
-                                       const pointer: Pointer); stdcall;
-  PFNGLINDEXPOINTEREXTPROC = procedure(atype: GLenum; stride, count: GLsizei;
-                                       const pointer: Pointer); stdcall;
-  PFNGLTEXCOORDPOINTEREXTPROC = procedure(size: GLint; atype: GLenum;
-                                          stride, count: GLsizei; const pointer: Pointer); stdcall;
-  PFNGLEDGEFLAGPOINTEREXTPROC = procedure(stride, count: GLsizei;
-                                          const pointer: PGLboolean); stdcall;
-  PFNGLGETPOINTERVEXTPROC = procedure(pname: GLenum; params: Pointer); stdcall;
-  PFNGLARRAYELEMENTARRAYEXTPROC = procedure(mode: GLenum; count: GLsizei;
-                                            const pi: Pointer); stdcall;
-
-  // WIN_swap_hint
-  PFNGLADDSWAPHINTRECTWINPROC = procedure(x, y: GLint; width, height: GLsizei); stdcall;
-
-  // EXT_paletted_texture
-  PFNGLCOLORTABLEEXTPROC = procedure(target, internalFormat: GLenum; width: GLsizei;
-                                     format, atype: GLenum; const data: Pointer); stdcall;
-  PFNGLCOLORSUBTABLEEXTPROC = procedure(target: GLenum; start, count: GLsizei;
-                                        format, atype: GLenum; const data: Pointer); stdcall;
-  PFNGLGETCOLORTABLEEXTPROC = procedure(target, format, atype: GLenum; data: Pointer); stdcall;
-  PFNGLGETCOLORTABLEPARAMETERIVEXTPROC = procedure(target, pname: GLenum; params: PGLint); stdcall;
-  PFNGLGETCOLORTABLEPARAMETERFVEXTPROC = procedure(target, pname: GLenum; params: PGLfloat); stdcall;
-
-procedure LoadOpenGL(const dll: String);
-procedure FreeOpenGL;
-
-implementation
-
-var
-  hDLL: THandle;
-
-procedure FreeOpenGL;
-begin
-
-  @glAccum := nil;
-  @glAlphaFunc := nil;
-  @glAreTexturesResident := nil;
-  @glArrayElement := nil;
-  @glBegin := nil;
-  @glBindTexture := nil;
-  @glBitmap := nil;
-  @glBlendFunc := nil;
-  @glCallList := nil;
-  @glCallLists := nil;
-  @glClear := nil;
-  @glClearAccum := nil;
-  @glClearColor := nil;
-  @glClearDepth := nil;
-  @glClearIndex := nil;
-  @glClearStencil := nil;
-  @glClipPlane := nil;
-  @glColor3b := nil;
-  @glColor3bv := nil;
-  @glColor3d := nil;
-  @glColor3dv := nil;
-  @glColor3f := nil;
-  @glColor3fv := nil;
-  @glColor3i := nil;
-  @glColor3iv := nil;
-  @glColor3s := nil;
-  @glColor3sv := nil;
-  @glColor3ub := nil;
-  @glColor3ubv := nil;
-  @glColor3ui := nil;
-  @glColor3uiv := nil;
-  @glColor3us := nil;
-  @glColor3usv := nil;
-  @glColor4b := nil;
-  @glColor4bv := nil;
-  @glColor4d := nil;
-  @glColor4dv := nil;
-  @glColor4f := nil;
-  @glColor4fv := nil;
-  @glColor4i := nil;
-  @glColor4iv := nil;
-  @glColor4s := nil;
-  @glColor4sv := nil;
-  @glColor4ub := nil;
-  @glColor4ubv := nil;
-  @glColor4ui := nil;
-  @glColor4uiv := nil;
-  @glColor4us := nil;
-  @glColor4usv := nil;
-  @glColorMask := nil;
-  @glColorMaterial := nil;
-  @glColorPointer := nil;
-  @glCopyPixels := nil;
-  @glCopyTexImage1D := nil;
-  @glCopyTexImage2D := nil;
-  @glCopyTexSubImage1D := nil;
-  @glCopyTexSubImage2D := nil;
-  @glCullFace := nil;
-  @glDeleteLists := nil;
-  @glDeleteTextures := nil;
-  @glDepthFunc := nil;
-  @glDepthMask := nil;
-  @glDepthRange := nil;
-  @glDisable := nil;
-  @glDisableClientState := nil;
-  @glDrawArrays := nil;
-  @glDrawBuffer := nil;
-  @glDrawElements := nil;
-  @glDrawPixels := nil;
-  @glEdgeFlag := nil;
-  @glEdgeFlagPointer := nil;
-  @glEdgeFlagv := nil;
-  @glEnable := nil;
-  @glEnableClientState := nil;
-  @glEnd := nil;
-  @glEndList := nil;
-  @glEvalCoord1d := nil;
-  @glEvalCoord1dv := nil;
-  @glEvalCoord1f := nil;
-  @glEvalCoord1fv := nil;
-  @glEvalCoord2d := nil;
-  @glEvalCoord2dv := nil;
-  @glEvalCoord2f := nil;
-  @glEvalCoord2fv := nil;
-  @glEvalMesh1 := nil;
-  @glEvalMesh2 := nil;
-  @glEvalPoint1 := nil;
-  @glEvalPoint2 := nil;
-  @glFeedbackBuffer := nil;
-  @glFinish := nil;
-  @glFlush := nil;
-  @glFogf := nil;
-  @glFogfv := nil;
-  @glFogi := nil;
-  @glFogiv := nil;
-  @glFrontFace := nil;
-  @glFrustum := nil;
-  @glGenLists := nil;
-  @glGenTextures := nil;
-  @glGetBooleanv := nil;
-  @glGetClipPlane := nil;
-  @glGetDoublev := nil;
-  @glGetError := nil;
-  @glGetFloatv := nil;
-  @glGetIntegerv := nil;
-  @glGetLightfv := nil;
-  @glGetLightiv := nil;
-  @glGetMapdv := nil;
-  @glGetMapfv := nil;
-  @glGetMapiv := nil;
-  @glGetMaterialfv := nil;
-  @glGetMaterialiv := nil;
-  @glGetPixelMapfv := nil;
-  @glGetPixelMapuiv := nil;
-  @glGetPixelMapusv := nil;
-  @glGetPointerv := nil;
-  @glGetPolygonStipple := nil;
-  @glGetString := nil;
-  @glGetTexEnvfv := nil;
-  @glGetTexEnviv := nil;
-  @glGetTexGendv := nil;
-  @glGetTexGenfv := nil;
-  @glGetTexGeniv := nil;
-  @glGetTexImage := nil;
-  @glGetTexLevelParameterfv := nil;
-  @glGetTexLevelParameteriv := nil;
-  @glGetTexParameterfv := nil;
-  @glGetTexParameteriv := nil;
-  @glHint := nil;
-  @glIndexMask := nil;
-  @glIndexPointer := nil;
-  @glIndexd := nil;
-  @glIndexdv := nil;
-  @glIndexf := nil;
-  @glIndexfv := nil;
-  @glIndexi := nil;
-  @glIndexiv := nil;
-  @glIndexs := nil;
-  @glIndexsv := nil;
-  @glIndexub := nil;
-  @glIndexubv := nil;
-  @glInitNames := nil;
-  @glInterleavedArrays := nil;
-  @glIsEnabled := nil;
-  @glIsList := nil;
-  @glIsTexture := nil;
-  @glLightModelf := nil;
-  @glLightModelfv := nil;
-  @glLightModeli := nil;
-  @glLightModeliv := nil;
-  @glLightf := nil;
-  @glLightfv := nil;
-  @glLighti := nil;
-  @glLightiv := nil;
-  @glLineStipple := nil;
-  @glLineWidth := nil;
-  @glListBase := nil;
-  @glLoadIdentity := nil;
-  @glLoadMatrixd := nil;
-  @glLoadMatrixf := nil;
-  @glLoadName := nil;
-  @glLogicOp := nil;
-  @glMap1d := nil;
-  @glMap1f := nil;
-  @glMap2d := nil;
-  @glMap2f := nil;
-  @glMapGrid1d := nil;
-  @glMapGrid1f := nil;
-  @glMapGrid2d := nil;
-  @glMapGrid2f := nil;
-  @glMaterialf := nil;
-  @glMaterialfv := nil;
-  @glMateriali := nil;
-  @glMaterialiv := nil;
-  @glMatrixMode := nil;
-  @glMultMatrixd := nil;
-  @glMultMatrixf := nil;
-  @glNewList := nil;
-  @glNormal3b := nil;
-  @glNormal3bv := nil;
-  @glNormal3d := nil;
-  @glNormal3dv := nil;
-  @glNormal3f := nil;
-  @glNormal3fv := nil;
-  @glNormal3i := nil;
-  @glNormal3iv := nil;
-  @glNormal3s := nil;
-  @glNormal3sv := nil;
-  @glNormalPointer := nil;
-  @glOrtho := nil;
-  @glPassThrough := nil;
-  @glPixelMapfv := nil;
-  @glPixelMapuiv := nil;
-  @glPixelMapusv := nil;
-  @glPixelStoref := nil;
-  @glPixelStorei := nil;
-  @glPixelTransferf := nil;
-  @glPixelTransferi := nil;
-  @glPixelZoom := nil;
-  @glPointSize := nil;
-  @glPolygonMode := nil;
-  @glPolygonOffset := nil;
-  @glPolygonStipple := nil;
-  @glPopAttrib := nil;
-  @glPopClientAttrib := nil;
-  @glPopMatrix := nil;
-  @glPopName := nil;
-  @glPrioritizeTextures := nil;
-  @glPushAttrib := nil;
-  @glPushClientAttrib := nil;
-  @glPushMatrix := nil;
-  @glPushName := nil;
-  @glRasterPos2d := nil;
-  @glRasterPos2dv := nil;
-  @glRasterPos2f := nil;
-  @glRasterPos2fv := nil;
-  @glRasterPos2i := nil;
-  @glRasterPos2iv := nil;
-  @glRasterPos2s := nil;
-  @glRasterPos2sv := nil;
-  @glRasterPos3d := nil;
-  @glRasterPos3dv := nil;
-  @glRasterPos3f := nil;
-  @glRasterPos3fv := nil;
-  @glRasterPos3i := nil;
-  @glRasterPos3iv := nil;
-  @glRasterPos3s := nil;
-  @glRasterPos3sv := nil;
-  @glRasterPos4d := nil;
-  @glRasterPos4dv := nil;
-  @glRasterPos4f := nil;
-  @glRasterPos4fv := nil;
-  @glRasterPos4i := nil;
-  @glRasterPos4iv := nil;
-  @glRasterPos4s := nil;
-  @glRasterPos4sv := nil;
-  @glReadBuffer := nil;
-  @glReadPixels := nil;
-  @glRectd := nil;
-  @glRectdv := nil;
-  @glRectf := nil;
-  @glRectfv := nil;
-  @glRecti := nil;
-  @glRectiv := nil;
-  @glRects := nil;
-  @glRectsv := nil;
-  @glRenderMode := nil;
-  @glRotated := nil;
-  @glRotatef := nil;
-  @glScaled := nil;
-  @glScalef := nil;
-  @glScissor := nil;
-  @glSelectBuffer := nil;
-  @glShadeModel := nil;
-  @glStencilFunc := nil;
-  @glStencilMask := nil;
-  @glStencilOp := nil;
-  @glTexCoord1d := nil;
-  @glTexCoord1dv := nil;
-  @glTexCoord1f := nil;
-  @glTexCoord1fv := nil;
-  @glTexCoord1i := nil;
-  @glTexCoord1iv := nil;
-  @glTexCoord1s := nil;
-  @glTexCoord1sv := nil;
-  @glTexCoord2d := nil;
-  @glTexCoord2dv := nil;
-  @glTexCoord2f := nil;
-  @glTexCoord2fv := nil;
-  @glTexCoord2i := nil;
-  @glTexCoord2iv := nil;
-  @glTexCoord2s := nil;
-  @glTexCoord2sv := nil;
-  @glTexCoord3d := nil;
-  @glTexCoord3dv := nil;
-  @glTexCoord3f := nil;
-  @glTexCoord3fv := nil;
-  @glTexCoord3i := nil;
-  @glTexCoord3iv := nil;
-  @glTexCoord3s := nil;
-  @glTexCoord3sv := nil;
-  @glTexCoord4d := nil;
-  @glTexCoord4dv := nil;
-  @glTexCoord4f := nil;
-  @glTexCoord4fv := nil;
-  @glTexCoord4i := nil;
-  @glTexCoord4iv := nil;
-  @glTexCoord4s := nil;
-  @glTexCoord4sv := nil;
-  @glTexCoordPointer := nil;
-  @glTexEnvf := nil;
-  @glTexEnvfv := nil;
-  @glTexEnvi := nil;
-  @glTexEnviv := nil;
-  @glTexGend := nil;
-  @glTexGendv := nil;
-  @glTexGenf := nil;
-  @glTexGenfv := nil;
-  @glTexGeni := nil;
-  @glTexGeniv := nil;
-  @glTexImage1D := nil;
-  @glTexImage2D := nil;
-  @glTexParameterf := nil;
-  @glTexParameterfv := nil;
-  @glTexParameteri := nil;
-  @glTexParameteriv := nil;
-  @glTexSubImage1D := nil;
-  @glTexSubImage2D := nil;
-  @glTranslated := nil;
-  @glTranslatef := nil;
-  @glVertex2d := nil;
-  @glVertex2dv := nil;
-  @glVertex2f := nil;
-  @glVertex2fv := nil;
-  @glVertex2i := nil;
-  @glVertex2iv := nil;
-  @glVertex2s := nil;
-  @glVertex2sv := nil;
-  @glVertex3d := nil;
-  @glVertex3dv := nil;
-  @glVertex3f := nil;
-  @glVertex3fv := nil;
-  @glVertex3i := nil;
-  @glVertex3iv := nil;
-  @glVertex3s := nil;
-  @glVertex3sv := nil;
-  @glVertex4d := nil;
-  @glVertex4dv := nil;
-  @glVertex4f := nil;
-  @glVertex4fv := nil;
-  @glVertex4i := nil;
-  @glVertex4iv := nil;
-  @glVertex4s := nil;
-  @glVertex4sv := nil;
-  @glVertexPointer := nil;
-  @glViewport := nil;
-  @ChoosePixelFormat := nil;
-
-  FreeLibrary(hDLL);
-
-end;
-
-procedure LoadOpenGL(const dll: String);
-begin
-
-  FreeOpenGL;
-
-  hDLL := LoadLibrary(PChar(dll));
-  if hDLL = 0 then raise Exception.Create('Could not load OpenGL from ' + dll);
-
-  @glAccum := GetProcAddress(hDLL, 'glAccum');
-  @glAlphaFunc := GetProcAddress(hDLL, 'glAlphaFunc');
-  @glAreTexturesResident := GetProcAddress(hDLL, 'glAreTexturesResident');
-  @glArrayElement := GetProcAddress(hDLL, 'glArrayElement');
-  @glBegin := GetProcAddress(hDLL, 'glBegin');
-  @glBindTexture := GetProcAddress(hDLL, 'glBindTexture');
-  @glBitmap := GetProcAddress(hDLL, 'glBitmap');
-  @glBlendFunc := GetProcAddress(hDLL, 'glBlendFunc');
-  @glCallList := GetProcAddress(hDLL, 'glCallList');
-  @glCallLists := GetProcAddress(hDLL, 'glCallLists');
-  @glClear := GetProcAddress(hDLL, 'glClear');
-  @glClearAccum := GetProcAddress(hDLL, 'glClearAccum');
-  @glClearColor := GetProcAddress(hDLL, 'glClearColor');
-  @glClearDepth := GetProcAddress(hDLL, 'glClearDepth');
-  @glClearIndex := GetProcAddress(hDLL, 'glClearIndex');
-  @glClearStencil := GetProcAddress(hDLL, 'glClearStencil');
-  @glClipPlane := GetProcAddress(hDLL, 'glClipPlane');
-  @glColor3b := GetProcAddress(hDLL, 'glColor3b');
-  @glColor3bv := GetProcAddress(hDLL, 'glColor3bv');
-  @glColor3d := GetProcAddress(hDLL, 'glColor3d');
-  @glColor3dv := GetProcAddress(hDLL, 'glColor3dv');
-  @glColor3f := GetProcAddress(hDLL, 'glColor3f');
-  @glColor3fv := GetProcAddress(hDLL, 'glColor3fv');
-  @glColor3i := GetProcAddress(hDLL, 'glColor3i');
-  @glColor3iv := GetProcAddress(hDLL, 'glColor3iv');
-  @glColor3s := GetProcAddress(hDLL, 'glColor3s');
-  @glColor3sv := GetProcAddress(hDLL, 'glColor3sv');
-  @glColor3ub := GetProcAddress(hDLL, 'glColor3ub');
-  @glColor3ubv := GetProcAddress(hDLL, 'glColor3ubv');
-  @glColor3ui := GetProcAddress(hDLL, 'glColor3ui');
-  @glColor3uiv := GetProcAddress(hDLL, 'glColor3uiv');
-  @glColor3us := GetProcAddress(hDLL, 'glColor3us');
-  @glColor3usv := GetProcAddress(hDLL, 'glColor3usv');
-  @glColor4b := GetProcAddress(hDLL, 'glColor4b');
-  @glColor4bv := GetProcAddress(hDLL, 'glColor4bv');
-  @glColor4d := GetProcAddress(hDLL, 'glColor4d');
-  @glColor4dv := GetProcAddress(hDLL, 'glColor4dv');
-  @glColor4f := GetProcAddress(hDLL, 'glColor4f');
-  @glColor4fv := GetProcAddress(hDLL, 'glColor4fv');
-  @glColor4i := GetProcAddress(hDLL, 'glColor4i');
-  @glColor4iv := GetProcAddress(hDLL, 'glColor4iv');
-  @glColor4s := GetProcAddress(hDLL, 'glColor4s');
-  @glColor4sv := GetProcAddress(hDLL, 'glColor4sv');
-  @glColor4ub := GetProcAddress(hDLL, 'glColor4ub');
-  @glColor4ubv := GetProcAddress(hDLL, 'glColor4ubv');
-  @glColor4ui := GetProcAddress(hDLL, 'glColor4ui');
-  @glColor4uiv := GetProcAddress(hDLL, 'glColor4uiv');
-  @glColor4us := GetProcAddress(hDLL, 'glColor4us');
-  @glColor4usv := GetProcAddress(hDLL, 'glColor4usv');
-  @glColorMask := GetProcAddress(hDLL, 'glColorMask');
-  @glColorMaterial := GetProcAddress(hDLL, 'glColorMaterial');
-  @glColorPointer := GetProcAddress(hDLL, 'glColorPointer');
-  @glCopyPixels := GetProcAddress(hDLL, 'glCopyPixels');
-  @glCopyTexImage1D := GetProcAddress(hDLL, 'glCopyTexImage1D');
-  @glCopyTexImage2D := GetProcAddress(hDLL, 'glCopyTexImage2D');
-  @glCopyTexSubImage1D := GetProcAddress(hDLL, 'glCopyTexSubImage1D');
-  @glCopyTexSubImage2D := GetProcAddress(hDLL, 'glCopyTexSubImage2D');
-  @glCullFace := GetProcAddress(hDLL, 'glCullFace');
-  @glDeleteLists := GetProcAddress(hDLL, 'glDeleteLists');
-  @glDeleteTextures := GetProcAddress(hDLL, 'glDeleteTextures');
-  @glDepthFunc := GetProcAddress(hDLL, 'glDepthFunc');
-  @glDepthMask := GetProcAddress(hDLL, 'glDepthMask');
-  @glDepthRange := GetProcAddress(hDLL, 'glDepthRange');
-  @glDisable := GetProcAddress(hDLL, 'glDisable');
-  @glDisableClientState := GetProcAddress(hDLL, 'glDisableClientState');
-  @glDrawArrays := GetProcAddress(hDLL, 'glDrawArrays');
-  @glDrawBuffer := GetProcAddress(hDLL, 'glDrawBuffer');
-  @glDrawElements := GetProcAddress(hDLL, 'glDrawElements');
-  @glDrawPixels := GetProcAddress(hDLL, 'glDrawPixels');
-  @glEdgeFlag := GetProcAddress(hDLL, 'glEdgeFlag');
-  @glEdgeFlagPointer := GetProcAddress(hDLL, 'glEdgeFlagPointer');
-  @glEdgeFlagv := GetProcAddress(hDLL, 'glEdgeFlagv');
-  @glEnable := GetProcAddress(hDLL, 'glEnable');
-  @glEnableClientState := GetProcAddress(hDLL, 'glEnableClientState');
-  @glEnd := GetProcAddress(hDLL, 'glEnd');
-  @glEndList := GetProcAddress(hDLL, 'glEndList');
-  @glEvalCoord1d := GetProcAddress(hDLL, 'glEvalCoord1d');
-  @glEvalCoord1dv := GetProcAddress(hDLL, 'glEvalCoord1dv');
-  @glEvalCoord1f := GetProcAddress(hDLL, 'glEvalCoord1f');
-  @glEvalCoord1fv := GetProcAddress(hDLL, 'glEvalCoord1fv');
-  @glEvalCoord2d := GetProcAddress(hDLL, 'glEvalCoord2d');
-  @glEvalCoord2dv := GetProcAddress(hDLL, 'glEvalCoord2dv');
-  @glEvalCoord2f := GetProcAddress(hDLL, 'glEvalCoord2f');
-  @glEvalCoord2fv := GetProcAddress(hDLL, 'glEvalCoord2fv');
-  @glEvalMesh1 := GetProcAddress(hDLL, 'glEvalMesh1');
-  @glEvalMesh2 := GetProcAddress(hDLL, 'glEvalMesh2');
-  @glEvalPoint1 := GetProcAddress(hDLL, 'glEvalPoint1');
-  @glEvalPoint2 := GetProcAddress(hDLL, 'glEvalPoint2');
-  @glFeedbackBuffer := GetProcAddress(hDLL, 'glFeedbackBuffer');
-  @glFinish := GetProcAddress(hDLL, 'glFinish');
-  @glFlush := GetProcAddress(hDLL, 'glFlush');
-  @glFogf := GetProcAddress(hDLL, 'glFogf');
-  @glFogfv := GetProcAddress(hDLL, 'glFogfv');
-  @glFogi := GetProcAddress(hDLL, 'glFogi');
-  @glFogiv := GetProcAddress(hDLL, 'glFogiv');
-  @glFrontFace := GetProcAddress(hDLL, 'glFrontFace');
-  @glFrustum := GetProcAddress(hDLL, 'glFrustum');
-  @glGenLists := GetProcAddress(hDLL, 'glGenLists');
-  @glGenTextures := GetProcAddress(hDLL, 'glGenTextures');
-  @glGetBooleanv := GetProcAddress(hDLL, 'glGetBooleanv');
-  @glGetClipPlane := GetProcAddress(hDLL, 'glGetClipPlane');
-  @glGetDoublev := GetProcAddress(hDLL, 'glGetDoublev');
-  @glGetError := GetProcAddress(hDLL, 'glGetError');
-  @glGetFloatv := GetProcAddress(hDLL, 'glGetFloatv');
-  @glGetIntegerv := GetProcAddress(hDLL, 'glGetIntegerv');
-  @glGetLightfv := GetProcAddress(hDLL, 'glGetLightfv');
-  @glGetLightiv := GetProcAddress(hDLL, 'glGetLightiv');
-  @glGetMapdv := GetProcAddress(hDLL, 'glGetMapdv');
-  @glGetMapfv := GetProcAddress(hDLL, 'glGetMapfv');
-  @glGetMapiv := GetProcAddress(hDLL, 'glGetMapiv');
-  @glGetMaterialfv := GetProcAddress(hDLL, 'glGetMaterialfv');
-  @glGetMaterialiv := GetProcAddress(hDLL, 'glGetMaterialiv');
-  @glGetPixelMapfv := GetProcAddress(hDLL, 'glGetPixelMapfv');
-  @glGetPixelMapuiv := GetProcAddress(hDLL, 'glGetPixelMapuiv');
-  @glGetPixelMapusv := GetProcAddress(hDLL, 'glGetPixelMapusv');
-  @glGetPointerv := GetProcAddress(hDLL, 'glGetPointerv');
-  @glGetPolygonStipple := GetProcAddress(hDLL, 'glGetPolygonStipple');
-  @glGetString := GetProcAddress(hDLL, 'glGetString');
-  @glGetTexEnvfv := GetProcAddress(hDLL, 'glGetTexEnvfv');
-  @glGetTexEnviv := GetProcAddress(hDLL, 'glGetTexEnviv');
-  @glGetTexGendv := GetProcAddress(hDLL, 'glGetTexGendv');
-  @glGetTexGenfv := GetProcAddress(hDLL, 'glGetTexGenfv');
-  @glGetTexGeniv := GetProcAddress(hDLL, 'glGetTexGeniv');
-  @glGetTexImage := GetProcAddress(hDLL, 'glGetTexImage');
-  @glGetTexLevelParameterfv := GetProcAddress(hDLL, 'glGetTexLevelParameterfv');
-  @glGetTexLevelParameteriv := GetProcAddress(hDLL, 'glGetTexLevelParameteriv');
-  @glGetTexParameterfv := GetProcAddress(hDLL, 'glGetTexParameterfv');
-  @glGetTexParameteriv := GetProcAddress(hDLL, 'glGetTexParameteriv');
-  @glHint := GetProcAddress(hDLL, 'glHint');
-  @glIndexMask := GetProcAddress(hDLL, 'glIndexMask');
-  @glIndexPointer := GetProcAddress(hDLL, 'glIndexPointer');
-  @glIndexd := GetProcAddress(hDLL, 'glIndexd');
-  @glIndexdv := GetProcAddress(hDLL, 'glIndexdv');
-  @glIndexf := GetProcAddress(hDLL, 'glIndexf');
-  @glIndexfv := GetProcAddress(hDLL, 'glIndexfv');
-  @glIndexi := GetProcAddress(hDLL, 'glIndexi');
-  @glIndexiv := GetProcAddress(hDLL, 'glIndexiv');
-  @glIndexs := GetProcAddress(hDLL, 'glIndexs');
-  @glIndexsv := GetProcAddress(hDLL, 'glIndexsv');
-  @glIndexub := GetProcAddress(hDLL, 'glIndexub');
-  @glIndexubv := GetProcAddress(hDLL, 'glIndexubv');
-  @glInitNames := GetProcAddress(hDLL, 'glInitNames');
-  @glInterleavedArrays := GetProcAddress(hDLL, 'glInterleavedArrays');
-  @glIsEnabled := GetProcAddress(hDLL, 'glIsEnabled');
-  @glIsList := GetProcAddress(hDLL, 'glIsList');
-  @glIsTexture := GetProcAddress(hDLL, 'glIsTexture');
-  @glLightModelf := GetProcAddress(hDLL, 'glLightModelf');
-  @glLightModelfv := GetProcAddress(hDLL, 'glLightModelfv');
-  @glLightModeli := GetProcAddress(hDLL, 'glLightModeli');
-  @glLightModeliv := GetProcAddress(hDLL, 'glLightModeliv');
-  @glLightf := GetProcAddress(hDLL, 'glLightf');
-  @glLightfv := GetProcAddress(hDLL, 'glLightfv');
-  @glLighti := GetProcAddress(hDLL, 'glLighti');
-  @glLightiv := GetProcAddress(hDLL, 'glLightiv');
-  @glLineStipple := GetProcAddress(hDLL, 'glLineStipple');
-  @glLineWidth := GetProcAddress(hDLL, 'glLineWidth');
-  @glListBase := GetProcAddress(hDLL, 'glListBase');
-  @glLoadIdentity := GetProcAddress(hDLL, 'glLoadIdentity');
-  @glLoadMatrixd := GetProcAddress(hDLL, 'glLoadMatrixd');
-  @glLoadMatrixf := GetProcAddress(hDLL, 'glLoadMatrixf');
-  @glLoadName := GetProcAddress(hDLL, 'glLoadName');
-  @glLogicOp := GetProcAddress(hDLL, 'glLogicOp');
-  @glMap1d := GetProcAddress(hDLL, 'glMap1d');
-  @glMap1f := GetProcAddress(hDLL, 'glMap1f');
-  @glMap2d := GetProcAddress(hDLL, 'glMap2d');
-  @glMap2f := GetProcAddress(hDLL, 'glMap2f');
-  @glMapGrid1d := GetProcAddress(hDLL, 'glMapGrid1d');
-  @glMapGrid1f := GetProcAddress(hDLL, 'glMapGrid1f');
-  @glMapGrid2d := GetProcAddress(hDLL, 'glMapGrid2d');
-  @glMapGrid2f := GetProcAddress(hDLL, 'glMapGrid2f');
-  @glMaterialf := GetProcAddress(hDLL, 'glMaterialf');
-  @glMaterialfv := GetProcAddress(hDLL, 'glMaterialfv');
-  @glMateriali := GetProcAddress(hDLL, 'glMateriali');
-  @glMaterialiv := GetProcAddress(hDLL, 'glMaterialiv');
-  @glMatrixMode := GetProcAddress(hDLL, 'glMatrixMode');
-  @glMultMatrixd := GetProcAddress(hDLL, 'glMultMatrixd');
-  @glMultMatrixf := GetProcAddress(hDLL, 'glMultMatrixf');
-  @glNewList := GetProcAddress(hDLL, 'glNewList');
-  @glNormal3b := GetProcAddress(hDLL, 'glNormal3b');
-  @glNormal3bv := GetProcAddress(hDLL, 'glNormal3bv');
-  @glNormal3d := GetProcAddress(hDLL, 'glNormal3d');
-  @glNormal3dv := GetProcAddress(hDLL, 'glNormal3dv');
-  @glNormal3f := GetProcAddress(hDLL, 'glNormal3f');
-  @glNormal3fv := GetProcAddress(hDLL, 'glNormal3fv');
-  @glNormal3i := GetProcAddress(hDLL, 'glNormal3i');
-  @glNormal3iv := GetProcAddress(hDLL, 'glNormal3iv');
-  @glNormal3s := GetProcAddress(hDLL, 'glNormal3s');
-  @glNormal3sv := GetProcAddress(hDLL, 'glNormal3sv');
-  @glNormalPointer := GetProcAddress(hDLL, 'glNormalPointer');
-  @glOrtho := GetProcAddress(hDLL, 'glOrtho');
-  @glPassThrough := GetProcAddress(hDLL, 'glPassThrough');
-  @glPixelMapfv := GetProcAddress(hDLL, 'glPixelMapfv');
-  @glPixelMapuiv := GetProcAddress(hDLL, 'glPixelMapuiv');
-  @glPixelMapusv := GetProcAddress(hDLL, 'glPixelMapusv');
-  @glPixelStoref := GetProcAddress(hDLL, 'glPixelStoref');
-  @glPixelStorei := GetProcAddress(hDLL, 'glPixelStorei');
-  @glPixelTransferf := GetProcAddress(hDLL, 'glPixelTransferf');
-  @glPixelTransferi := GetProcAddress(hDLL, 'glPixelTransferi');
-  @glPixelZoom := GetProcAddress(hDLL, 'glPixelZoom');
-  @glPointSize := GetProcAddress(hDLL, 'glPointSize');
-  @glPolygonMode := GetProcAddress(hDLL, 'glPolygonMode');
-  @glPolygonOffset := GetProcAddress(hDLL, 'glPolygonOffset');
-  @glPolygonStipple := GetProcAddress(hDLL, 'glPolygonStipple');
-  @glPopAttrib := GetProcAddress(hDLL, 'glPopAttrib');
-  @glPopClientAttrib := GetProcAddress(hDLL, 'glPopClientAttrib');
-  @glPopMatrix := GetProcAddress(hDLL, 'glPopMatrix');
-  @glPopName := GetProcAddress(hDLL, 'glPopName');
-  @glPrioritizeTextures := GetProcAddress(hDLL, 'glPrioritizeTextures');
-  @glPushAttrib := GetProcAddress(hDLL, 'glPushAttrib');
-  @glPushClientAttrib := GetProcAddress(hDLL, 'glPushClientAttrib');
-  @glPushMatrix := GetProcAddress(hDLL, 'glPushMatrix');
-  @glPushName := GetProcAddress(hDLL, 'glPushName');
-  @glRasterPos2d := GetProcAddress(hDLL, 'glRasterPos2d');
-  @glRasterPos2dv := GetProcAddress(hDLL, 'glRasterPos2dv');
-  @glRasterPos2f := GetProcAddress(hDLL, 'glRasterPos2f');
-  @glRasterPos2fv := GetProcAddress(hDLL, 'glRasterPos2fv');
-  @glRasterPos2i := GetProcAddress(hDLL, 'glRasterPos2i');
-  @glRasterPos2iv := GetProcAddress(hDLL, 'glRasterPos2iv');
-  @glRasterPos2s := GetProcAddress(hDLL, 'glRasterPos2s');
-  @glRasterPos2sv := GetProcAddress(hDLL, 'glRasterPos2sv');
-  @glRasterPos3d := GetProcAddress(hDLL, 'glRasterPos3d');
-  @glRasterPos3dv := GetProcAddress(hDLL, 'glRasterPos3dv');
-  @glRasterPos3f := GetProcAddress(hDLL, 'glRasterPos3f');
-  @glRasterPos3fv := GetProcAddress(hDLL, 'glRasterPos3fv');
-  @glRasterPos3i := GetProcAddress(hDLL, 'glRasterPos3i');
-  @glRasterPos3iv := GetProcAddress(hDLL, 'glRasterPos3iv');
-  @glRasterPos3s := GetProcAddress(hDLL, 'glRasterPos3s');
-  @glRasterPos3sv := GetProcAddress(hDLL, 'glRasterPos3sv');
-  @glRasterPos4d := GetProcAddress(hDLL, 'glRasterPos4d');
-  @glRasterPos4dv := GetProcAddress(hDLL, 'glRasterPos4dv');
-  @glRasterPos4f := GetProcAddress(hDLL, 'glRasterPos4f');
-  @glRasterPos4fv := GetProcAddress(hDLL, 'glRasterPos4fv');
-  @glRasterPos4i := GetProcAddress(hDLL, 'glRasterPos4i');
-  @glRasterPos4iv := GetProcAddress(hDLL, 'glRasterPos4iv');
-  @glRasterPos4s := GetProcAddress(hDLL, 'glRasterPos4s');
-  @glRasterPos4sv := GetProcAddress(hDLL, 'glRasterPos4sv');
-  @glReadBuffer := GetProcAddress(hDLL, 'glReadBuffer');
-  @glReadPixels := GetProcAddress(hDLL, 'glReadPixels');
-  @glRectd := GetProcAddress(hDLL, 'glRectd');
-  @glRectdv := GetProcAddress(hDLL, 'glRectdv');
-  @glRectf := GetProcAddress(hDLL, 'glRectf');
-  @glRectfv := GetProcAddress(hDLL, 'glRectfv');
-  @glRecti := GetProcAddress(hDLL, 'glRecti');
-  @glRectiv := GetProcAddress(hDLL, 'glRectiv');
-  @glRects := GetProcAddress(hDLL, 'glRects');
-  @glRectsv := GetProcAddress(hDLL, 'glRectsv');
-  @glRenderMode := GetProcAddress(hDLL, 'glRenderMode');
-  @glRotated := GetProcAddress(hDLL, 'glRotated');
-  @glRotatef := GetProcAddress(hDLL, 'glRotatef');
-  @glScaled := GetProcAddress(hDLL, 'glScaled');
-  @glScalef := GetProcAddress(hDLL, 'glScalef');
-  @glScissor := GetProcAddress(hDLL, 'glScissor');
-  @glSelectBuffer := GetProcAddress(hDLL, 'glSelectBuffer');
-  @glShadeModel := GetProcAddress(hDLL, 'glShadeModel');
-  @glStencilFunc := GetProcAddress(hDLL, 'glStencilFunc');
-  @glStencilMask := GetProcAddress(hDLL, 'glStencilMask');
-  @glStencilOp := GetProcAddress(hDLL, 'glStencilOp');
-  @glTexCoord1d := GetProcAddress(hDLL, 'glTexCoord1d');
-  @glTexCoord1dv := GetProcAddress(hDLL, 'glTexCoord1dv');
-  @glTexCoord1f := GetProcAddress(hDLL, 'glTexCoord1f');
-  @glTexCoord1fv := GetProcAddress(hDLL, 'glTexCoord1fv');
-  @glTexCoord1i := GetProcAddress(hDLL, 'glTexCoord1i');
-  @glTexCoord1iv := GetProcAddress(hDLL, 'glTexCoord1iv');
-  @glTexCoord1s := GetProcAddress(hDLL, 'glTexCoord1s');
-  @glTexCoord1sv := GetProcAddress(hDLL, 'glTexCoord1sv');
-  @glTexCoord2d := GetProcAddress(hDLL, 'glTexCoord2d');
-  @glTexCoord2dv := GetProcAddress(hDLL, 'glTexCoord2dv');
-  @glTexCoord2f := GetProcAddress(hDLL, 'glTexCoord2f');
-  @glTexCoord2fv := GetProcAddress(hDLL, 'glTexCoord2fv');
-  @glTexCoord2i := GetProcAddress(hDLL, 'glTexCoord2i');
-  @glTexCoord2iv := GetProcAddress(hDLL, 'glTexCoord2iv');
-  @glTexCoord2s := GetProcAddress(hDLL, 'glTexCoord2s');
-  @glTexCoord2sv := GetProcAddress(hDLL, 'glTexCoord2sv');
-  @glTexCoord3d := GetProcAddress(hDLL, 'glTexCoord3d');
-  @glTexCoord3dv := GetProcAddress(hDLL, 'glTexCoord3dv');
-  @glTexCoord3f := GetProcAddress(hDLL, 'glTexCoord3f');
-  @glTexCoord3fv := GetProcAddress(hDLL, 'glTexCoord3fv');
-  @glTexCoord3i := GetProcAddress(hDLL, 'glTexCoord3i');
-  @glTexCoord3iv := GetProcAddress(hDLL, 'glTexCoord3iv');
-  @glTexCoord3s := GetProcAddress(hDLL, 'glTexCoord3s');
-  @glTexCoord3sv := GetProcAddress(hDLL, 'glTexCoord3sv');
-  @glTexCoord4d := GetProcAddress(hDLL, 'glTexCoord4d');
-  @glTexCoord4dv := GetProcAddress(hDLL, 'glTexCoord4dv');
-  @glTexCoord4f := GetProcAddress(hDLL, 'glTexCoord4f');
-  @glTexCoord4fv := GetProcAddress(hDLL, 'glTexCoord4fv');
-  @glTexCoord4i := GetProcAddress(hDLL, 'glTexCoord4i');
-  @glTexCoord4iv := GetProcAddress(hDLL, 'glTexCoord4iv');
-  @glTexCoord4s := GetProcAddress(hDLL, 'glTexCoord4s');
-  @glTexCoord4sv := GetProcAddress(hDLL, 'glTexCoord4sv');
-  @glTexCoordPointer := GetProcAddress(hDLL, 'glTexCoordPointer');
-  @glTexEnvf := GetProcAddress(hDLL, 'glTexEnvf');
-  @glTexEnvfv := GetProcAddress(hDLL, 'glTexEnvfv');
-  @glTexEnvi := GetProcAddress(hDLL, 'glTexEnvi');
-  @glTexEnviv := GetProcAddress(hDLL, 'glTexEnviv');
-  @glTexGend := GetProcAddress(hDLL, 'glTexGend');
-  @glTexGendv := GetProcAddress(hDLL, 'glTexGendv');
-  @glTexGenf := GetProcAddress(hDLL, 'glTexGenf');
-  @glTexGenfv := GetProcAddress(hDLL, 'glTexGenfv');
-  @glTexGeni := GetProcAddress(hDLL, 'glTexGeni');
-  @glTexGeniv := GetProcAddress(hDLL, 'glTexGeniv');
-  @glTexImage1D := GetProcAddress(hDLL, 'glTexImage1D');
-  @glTexImage2D := GetProcAddress(hDLL, 'glTexImage2D');
-  @glTexParameterf := GetProcAddress(hDLL, 'glTexParameterf');
-  @glTexParameterfv := GetProcAddress(hDLL, 'glTexParameterfv');
-  @glTexParameteri := GetProcAddress(hDLL, 'glTexParameteri');
-  @glTexParameteriv := GetProcAddress(hDLL, 'glTexParameteriv');
-  @glTexSubImage1D := GetProcAddress(hDLL, 'glTexSubImage1D');
-  @glTexSubImage2D := GetProcAddress(hDLL, 'glTexSubImage2D');
-  @glTranslated := GetProcAddress(hDLL, 'glTranslated');
-  @glTranslatef := GetProcAddress(hDLL, 'glTranslatef');
-  @glVertex2d := GetProcAddress(hDLL, 'glVertex2d');
-  @glVertex2dv := GetProcAddress(hDLL, 'glVertex2dv');
-  @glVertex2f := GetProcAddress(hDLL, 'glVertex2f');
-  @glVertex2fv := GetProcAddress(hDLL, 'glVertex2fv');
-  @glVertex2i := GetProcAddress(hDLL, 'glVertex2i');
-  @glVertex2iv := GetProcAddress(hDLL, 'glVertex2iv');
-  @glVertex2s := GetProcAddress(hDLL, 'glVertex2s');
-  @glVertex2sv := GetProcAddress(hDLL, 'glVertex2sv');
-  @glVertex3d := GetProcAddress(hDLL, 'glVertex3d');
-  @glVertex3dv := GetProcAddress(hDLL, 'glVertex3dv');
-  @glVertex3f := GetProcAddress(hDLL, 'glVertex3f');
-  @glVertex3fv := GetProcAddress(hDLL, 'glVertex3fv');
-  @glVertex3i := GetProcAddress(hDLL, 'glVertex3i');
-  @glVertex3iv := GetProcAddress(hDLL, 'glVertex3iv');
-  @glVertex3s := GetProcAddress(hDLL, 'glVertex3s');
-  @glVertex3sv := GetProcAddress(hDLL, 'glVertex3sv');
-  @glVertex4d := GetProcAddress(hDLL, 'glVertex4d');
-  @glVertex4dv := GetProcAddress(hDLL, 'glVertex4dv');
-  @glVertex4f := GetProcAddress(hDLL, 'glVertex4f');
-  @glVertex4fv := GetProcAddress(hDLL, 'glVertex4fv');
-  @glVertex4i := GetProcAddress(hDLL, 'glVertex4i');
-  @glVertex4iv := GetProcAddress(hDLL, 'glVertex4iv');
-  @glVertex4s := GetProcAddress(hDLL, 'glVertex4s');
-  @glVertex4sv := GetProcAddress(hDLL, 'glVertex4sv');
-  @glVertexPointer := GetProcAddress(hDLL, 'glVertexPointer');
-  @glViewport := GetProcAddress(hDLL, 'glViewport');
-
-  @ChoosePixelFormat := GetProcAddress(hDLL, 'ChoosePixelFormat');
-  if not Assigned(ChoosePixelFormat) then
-    @ChoosePixelFormat := @Windows.ChoosePixelFormat;
-
-end;
-
-initialization
-
-  Set8087CW($133F);
-
-  try
-    LoadOpenGL('opengl32.dll');
-  except end;
-
-finalization
-
-  FreeOpenGL;
-
-end.
diff --git a/src/lib/dgl/dglOpenGL.pas b/src/lib/dgl/dglOpenGL.pas
deleted file mode 100644 (file)
index 80c8231..0000000
+++ /dev/null
@@ -1,15296 +0,0 @@
-{==============================================================================}
-{                                                                              }
-{       OpenGL 3.2 - Headertranslation                                         }
-{       Version 3.2.1                                                          }
-{       Date : 15.09.2009                                                      }
-{                                                                              }
-{       Works with :                                                           }
-{        - Delphi 3 and up                                                     }
-{        - FreePascal (1.9.3 and up)                                           }
-{                                                                              }
-{==============================================================================}
-{                                                                              }
-{       Containts the translations of glext.h, gl_1_1.h, glu.h and weglext.h.  }
-{       It also contains some helperfunctions that were inspired by those      }
-{       found in Mike Lischke's OpenGL12.pas.                                  }
-{                                                                              }
-{       Copyright (C) DGL-OpenGL2-Portteam                                     }
-{       All Rights Reserved                                                    }
-{                                                                              }
-{       Obtained through:                                                      }
-{       Delphi OpenGL Community(DGL) - www.delphigl.com                        }
-{                                                                              }
-{       Converted and maintained by DGL's GL2.0-Team :                         }
-{         - Sascha Willems                - http://www.delphigl.de             }
-{         - Steffen Xonna (Lossy eX)      - http://www.dev-center.de           }
-{         - Lars Middendorf               - http://www.3d-seite.de             }
-{       Additional input :                                                     }
-{         - Martin Waldegger (Mars)       - http://www.basegraph.com           }
-{         - Benjamin Rosseaux (BeRo)      - http://www.0ok.de                  }
-{       Additional thanks:                                                     }
-{           sigsegv (libdl.so)                                                 }
-{                                                                              }
-{                                                                              }
-{==============================================================================}
-{ You may retrieve the latest version of this file at the Delphi OpenGL        }
-{ Community home page, located at http://www.delphigl.com/                     }
-{                                                                              }
-{ The contents of this file are used with permission, subject to               }
-{ the Mozilla Public License Version 1.1 (the "License"); you may              }
-{ not use this file except in compliance with the License. You may             }
-{ obtain a copy of the License at                                              }
-{ http://www.mozilla.org/MPL/MPL-1.1.html                                      }
-{                                                                              }
-{ Software distributed under the License is distributed on an                  }
-{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or               }
-{ implied. See the License for the specific language governing                 }
-{ rights and limitations under the License.                                    }
-{                                                                              }
-{==============================================================================}
-{ History :                                                                    }
-{ Version 1.0    Initial Release                                               }
-{ Version 1.1    Added PPointer in Tpyessection for compatiblity with Delphi   }
-{                versions lower than 7                                    (SW) }
-{                Added a function named RaiseLastOSError including a comment   }
-{                on how to make it run under Delphi versions lower than 7 (SW) }
-{                Added some data types according to the GL-Syntax         (SW) }
-{ Version 1.2    Fixed some problems with getting the addresses of some        }
-{                Extensions (e.g. glTexImage3D) where the EXT/ARB did work     }
-{                but not the core-functions                               (SW) }
-{ Version 1.3    A second call to ReadimplementationProperties won't           }
-{                revert to the default libs anymore                       (MW) }
-{                Libraries now will be released if necessary              (MW) }
-{ Version 1.3a   Small fixes for glSlang-functions                        (SW) }
-{ Version 1.3b   Fixed a small bug with GL_ARB_shader_objects, that lead       }
-{                lead to that extension not loaded correctly              (SW) }
-{ Version 1.3c   more GL 1.5 compliance by FOG_COORD_xx and                    }
-{                ARB less VBO and occlusion query routines                (MW) }
-{ Version 1.3d   Fixed linebreaks (should now be corrected under D5)      (SW) }
-{ Version 1.4    Changed header to correspond to the OpenGL-Shading            }
-{                Language specification 1.10 :                                 }
-{                - Added new GL_SAMPLER_*-Constants                            }
-{                - Added Constant GL_SHADING_LANGUAGE_VERSION_ARB              }
-{                - Added Constant GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB       }
-{                - Added Constant GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB  (SW) }
-{ Version 1.4a   Fixed a missing stdcall for glBindAttribLocationARB      (SW) }
-{ Version 1.4b   Fixed declaration for glUniform*(f/i)vARB (added count)  (MW) }
-{                glCompileShaderARB changed from function to procedure    (MW) }
-{ Version 1.5    Added support for FreePascal                             (BR) }
-{                Added type TGLVectorf3/TGLVector3f                       (SW) }
-{ Version 1.6    Added Extension GL_EXT_framebuffer_object                (SX) }
-{ Version 1.7    Added Extension GL_ARB_fragment_program_shadow           (SX) }
-{                Added Extension GL_ARB_draw_buffers                      (SX) }
-{                Added Extension GL_ARB_texture_rectangle                 (SX) }
-{                Added Extension GL_ARB_color_buffer_float                (SX) }
-{                Added Extension GL_ARB_half_float_pixel                  (SX) }
-{                Added Extension GL_ARB_texture_float                     (SX) }
-{                Added Extension GL_ARB_pixel_buffer_object               (SX) }
-{                Added Extension GL_EXT_depth_bounds_test                 (SX) }
-{                Added Extension GL_EXT_texture_mirror_clamp              (SX) }
-{                Added Extension GL_EXT_blend_equation_separate           (SX) }
-{                Added Extension GL_EXT_pixel_buffer_object               (SX) }
-{                Added Extension GL_EXT_texture_compression_dxt1          (SX) }
-{                Added Extension GL_NV_fragment_program_option            (SX) }
-{                Added Extension GL_NV_fragment_program2                  (SX) }
-{                Added Extension GL_NV_vertex_program2_option             (SX) }
-{                Added Extension GL_NV_vertex_program3                    (SX) }
-{ Version 1.8    Added explicit delegate type definitions                 (LM) }
-{                Added .Net 1.1 Support                                   (LM) }
-{                Added .Net overloaded functions                          (LM) }
-{                Added delayed extension loading and stubs                (LM) }
-{                Added automatic InitOpenGL call in CreateRenderingContext(LM) }
-{                Added extra Read_* function                              (LM) }
-{ Version 2.0    fixed some Problem with version string and damn drivers.      }
-{                String 1.15 identified as OpenGL 1.5 not as OpenGL 1.1   (SX) }
-{                Removed unexisting extension GL_ARB_texture_mirror_repeat(SX) }
-{                Added Extension WGL_ARB_pixel_format_float               (SX) }
-{                Added Extension GL_EXT_stencil_clear_tag                 (SX) }
-{                Added Extension GL_EXT_texture_rectangle                 (SX) }
-{                Added Extension GL_EXT_texture_edge_clamp                (SX) }
-{                Some 1.5 Core Consts added (now completed)               (SX) }
-{                gluProject need pointer for not .net                     (SX) }
-{                gluUnProject need pointer for not .net                   (SX) }
-{                wglUseFontOutlines* need pointer for not .net            (SX) }
-{                wglSwapMultipleBuffers need pointer for not .net         (SX) }
-{                Bug with wglGetExtensionsStringEXT removed                    }
-{                different type for .net                                  (SX) }
-{                Added OpenGL 2.0 Core                                    (SX) }
-{ Version 2.0.1  fixed some problems with glGetActiveAttrib in 2.0 Core   (SX) }
-{                fixes some problems with gluProject                      (SX) }
-{                fixes some problems with gluUnProject                    (SX) }
-{                fixes some problems with gluTessVertex                   (SX) }
-{                fixes some problems with gluLoadSamplingMatrices         (SX) }
-{ Version 2.1    Removed .NET Support                                     (SX) }
-{                Better support for Linux                                 (SX) }
-{                Better Codeformation                                     (SX) }
-{                Added some more Vector/Matrix types                      (SX) }
-{                Added OpenGL 2.1 Core                                    (SX) }
-{                Added Extension GL_EXT_packed_depth_stencil              (SX) }
-{                Added Extension GL_EXT_texture_sRGB                      (SX) }
-{                Added Extension GL_EXT_framebuffer_blit                  (SX) }
-{                Added Extension GL_EXT_framebuffer_multisample           (SX) }
-{                Added Extension GL_EXT_timer_query                       (SX) }
-{                Added Extension GL_EXT_gpu_program_parameters            (SX) }
-{                Added Extension GL_EXT_bindable_uniform                  (SX) }
-{                Added Extension GL_EXT_draw_buffers2                     (SX) }
-{                Added Extension GL_EXT_draw_instanced                    (SX) }
-{                Added Extension GL_EXT_framebuffer_sRGB                  (SX) }
-{                Added Extension GL_EXT_geometry_shader4                  (SX) }
-{                Added Extension GL_EXT_gpu_shader4                       (SX) }
-{                Added Extension GL_EXT_packed_float                      (SX) }
-{                Added Extension GL_EXT_texture_array                     (SX) }
-{                Added Extension GL_EXT_texture_buffer_object             (SX) }
-{                Added Extension GL_EXT_texture_compression_latc          (SX) }
-{                Added Extension GL_EXT_texture_compression_rgtc          (SX) }
-{                Added Extension GL_EXT_texture_integer                   (SX) }
-{                Added Extension GL_EXT_texture_shared_exponent           (SX) }
-{                Added Extension GL_NV_depth_buffer_float                 (SX) }
-{                Added Extension GL_NV_fragment_program4                  (SX) }
-{                Added Extension GL_NV_framebuffer_multisample_coverage   (SX) }
-{                Added Extension GL_NV_geometry_program4                  (SX) }
-{                Added Extension GL_NV_gpu_program4                       (SX) }
-{                Added Extension GL_NV_parameter_buffer_object            (SX) }
-{                Added Extension GL_NV_transform_feedback                 (SX) }
-{                Added Extension GL_NV_vertex_program4                    (SX) }
-{ Version 3.0    fixed some const of GL_EXT_texture_shared_exponent       (SX) }
-{                possible better support for mac                          (SX) }
-{                Added OpenGL 3.0 Core                                    (SX) }
-{                Added Extension GL_ARB_depth_buffer_float                (SX) }
-{                Added Extension GL_ARB_draw_instanced                    (SX) }
-{                Added Extension GL_ARB_framebuffer_object                (SX) }
-{                Added Extension GL_ARB_framebuffer_sRGB                  (SX) }
-{                Added Extension GL_ARB_geometry_shader4                  (SX) }
-{                Added Extension GL_ARB_half_float_vertex                 (SX) }
-{                Added Extension GL_ARB_instanced_arrays                  (SX) }
-{                Added Extension GL_ARB_map_buffer_range                  (SX) }
-{                Added Extension GL_ARB_texture_buffer_object             (SX) }
-{                Added Extension GL_ARB_texture_compression_rgtc          (SX) }
-{                Added Extension GL_ARB_texture_rg                        (SX) }
-{                Added Extension GL_ARB_vertex_array_object               (SX) }
-{                Added Extension GL_NV_conditional_render                 (SX) }
-{                Added Extension GL_NV_present_video                      (SX) }
-{                Added Extension GL_EXT_transform_feedback                (SX) }
-{                Added Extension GL_EXT_direct_state_access               (SX) }
-{                Added Extension GL_EXT_vertex_array_bgra                 (SX) }
-{                Added Extension GL_EXT_texture_swizzle                   (SX) }
-{                Added Extension GL_NV_explicit_multisample               (SX) }
-{                Added Extension GL_NV_transform_feedback2                (SX) }
-{                Added Extension WGL_ARB_create_context                   (SX) }
-{                Added Extension WGL_NV_present_video                     (SX) }
-{                Added Extension WGL_NV_video_out                         (SX) }
-{                Added Extension WGL_NV_swap_group                        (SX) }
-{                Added Extension WGL_NV_gpu_affinity                      (SX) }
-{                Added define DGL_TINY_HEADER to suppress automatic            }
-{                function loading                                         (SX) }
-{                glProcedure renamed to dglGetProcAddress and now it's         }
-{                visible from outside the unit to custom load functions   (SX) }
-{                dglCheckExtension added to check if an extension exists  (SX) }
-{                Read_GL_ARB_buffer_object renamed to                          }
-{                Read_GL_ARB_vertex_buffer_object                         (SX) }
-{ Version 3.0.1  fixed an problem with fpc                                (SX) }
-{ Version 3.0.2  fixed an problem with WGL_ARB_create_context             (SX) }
-{ Version 3.2    Functions from GL_VERSION_3_0 where updated              (SX) }
-{                Functions from GL_ARB_map_buffer_range where updated     (SX) }
-{                Functions from GL_NV_present_video where added           (SX) }
-{                Added consts of GL_ARB_instanced_arrays                  (SX) }
-{                Defines to identify Delphi was changed (prevent for           }
-{                feature maintenance)                                     (SX) }
-{                Added Extension GL_ATI_meminfo                           (SX) }
-{                Added Extension GL_AMD_performance_monitor               (SX) }
-{                Added Extension GL_AMD_texture_texture4                  (SX) }
-{                Added Extension GL_AMD_vertex_shader_tesselator          (SX) }
-{                Added Extension GL_EXT_provoking_vertex                  (SX) }
-{                Added Extension WGL_AMD_gpu_association                  (SX) }
-{                Added OpenGL 3.1 Core                                    (SX) }
-{                All deprecated stuff can be disabled if you undef the         }
-{                define DGL_DEPRECATED                                    (SX) }
-{                Added Extension GL_ARB_uniform_buffer_object             (SX) }
-{                Added Extension GL_ARB_compatibility                     (SX) }
-{                Added Extension GL_ARB_copy_buffer                       (SX) }
-{                Added Extension GL_ARB_shader_texture_lod                (SX) }
-{                Remove function from GL_NV_present_video                 (SX) }
-{                Added Extension WGL_3DL_stereo_control                   (SX) }
-{                Added Extension GL_EXT_texture_snorm                     (SX) }
-{                Added Extension GL_AMD_draw_buffers_blend                (SX) }
-{                Added Extension GL_APPLE_texture_range                   (SX) }
-{                Added Extension GL_APPLE_float_pixels                    (SX) }
-{                Added Extension GL_APPLE_vertex_program_evaluators       (SX) }
-{                Added Extension GL_APPLE_aux_depth_stencil               (SX) }
-{                Added Extension GL_APPLE_object_purgeable                (SX) }
-{                Added Extension GL_APPLE_row_bytes                       (SX) }
-{                Added OpenGL 3.2 Core                                    (SX) }
-{                Added Extension GL_ARB_depth_clamp                       (SX) }
-{                Added Extension GL_ARB_draw_elements_base_vertex         (SX) }
-{                Added Extension GL_ARB_fragment_coord_conventions        (SX) }
-{                Added Extension GL_ARB_provoking_vertex                  (SX) }
-{                Added Extension GL_ARB_seamless_cube_map                 (SX) }
-{                Added Extension GL_ARB_sync                              (SX) }
-{                Added Extension GL_ARB_texture_multisample               (SX) }
-{                Added Extension GL_ARB_vertex_array_bgra                 (SX) }
-{                Added Extension GL_ARB_draw_buffers_blend                (SX) }
-{                Added Extension GL_ARB_sample_shading                    (SX) }
-{                Added Extension GL_ARB_texture_cube_map_array            (SX) }
-{                Added Extension GL_ARB_texture_gather                    (SX) }
-{                Added Extension GL_ARB_texture_query_lod                 (SX) }
-{                Added Extension WGL_ARB_create_context_profile           (SX) }
-{                Added GLX Core up to Version 1.4                         (SX) }
-{                Added Extension GLX_ARB_multisample                      (SX) }
-{                Added Extension GLX_ARB_fbconfig_float                   (SX) }
-{                Added Extension GLX_ARB_get_proc_address                 (SX) }
-{                Added Extension GLX_ARB_create_context                   (SX) }
-{                Added Extension GLX_ARB_create_context_profile           (SX) }
-{                Added Extension GLX_EXT_visual_info                      (SX) }
-{                Added Extension GLX_EXT_visual_rating                    (SX) }
-{                Added Extension GLX_EXT_import_context                   (SX) }
-{                Added Extension GLX_EXT_fbconfig_packed_float            (SX) }
-{                Added Extension GLX_EXT_framebuffer_sRGB                 (SX) }
-{                Added Extension GLX_EXT_texture_from_pixmap              (SX) }
-{ Version 3.2.1  Fixed some problems with Delphi < 6                      (SX) }
-
-
-{==============================================================================}
-{ Header based on glext.h rev 54 (2009-08-03)                                  }
-{ This is an important notice for maintaining. Dont remove it. And make sure   }
-{ to keep him up to date                                                       }
-{==============================================================================}
-
-
-{$define DGL_DEPRECATED}
-{
-  This define defines if the header should use deprecated ARB stuff or not.
-  per Default the Header use deprecated Stuff.
-}
-
-
-{.$define DGL_TINY_HEADER}
-{
-  If you enable the define DGL_TINY_HEADER no function automatically will be loaded if you
-  call ActivateRenderingContext. This may some bit faster and the smart linker can delete
-  all non used functions. This will reduce the filesize of your binary file. But in this
-  case you have to load the functions by yourself. There are two ways to do this.
-  
-  1. You can load whole extension by calling the func Read_Extensionname. But if you do
-     this it's possible to load functions you dont use. So you have the same "problem"
-     like before. But it's only an bit smaler.
-     > Read_GL_ARB_multitexture;
-
-  2. You are able to load only the functions you exactly need. In this case you are able
-     to use the variables of the dglOpenGL.pas. So you only need to load the functions
-     and you can use the header like before.
-     To do this you have to created and activated an opengl context and than you can load
-     the needed functions.
-     > ActivateRenderingContext(fDC, fRC);
-     > glActiveTextureARB := dglGetProcAddress('glActiveTextureARB');
-     > glMultiTexCoord2fARB := dglGetProcAddress('glMultiTexCoord2fARB');
-
-     So only the function "glActiveTextureARB" and "glMultiTexCoord2fARB" will be loaded.
-
-
-  Please notice that the extension variables won't be loaded if this define is active. But
-  you can call dglCheckExtension to check if any extension exists. You can assign them to
-  the variables of the dglOpenGL.pas so all code they use this will find them.
-
-  > GL_ARB_shading_language_100 := dglCheckExtension('GL_ARB_shading_language_100');
-}
-
-
-unit dglOpenGL;
-
-interface
-
-// defines to configure freepascal
-{$IFDEF FPC}
-  {$MODE Delphi}
-
-  {$IFNDEF WINDOWS}
-    {$LINKLIB c}
-  {$ENDIF}
-{$ENDIF}
-
-// known delphi versions
-{$IFNDEF FPC}       // if freepascal isnt defined
-  {$IFDEF VER140}   // Delphi 6
-    {$DEFINE DELPHI6_AND_DOWN}
-  {$ENDIF}
-
-  {$IFDEF VER130}   // Delphi 5
-    {$DEFINE DELPHI6_AND_DOWN}
-  {$ENDIF}
-
-  {$IFDEF VER120}   // Delphi 4
-    {$DEFINE DELPHI6_AND_DOWN}
-  {$ENDIF}
-
-  {$IFDEF VER110}   // C++ Builder 3
-    {$DEFINE DELPHI6_AND_DOWN}
-  {$ENDIF}
-
-  {$IFDEF VER100}   // Delphi 3
-    {$DEFINE DELPHI6_AND_DOWN}
-  {$ENDIF}
-{$ENDIF}
-
-// Options for Delphi < 5
-{$IFDEF DELPHI6_AND_DOWN}
-  {$A+}
-{$ELSE}
-  {$A4}
-{$ENDIF}
-
-// generell options
-{$H+,O+,X+}
-
-// detecting Windows
-{$IFDEF Win32}          // Delphi and fpc of 32 Bit Windows
-  {$DEFINE DGL_WIN}
-{$ENDIF}
-
-{$IFDEF Win64}          // Delphi and fpc of 32 Bit Windows
-  {$DEFINE DGL_WIN}
-{$ENDIF}
-
-// detecting Linux
-{$IFDEF linux}          // Linux
-  {$DEFINE DGL_LINUX}
-{$ENDIF}
-
-// detecting 64 Bit CPU
-{$IFDEF CPU64}          // fpc on 64 bit cpus
-  {$DEFINE DGL_64BIT}   // dgl define for 64 bit
-{$ENDIF}
-
-
-
-uses
-  SysUtils
-  {$IFDEF DGL_WIN}, Windows{$ENDIF}
-  {$IFDEF DGL_LINUX}, X, XLib, XUtil{$ENDIF}
-  ;
-
-type
-  // Needed for Delphi 6 and less (defined in system.pas for Delphi 7)
-  PPointer = ^Pointer;
-  PCardinal = ^Cardinal;
-
-  GLenum = Cardinal;
-  GLboolean = BYTEBOOL;
-  GLbitfield = Cardinal;
-  GLbyte = Shortint;
-  GLshort = SmallInt;
-  GLint = Integer;
-  GLsizei = Integer;
-  GLubyte = Byte;
-  GLushort = Word;
-  GLuint = Cardinal;
-  GLfloat = Single;
-  GLclampf = Single;
-  GLdouble = Double;
-  GLclampd = Double;
-  GLvoid = Pointer;
-  GLint64 = Int64;
-  GLuint64 = {$IFDEF DELPHI6_AND_DOWN} Int64 {$ELSE} UInt64 {$ENDIF};
-
-  TGLenum = GLenum;
-  TGLboolean = GLboolean;
-  TGLbitfield = GLbitfield;
-  TGLbyte = GLbyte;
-  TGLshort = GLshort;
-  TGLint = GLint;
-  TGLsizei = GLsizei;
-  TGLubyte = GLubyte;
-  TGLushort = GLushort;
-  TGLuint = GLuint;
-  TGLfloat = GLfloat;
-  TGLclampf = GLclampf;
-  TGLdouble = GLdouble;
-  TGLclampd = GLclampd;
-  TGLvoid = GLvoid;
-  TGLint64 = GLint64;
-  TGLuint64 = GLuint64;
-
-  PGLboolean = ^GLboolean;
-  PGLbyte = ^GLbyte;
-  PGLshort = ^GLshort;
-  PGLint = ^GLint;
-  PGLsizei = ^GLsizei;
-  PGLubyte = ^GLubyte;
-  PGLushort = ^GLushort;
-  PGLuint = ^GLuint;
-  PGLclampf = ^GLclampf;
-  PGLfloat = ^GLfloat;
-  PGLdouble = ^GLdouble;
-  PGLclampd = ^GLclampd;
-  PGLenum = ^GLenum;
-  PGLvoid = Pointer;
-  PPGLvoid = ^PGLvoid;
-  PGLint64 = ^GLint64;
-
-  // GL_NV_half_float
-  GLhalfNV = WORD;
-  TGLhalfNV = GLhalfNV;
-  PGLhalfNV = ^GLhalfNV;
-
-  // GL_ARB_shader_objects
-  PGLHandleARB = ^GLHandleARB;
-  GLHandleARB = Integer;
-  GLcharARB = AnsiChar;
-  PGLcharARB = PAnsiChar;
-  PPGLcharARB = ^PGLcharARB;
-
-  // GL_VERSION_2_0
-  GLHandle = Integer;
-  PGLchar = PAnsiChar;
-  PPGLchar = ^PGLChar;
-
-  // GL_EXT_timer_query
-  GLint64EXT = Int64;
-  TGLint64EXT = GLint64EXT;
-  PGLint64EXT = ^TGLint64EXT;
-
-  GLuint64EXT = TGLuint64;
-  TGLuint64EXT = GLuint64EXT;
-  PGLuint64EXT = ^TGLuint64EXT;
-
-  // WGL_ARB_pbuffer
-  HPBUFFERARB = THandle;
-
-  // WGL_EXT_pbuffer
-  HPBUFFEREXT = THandle;
-
-  // WGL_NV_present_video
-  PHVIDEOOUTPUTDEVICENV = ^HVIDEOOUTPUTDEVICENV;
-  HVIDEOOUTPUTDEVICENV = THandle;
-
-  // WGL_NV_video_out
-  PHPVIDEODEV = ^HPVIDEODEV;
-  HPVIDEODEV = THandle;
-
-  // WGL_NV_gpu_affinity
-  PHPGPUNV = ^HPGPUNV;
-  PHGPUNV = ^HGPUNV;
-
-  HPGPUNV = THandle;
-  HGPUNV = THandle;
-
-  // ARB_sync
-  GLsync = Pointer;
-
-  // GLX
-  {$IFDEF DGL_LINUX}
-    GLXContext = Pointer;
-    GLXContextID = TXID;
-    GLXDrawable = TXID;
-    GLXFBConfig = Pointer;
-    GLXPbuffer = TXID;
-    GLXPixmap = TXID;
-    GLXWindow = TXID;
-
-    Window = TXID;
-    Colormap = TXID;
-    Pixmap = TXID;
-    Font = TXID;
-  {$ENDIF}
-
-  // Datatypes corresponding to GL's types TGL(name)(type)(count)
-  TGLVectorub2 = array[0..1] of TGLubyte;
-  TGLVectori2  = array[0..1] of TGLint;
-  TGLVectorf2  = array[0..1] of TGLfloat;
-  TGLVectord2  = array[0..1] of TGLdouble;
-  TGLVectorp2  = array[0..1] of Pointer;
-
-  TGLVectorub3 = array[0..2] of TGLubyte;
-  TGLVectori3  = array[0..2] of TGLint;
-  TGLVectorf3  = array[0..2] of TGLfloat;
-  TGLVectord3  = array[0..2] of TGLdouble;
-  TGLVectorp3  = array[0..2] of Pointer;
-
-  TGLVectorub4 = array[0..3] of TGLubyte;
-  TGLVectori4  = array[0..3] of TGLint;
-  TGLVectorf4  = array[0..3] of TGLfloat;
-  TGLVectord4  = array[0..3] of TGLdouble;
-  TGLVectorp4  = array[0..3] of Pointer;
-
-  TGLArrayf4 = TGLVectorf4;
-  TGLArrayf3 = TGLVectorf3;
-  TGLArrayd3 = TGLVectord3;
-  TGLArrayi4 = TGLVectori4;
-  TGLArrayp4 = TGLVectorp4;
-
-  TGlMatrixub3 = array[0..2, 0..2] of TGLubyte;
-  TGlMatrixi3  = array[0..2, 0..2] of TGLint;
-  TGLMatrixf3  = array[0..2, 0..2] of TGLfloat;
-  TGLMatrixd3  = array[0..2, 0..2] of TGLdouble;
-
-  TGlMatrixub4 = array[0..3, 0..3] of TGLubyte;
-  TGlMatrixi4  = array[0..3, 0..3] of TGLint;
-  TGLMatrixf4  = array[0..3, 0..3] of TGLfloat;
-  TGLMatrixd4  = array[0..3, 0..3] of TGLdouble;
-
-  TGLVector3f = TGLVectorf3;
-
-  // Datatypes corresponding to OpenGL12.pas for easy porting
-  TVector3d = TGLVectord3;
-
-  TVector4i = TGLVectori4;
-  TVector4f = TGLVectorf4;
-  TVector4p = TGLVectorp4;
-
-  TMatrix4f = TGLMatrixf4;
-  TMatrix4d = TGLMatrixd4;
-
-  PGLMatrixd4 = ^TGLMatrixd4;
-  PVector4i = ^TVector4i;
-
-
-
-{$IFDEF FPC}
-  TRect = packed record
-    Left, Top, Right, Bottom: Longint;
-  end;
-{$ENDIF}
-
-
-  PGPU_DEVICE = ^GPU_DEVICE;
-  GPU_DEVICE = record
-    cb: DWORD;
-    DeviceName: array [0..31] of AnsiChar;
-    DeviceString: array [0..127] of AnsiChar;
-    Flags: DWORD;
-    rcVirtualScreen: TRect;
-  end;
-  
-
-type
-{$IFDEF FPC}
-  {$IFDEF DGL_WIN}
-    PWGLSwap = ^TWGLSwap;
-    {$EXTERNALSYM _WGLSWAP}
-      _WGLSWAP = packed record
-        hdc: HDC;
-        uiFlags: UINT;
-      end;
-
-    TWGLSwap = _WGLSWAP;
-  {$EXTERNALSYM WGLSWAP}
-    WGLSWAP = _WGLSWAP;
-
-  {$ENDIF}
-{$ENDIF}
-
-  // GLU types
-  TGLUNurbs = record
-  end;
-  TGLUQuadric = record
-  end;
-  TGLUTesselator = record
-  end;
-  PGLUNurbs = ^TGLUNurbs;
-  PGLUQuadric = ^TGLUQuadric;
-  PGLUTesselator = ^TGLUTesselator;
-  // backwards compatibility
-  TGLUNurbsObj = TGLUNurbs;
-  TGLUQuadricObj = TGLUQuadric;
-  TGLUTesselatorObj = TGLUTesselator;
-  TGLUTriangulatorObj = TGLUTesselator;
-  PGLUNurbsObj = PGLUNurbs;
-  PGLUQuadricObj = PGLUQuadric;
-  PGLUTesselatorObj = PGLUTesselator;
-  PGLUTriangulatorObj = PGLUTesselator;
-
-  // GLUQuadricCallback
-  TGLUQuadricErrorProc = procedure(errorCode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  // GLUTessCallback
-  TGLUTessBeginProc = procedure(AType: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessEdgeFlagProc = procedure(Flag: GLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessVertexProc = procedure(VertexData: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessEndProc = procedure; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessErrorProc = procedure(ErrNo: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessCombineProc = procedure(Coords: TGLArrayd3; VertexData: TGLArrayp4; Weight: TGLArrayf4; OutData: PPointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessBeginDataProc = procedure(AType: GLenum; UserData: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessEdgeFlagDataProc = procedure(Flag: GLboolean; UserData: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessVertexDataProc = procedure(VertexData: Pointer; UserData: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessEndDataProc = procedure(UserData: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessErrorDataProc = procedure(ErrNo: GLenum; UserData: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TGLUTessCombineDataProc = procedure(Coords: TGLArrayd3; VertexData: TGLArrayp4; Weight: TGLArrayf4; OutData: PPointer; UserData: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  // GLUNurbsCallback
-  TGLUNurbsErrorProc = procedure(ErrorCode: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-var
-  GL_VERSION_1_0,
-  GL_VERSION_1_1,
-  GL_VERSION_1_2,
-  GL_VERSION_1_3,
-  GL_VERSION_1_4,
-  GL_VERSION_1_5,
-  GL_VERSION_2_0,
-  GL_VERSION_2_1,
-  GL_VERSION_3_0,
-  GL_VERSION_3_1,
-  GL_VERSION_3_2,
-  GLU_VERSION_1_1,
-  GLU_VERSION_1_2,
-  GLU_VERSION_1_3,
-  GL_3DFX_multisample,
-  GL_3DFX_tbuffer,
-  GL_3DFX_texture_compression_FXT1,
-  GL_APPLE_client_storage,
-  GL_APPLE_element_array,
-  GL_APPLE_fence,
-  GL_APPLE_specular_vector,
-  GL_APPLE_transform_hint,
-  GL_APPLE_vertex_array_object,
-  GL_APPLE_vertex_array_range,
-  GL_APPLE_ycbcr_422,
-  GL_APPLE_texture_range,
-  GL_APPLE_float_pixels,
-  GL_APPLE_vertex_program_evaluators,
-  GL_APPLE_aux_depth_stencil,
-  GL_APPLE_object_purgeable,
-  GL_APPLE_row_bytes,
-  GL_ARB_depth_texture,
-  GL_ARB_fragment_program,
-  GL_ARB_imaging,
-  GL_ARB_matrix_palette,
-  GL_ARB_multisample,
-  GL_ARB_multitexture,
-  GL_ARB_point_parameters,
-  GL_ARB_shadow,
-  GL_ARB_shadow_ambient,
-  GL_ARB_texture_border_clamp,
-  GL_ARB_texture_compression,
-  GL_ARB_texture_cube_map,
-  GL_ARB_texture_env_add,
-  GL_ARB_texture_env_combine,
-  GL_ARB_texture_env_crossbar,
-  GL_ARB_texture_env_dot3,
-  GL_ARB_texture_mirrored_repeat,
-  GL_ARB_transpose_matrix,
-  GL_ARB_vertex_blend,
-  GL_ARB_vertex_buffer_object,
-  GL_ARB_vertex_program,
-  GL_ARB_window_pos,
-  GL_ARB_shader_objects,
-  GL_ARB_vertex_shader,
-  GL_ARB_fragment_shader,
-  GL_ARB_shading_language_100,
-  GL_ARB_occlusion_query,
-  GL_ARB_texture_non_power_of_two,
-  GL_ARB_point_sprite,
-  GL_ARB_fragment_program_shadow,
-  GL_ARB_draw_buffers,
-  GL_ARB_texture_rectangle,
-  GL_ARB_color_buffer_float,
-  GL_ARB_half_float_pixel,
-  GL_ARB_texture_float,
-  GL_ARB_pixel_buffer_object,
-  GL_ARB_depth_buffer_float,
-  GL_ARB_draw_instanced,
-  GL_ARB_framebuffer_object,
-  GL_ARB_framebuffer_sRGB,
-  GL_ARB_geometry_shader4,
-  GL_ARB_half_float_vertex,
-  GL_ARB_instanced_arrays,
-  GL_ARB_map_buffer_range,
-  GL_ARB_texture_buffer_object,
-  GL_ARB_texture_compression_rgtc,
-  GL_ARB_texture_rg,
-  GL_ARB_vertex_array_object,
-  GL_ARB_uniform_buffer_object,
-  GL_ARB_compatibility,
-  GL_ARB_copy_buffer,
-  GL_ARB_shader_texture_lod,
-  GL_ARB_depth_clamp,
-  GL_ARB_draw_elements_base_vertex,
-  GL_ARB_fragment_coord_conventions,
-  GL_ARB_provoking_vertex,
-  GL_ARB_seamless_cube_map,
-  GL_ARB_sync,
-  GL_ARB_texture_multisample,
-  GL_ARB_vertex_array_bgra,
-  GL_ARB_draw_buffers_blend,
-  GL_ARB_sample_shading,
-  GL_ARB_texture_cube_map_array,
-  GL_ARB_texture_gather,
-  GL_ARB_texture_query_lod,
-  GL_ATI_draw_buffers,
-  GL_ATI_element_array,
-  GL_ATI_envmap_bumpmap,
-  GL_ATI_fragment_shader,
-  GL_ATI_map_object_buffer,
-  GL_ATI_pn_triangles,
-  GL_ATI_separate_stencil,
-  GL_ATI_text_fragment_shader,
-  GL_ATI_texture_env_combine3,
-  GL_ATI_texture_float,
-  GL_ATI_texture_mirror_once,
-  GL_ATI_vertex_array_object,
-  GL_ATI_vertex_attrib_array_object,
-  GL_ATI_vertex_streams,
-  GL_ATI_meminfo,
-  GL_AMD_performance_monitor,
-  GL_AMD_texture_texture4,
-  GL_AMD_vertex_shader_tesselator,
-  GL_AMD_draw_buffers_blend,
-  GL_EXT_422_pixels,
-  GL_EXT_abgr,
-  GL_EXT_bgra,
-  GL_EXT_blend_color,
-  GL_EXT_blend_func_separate,
-  GL_EXT_blend_logic_op,
-  GL_EXT_blend_minmax,
-  GL_EXT_blend_subtract,
-  GL_EXT_clip_volume_hint,
-  GL_EXT_cmyka,
-  GL_EXT_color_matrix,
-  GL_EXT_color_subtable,
-  GL_EXT_compiled_vertex_array,
-  GL_EXT_convolution,
-  GL_EXT_coordinate_frame,
-  GL_EXT_copy_texture,
-  GL_EXT_cull_vertex,
-  GL_EXT_draw_range_elements,
-  GL_EXT_fog_coord,
-  GL_EXT_framebuffer_object,
-  GL_EXT_histogram,
-  GL_EXT_index_array_formats,
-  GL_EXT_index_func,
-  GL_EXT_index_material,
-  GL_EXT_index_texture,
-  GL_EXT_light_texture,
-  GL_EXT_misc_attribute,
-  GL_EXT_multi_draw_arrays,
-  GL_EXT_multisample,
-  GL_EXT_packed_pixels,
-  GL_EXT_paletted_texture,
-  GL_EXT_pixel_transform,
-  GL_EXT_pixel_transform_color_table,
-  GL_EXT_point_parameters,
-  GL_EXT_polygon_offset,
-  GL_EXT_rescale_normal,
-  GL_EXT_secondary_color,
-  GL_EXT_separate_specular_color,
-  GL_EXT_shadow_funcs,
-  GL_EXT_shared_texture_palette,
-  GL_EXT_stencil_two_side,
-  GL_EXT_stencil_wrap,
-  GL_EXT_subtexture,
-  GL_EXT_texture,
-  GL_EXT_texture3D,
-  GL_EXT_texture_compression_s3tc,
-  GL_EXT_texture_cube_map,
-  GL_EXT_texture_edge_clamp,
-  GL_EXT_texture_env_add,
-  GL_EXT_texture_env_combine,
-  GL_EXT_texture_env_dot3,
-  GL_EXT_texture_filter_anisotropic,
-  GL_EXT_texture_lod_bias,
-  GL_EXT_texture_object,
-  GL_EXT_texture_perturb_normal,
-  GL_EXT_texture_rectangle,
-  GL_EXT_vertex_array,
-  GL_EXT_vertex_shader,
-  GL_EXT_vertex_weighting,
-  GL_EXT_depth_bounds_test,
-  GL_EXT_texture_mirror_clamp,
-  GL_EXT_blend_equation_separate,
-  GL_EXT_pixel_buffer_object,
-  GL_EXT_texture_compression_dxt1,
-  GL_EXT_stencil_clear_tag,
-  GL_EXT_packed_depth_stencil,
-  GL_EXT_texture_sRGB,
-  GL_EXT_framebuffer_blit,
-  GL_EXT_framebuffer_multisample,
-  GL_EXT_timer_query,
-  GL_EXT_gpu_program_parameters,
-  GL_EXT_bindable_uniform,
-  GL_EXT_draw_buffers2,
-  GL_EXT_draw_instanced,
-  GL_EXT_framebuffer_sRGB,
-  GL_EXT_geometry_shader4,
-  GL_EXT_gpu_shader4,
-  GL_EXT_packed_float,
-  GL_EXT_texture_array,
-  GL_EXT_texture_buffer_object,
-  GL_EXT_texture_compression_latc,
-  GL_EXT_texture_compression_rgtc,
-  GL_EXT_texture_integer,
-  GL_EXT_texture_shared_exponent,
-  GL_EXT_transform_feedback,
-  GL_EXT_direct_state_access,
-  GL_EXT_vertex_array_bgra,
-  GL_EXT_texture_swizzle,
-  GL_EXT_provoking_vertex,
-  GL_EXT_texture_snorm,
-  GL_FfdMaskSGIX,
-  GL_HP_convolution_border_modes,
-  GL_HP_image_transform,
-  GL_HP_occlusion_test,
-  GL_HP_texture_lighting,
-  GL_IBM_cull_vertex,
-  GL_IBM_multimode_draw_arrays,
-  GL_IBM_rasterpos_clip,
-  GL_IBM_texture_mirrored_repeat,
-  GL_IBM_vertex_array_lists,
-  GL_INGR_blend_func_separate,
-  GL_INGR_color_clamp,
-  GL_INGR_interlace_read,
-  GL_INGR_palette_buffer,
-  GL_INTEL_parallel_arrays,
-  GL_INTEL_texture_scissor,
-  GL_MESA_resize_buffers,
-  GL_MESA_window_pos,
-  GL_NV_blend_square,
-  GL_NV_copy_depth_to_color,
-  GL_NV_depth_clamp,
-  GL_NV_evaluators,
-  GL_NV_fence,
-  GL_NV_float_buffer,
-  GL_NV_fog_distance,
-  GL_NV_fragment_program,
-  GL_NV_half_float,
-  GL_NV_light_max_exponent,
-  GL_NV_multisample_filter_hint,
-  GL_NV_occlusion_query,
-  GL_NV_packed_depth_stencil,
-  GL_NV_pixel_data_range,
-  GL_NV_point_sprite,
-  GL_NV_primitive_restart,
-  GL_NV_register_combiners,
-  GL_NV_register_combiners2,
-  GL_NV_texgen_emboss,
-  GL_NV_texgen_reflection,
-  GL_NV_texture_compression_vtc,
-  GL_NV_texture_env_combine4,
-  GL_NV_texture_expand_normal,
-  GL_NV_texture_rectangle,
-  GL_NV_texture_shader,
-  GL_NV_texture_shader2,
-  GL_NV_texture_shader3,
-  GL_NV_vertex_array_range,
-  GL_NV_vertex_array_range2,
-  GL_NV_vertex_program,
-  GL_NV_vertex_program1_1,
-  GL_NV_vertex_program2,
-  GL_NV_fragment_program_option,
-  GL_NV_fragment_program2,
-  GL_NV_vertex_program2_option,
-  GL_NV_vertex_program3,
-  GL_NV_depth_buffer_float,
-  GL_NV_fragment_program4,
-  GL_NV_framebuffer_multisample_coverage,
-  GL_NV_geometry_program4,
-  GL_NV_gpu_program4,
-  GL_NV_parameter_buffer_object,
-  GL_NV_transform_feedback,
-  GL_NV_vertex_program4,
-  GL_NV_conditional_render,
-  GL_NV_present_video,
-  GL_NV_explicit_multisample,
-  GL_NV_transform_feedback2,
-  GL_OML_interlace,
-  GL_OML_resample,
-  GL_OML_subsample,
-  GL_PGI_misc_hints,
-  GL_PGI_vertex_hints,
-  GL_REND_screen_coordinates,
-  GL_S3_s3tc,
-  GL_SGIS_detail_texture,
-  GL_SGIS_fog_function,
-  GL_SGIS_generate_mipmap,
-  GL_SGIS_multisample,
-  GL_SGIS_pixel_texture,
-  GL_SGIS_point_line_texgen,
-  GL_SGIS_point_parameters,
-  GL_SGIS_sharpen_texture,
-  GL_SGIS_texture4D,
-  GL_SGIS_texture_border_clamp,
-  GL_SGIS_texture_color_mask,
-  GL_SGIS_texture_edge_clamp,
-  GL_SGIS_texture_filter4,
-  GL_SGIS_texture_lod,
-  GL_SGIS_texture_select,
-  GL_SGIX_async,
-  GL_SGIX_async_histogram,
-  GL_SGIX_async_pixel,
-  GL_SGIX_blend_alpha_minmax,
-  GL_SGIX_calligraphic_fragment,
-  GL_SGIX_clipmap,
-  GL_SGIX_convolution_accuracy,
-  GL_SGIX_depth_pass_instrument,
-  GL_SGIX_depth_texture,
-  GL_SGIX_flush_raster,
-  GL_SGIX_fog_offset,
-  GL_SGIX_fog_scale,
-  GL_SGIX_fragment_lighting,
-  GL_SGIX_framezoom,
-  GL_SGIX_igloo_interface,
-  GL_SGIX_impact_pixel_texture,
-  GL_SGIX_instruments,
-  GL_SGIX_interlace,
-  GL_SGIX_ir_instrument1,
-  GL_SGIX_list_priority,
-  GL_SGIX_pixel_texture,
-  GL_SGIX_pixel_tiles,
-  GL_SGIX_polynomial_ffd,
-  GL_SGIX_reference_plane,
-  GL_SGIX_resample,
-  GL_SGIX_scalebias_hint,
-  GL_SGIX_shadow,
-  GL_SGIX_shadow_ambient,
-  GL_SGIX_sprite,
-  GL_SGIX_subsample,
-  GL_SGIX_tag_sample_buffer,
-  GL_SGIX_texture_add_env,
-  GL_SGIX_texture_coordinate_clamp,
-  GL_SGIX_texture_lod_bias,
-  GL_SGIX_texture_multi_buffer,
-  GL_SGIX_texture_scale_bias,
-  GL_SGIX_texture_select,
-  GL_SGIX_vertex_preclip,
-  GL_SGIX_ycrcb,
-  GL_SGIX_ycrcb_subsample,
-  GL_SGIX_ycrcba,
-  GL_SGI_color_matrix,
-  GL_SGI_color_table,
-  GL_SGI_depth_pass_instrument,
-  GL_SGI_texture_color_table,
-  GL_SUNX_constant_data,
-  GL_SUN_convolution_border_modes,
-  GL_SUN_global_alpha,
-  GL_SUN_mesh_array,
-  GL_SUN_slice_accum,
-  GL_SUN_triangle_list,
-  GL_SUN_vertex,
-
-  GL_WIN_phong_shading,
-  GL_WIN_specular_fog,
-  WGL_3DFX_multisample,
-  WGL_ARB_buffer_region,
-  WGL_ARB_extensions_string,
-  WGL_ARB_make_current_read,
-  WGL_ARB_multisample,
-  WGL_ARB_pbuffer,
-  WGL_ARB_pixel_format,
-  WGL_ARB_pixel_format_float,
-  WGL_ARB_render_texture,
-  WGL_ARB_create_context,
-  WGL_ARB_create_context_profile,
-  WGL_ATI_pixel_format_float,
-  WGL_AMD_gpu_association,
-  WGL_EXT_depth_float,
-  WGL_EXT_display_color_table,
-  WGL_EXT_extensions_string,
-  WGL_EXT_make_current_read,
-  WGL_EXT_multisample,
-  WGL_EXT_pbuffer,
-  WGL_EXT_pixel_format,
-  WGL_EXT_swap_control,
-  WGL_I3D_digital_video_control,
-  WGL_I3D_gamma,
-  WGL_I3D_genlock,
-  WGL_I3D_image_buffer,
-  WGL_I3D_swap_frame_lock,
-  WGL_I3D_swap_frame_usage,
-  WGL_NV_float_buffer,
-  WGL_NV_render_depth_texture,
-  WGL_NV_render_texture_rectangle,
-  WGL_NV_vertex_array_range,
-  WGL_NV_present_video,
-  WGL_NV_video_out,
-  WGL_NV_swap_group,
-  WGL_NV_gpu_affinity,
-  WGL_OML_sync_control,
-  WGL_3DL_stereo_control,
-  WIN_draw_range_elements,
-  WIN_swap_hint,
-  
-//  GLX_VERSION_1_0,
-  GLX_VERSION_1_3,
-  GLX_VERSION_1_4,
-  GLX_ARB_multisample,
-  GLX_ARB_fbconfig_float,
-  GLX_ARB_get_proc_address,
-  GLX_ARB_create_context,
-  GLX_ARB_create_context_profile,
-  GLX_EXT_visual_info,
-  GLX_EXT_visual_rating,
-  GLX_EXT_import_context,
-  GLX_EXT_fbconfig_packed_float,
-  GLX_EXT_framebuffer_sRGB,
-  GLX_EXT_texture_from_pixmap: Boolean;
-
-const
-  // GL_VERSION_1_1
-  { AttribMask }
-  GL_DEPTH_BUFFER_BIT = $00000100;
-  GL_STENCIL_BUFFER_BIT = $00000400;
-  GL_COLOR_BUFFER_BIT = $00004000;
-  { Boolean }
-  GL_TRUE = 1;
-  GL_FALSE = 0;
-  { BeginMode }
-  GL_POINTS = $0000;
-  GL_LINES = $0001;
-  GL_LINE_LOOP = $0002;
-  GL_LINE_STRIP = $0003;
-  GL_TRIANGLES = $0004;
-  GL_TRIANGLE_STRIP = $0005;
-  GL_TRIANGLE_FAN = $0006;
-  { AlphaFunction }
-  GL_NEVER = $0200;
-  GL_LESS = $0201;
-  GL_EQUAL = $0202;
-  GL_LEQUAL = $0203;
-  GL_GREATER = $0204;
-  GL_NOTEQUAL = $0205;
-  GL_GEQUAL = $0206;
-  GL_ALWAYS = $0207;
-  { BlendingFactorDest }
-  GL_ZERO = 0;
-  GL_ONE = 1;
-  GL_SRC_COLOR = $0300;
-  GL_ONE_MINUS_SRC_COLOR = $0301;
-  GL_SRC_ALPHA = $0302;
-  GL_ONE_MINUS_SRC_ALPHA = $0303;
-  GL_DST_ALPHA = $0304;
-  GL_ONE_MINUS_DST_ALPHA = $0305;
-  { BlendingFactorSrc }
-  GL_DST_COLOR = $0306;
-  GL_ONE_MINUS_DST_COLOR = $0307;
-  GL_SRC_ALPHA_SATURATE = $0308;
-  { DrawBufferMode }
-  GL_NONE = 0;
-  GL_FRONT_LEFT = $0400;
-  GL_FRONT_RIGHT = $0401;
-  GL_BACK_LEFT = $0402;
-  GL_BACK_RIGHT = $0403;
-  GL_FRONT = $0404;
-  GL_BACK = $0405;
-  GL_LEFT = $0406;
-  GL_RIGHT = $0407;
-  GL_FRONT_AND_BACK = $0408;
-  { ErrorCode }
-  GL_NO_ERROR = 0;
-  GL_INVALID_ENUM = $0500;
-  GL_INVALID_VALUE = $0501;
-  GL_INVALID_OPERATION = $0502;
-  GL_OUT_OF_MEMORY = $0505;
-  { FrontFaceDirection }
-  GL_CW = $0900;
-  GL_CCW = $0901;
-  { GetPName }
-  GL_POINT_SIZE = $0B11;
-  GL_POINT_SIZE_RANGE = $0B12;
-  GL_POINT_SIZE_GRANULARITY = $0B13;
-  GL_LINE_SMOOTH = $0B20;
-  GL_LINE_WIDTH = $0B21;
-  GL_LINE_WIDTH_RANGE = $0B22;
-  GL_LINE_WIDTH_GRANULARITY = $0B23;
-  GL_POLYGON_SMOOTH = $0B41;
-  GL_CULL_FACE = $0B44;
-  GL_CULL_FACE_MODE = $0B45;
-  GL_FRONT_FACE = $0B46;
-  GL_DEPTH_RANGE = $0B70;
-  GL_DEPTH_TEST = $0B71;
-  GL_DEPTH_WRITEMASK = $0B72;
-  GL_DEPTH_CLEAR_VALUE = $0B73;
-  GL_DEPTH_FUNC = $0B74;
-  GL_STENCIL_TEST = $0B90;
-  GL_STENCIL_CLEAR_VALUE = $0B91;
-  GL_STENCIL_FUNC = $0B92;
-  GL_STENCIL_VALUE_MASK = $0B93;
-  GL_STENCIL_FAIL = $0B94;
-  GL_STENCIL_PASS_DEPTH_FAIL = $0B95;
-  GL_STENCIL_PASS_DEPTH_PASS = $0B96;
-  GL_STENCIL_REF = $0B97;
-  GL_STENCIL_WRITEMASK = $0B98;
-  GL_VIEWPORT = $0BA2;
-  GL_DITHER = $0BD0;
-  GL_BLEND_DST = $0BE0;
-  GL_BLEND_SRC = $0BE1;
-  GL_BLEND = $0BE2;
-  GL_LOGIC_OP_MODE = $0BF0;
-  GL_COLOR_LOGIC_OP = $0BF2;
-  GL_DRAW_BUFFER = $0C01;
-  GL_READ_BUFFER = $0C02;
-  GL_SCISSOR_BOX = $0C10;
-  GL_SCISSOR_TEST = $0C11;
-  GL_COLOR_CLEAR_VALUE = $0C22;
-  GL_COLOR_WRITEMASK = $0C23;
-  GL_DOUBLEBUFFER = $0C32;
-  GL_STEREO = $0C33;
-  GL_LINE_SMOOTH_HINT = $0C52;
-  GL_POLYGON_SMOOTH_HINT = $0C53;
-  GL_UNPACK_SWAP_BYTES = $0CF0;
-  GL_UNPACK_LSB_FIRST = $0CF1;
-  GL_UNPACK_ROW_LENGTH = $0CF2;
-  GL_UNPACK_SKIP_ROWS = $0CF3;
-  GL_UNPACK_SKIP_PIXELS = $0CF4;
-  GL_UNPACK_ALIGNMENT = $0CF5;
-  GL_PACK_SWAP_BYTES = $0D00;
-  GL_PACK_LSB_FIRST = $0D01;
-  GL_PACK_ROW_LENGTH = $0D02;
-  GL_PACK_SKIP_ROWS = $0D03;
-  GL_PACK_SKIP_PIXELS = $0D04;
-  GL_PACK_ALIGNMENT = $0D05;
-  GL_MAX_TEXTURE_SIZE = $0D33;
-  GL_MAX_VIEWPORT_DIMS = $0D3A;
-  GL_SUBPIXEL_BITS = $0D50;
-  GL_TEXTURE_1D = $0DE0;
-  GL_TEXTURE_2D = $0DE1;
-  GL_POLYGON_OFFSET_UNITS = $2A00;
-  GL_POLYGON_OFFSET_POINT = $2A01;
-  GL_POLYGON_OFFSET_LINE = $2A02;
-  GL_POLYGON_OFFSET_FILL = $8037;
-  GL_POLYGON_OFFSET_FACTOR = $8038;
-  GL_TEXTURE_BINDING_1D = $8068;
-  GL_TEXTURE_BINDING_2D = $8069;
-  { GetTextureParameter }
-  GL_TEXTURE_WIDTH = $1000;
-  GL_TEXTURE_HEIGHT = $1001;
-  GL_TEXTURE_INTERNAL_FORMAT = $1003;
-  GL_TEXTURE_BORDER_COLOR = $1004;
-  GL_TEXTURE_BORDER = $1005;
-  GL_TEXTURE_RED_SIZE = $805C;
-  GL_TEXTURE_GREEN_SIZE = $805D;
-  GL_TEXTURE_BLUE_SIZE = $805E;
-  GL_TEXTURE_ALPHA_SIZE = $805F;
-  { HintMode }
-  GL_DONT_CARE = $1100;
-  GL_FASTEST = $1101;
-  GL_NICEST = $1102;
-  { DataType }
-  GL_BYTE = $1400;
-  GL_UNSIGNED_BYTE = $1401;
-  GL_SHORT = $1402;
-  GL_UNSIGNED_SHORT = $1403;
-  GL_INT = $1404;
-  GL_UNSIGNED_INT = $1405;
-  GL_FLOAT = $1406;
-  GL_DOUBLE = $140A;
-  { LogicOp }
-  GL_CLEAR = $1500;
-  GL_AND = $1501;
-  GL_AND_REVERSE = $1502;
-  GL_COPY = $1503;
-  GL_AND_INVERTED = $1504;
-  GL_NOOP = $1505;
-  GL_XOR = $1506;
-  GL_OR = $1507;
-  GL_NOR = $1508;
-  GL_EQUIV = $1509;
-  GL_INVERT = $150A;
-  GL_OR_REVERSE = $150B;
-  GL_COPY_INVERTED = $150C;
-  GL_OR_INVERTED = $150D;
-  GL_NAND = $150E;
-  GL_SET = $150F;
-  { MatrixMode (for gl3.h, FBO attachment type) }
-  GL_TEXTURE = $1702;
-  { PixelCopyType }
-  GL_COLOR = $1800;
-  GL_DEPTH = $1801;
-  GL_STENCIL = $1802;
-  { PixelFormat }
-  GL_STENCIL_INDEX = $1901;
-  GL_DEPTH_COMPONENT = $1902;
-  GL_RED = $1903;
-  GL_GREEN = $1904;
-  GL_BLUE = $1905;
-  GL_ALPHA = $1906;
-  GL_RGB = $1907;
-  GL_RGBA = $1908;
-  { PolygonMode }
-  GL_POINT = $1B00;
-  GL_LINE = $1B01;
-  GL_FILL = $1B02;
-  { StencilOp }
-  GL_KEEP = $1E00;
-  GL_REPLACE = $1E01;
-  GL_INCR = $1E02;
-  GL_DECR = $1E03;
-  { StringName }
-  GL_VENDOR = $1F00;
-  GL_RENDERER = $1F01;
-  GL_VERSION = $1F02;
-  GL_EXTENSIONS = $1F03;
-  { TextureMagFilter }
-  GL_NEAREST = $2600;
-  GL_LINEAR = $2601;
-  { TextureMinFilter }
-  GL_NEAREST_MIPMAP_NEAREST = $2700;
-  GL_LINEAR_MIPMAP_NEAREST = $2701;
-  GL_NEAREST_MIPMAP_LINEAR = $2702;
-  GL_LINEAR_MIPMAP_LINEAR = $2703;
-  { TextureParameterName }
-  GL_TEXTURE_MAG_FILTER = $2800;
-  GL_TEXTURE_MIN_FILTER = $2801;
-  GL_TEXTURE_WRAP_S = $2802;
-  GL_TEXTURE_WRAP_T = $2803;
-  { TextureTarget }
-  GL_PROXY_TEXTURE_1D = $8063;
-  GL_PROXY_TEXTURE_2D = $8064;
-  { TextureWrapMode }
-  GL_REPEAT = $2901;
-  { PixelInternalFormat }
-  GL_R3_G3_B2 = $2A10;
-  GL_RGB4 = $804F;
-  GL_RGB5 = $8050;
-  GL_RGB8 = $8051;
-  GL_RGB10 = $8052;
-  GL_RGB12 = $8053;
-  GL_RGB16 = $8054;
-  GL_RGBA2 = $8055;
-  GL_RGBA4 = $8056;
-  GL_RGB5_A1 = $8057;
-  GL_RGBA8 = $8058;
-  GL_RGB10_A2 = $8059;
-  GL_RGBA12 = $805A;
-  GL_RGBA16 = $805B;
-{$ifdef DGL_DEPRECATED}
-  GL_ACCUM = $0100;
-  GL_LOAD = $0101;
-  GL_RETURN = $0102;
-  GL_MULT = $0103;
-  GL_ADD = $0104;
-  GL_CURRENT_BIT = $00000001;
-  GL_POINT_BIT = $00000002;
-  GL_LINE_BIT = $00000004;
-  GL_POLYGON_BIT = $00000008;
-  GL_POLYGON_STIPPLE_BIT = $00000010;
-  GL_PIXEL_MODE_BIT = $00000020;
-  GL_LIGHTING_BIT = $00000040;
-  GL_FOG_BIT = $00000080;
-  GL_ACCUM_BUFFER_BIT = $00000200;
-  GL_VIEWPORT_BIT = $00000800;
-  GL_TRANSFORM_BIT = $00001000;
-  GL_ENABLE_BIT = $00002000;
-  GL_HINT_BIT = $00008000;
-  GL_EVAL_BIT = $00010000;
-  GL_LIST_BIT = $00020000;
-  GL_TEXTURE_BIT = $00040000;
-  GL_SCISSOR_BIT = $00080000;
-  GL_ALL_ATTRIB_BITS = $000FFFFF;
-  GL_QUADS = $0007;
-  GL_QUAD_STRIP = $0008;
-  GL_POLYGON = $0009;
-  GL_CLIP_PLANE0 = $3000;
-  GL_CLIP_PLANE1 = $3001;
-  GL_CLIP_PLANE2 = $3002;
-  GL_CLIP_PLANE3 = $3003;
-  GL_CLIP_PLANE4 = $3004;
-  GL_CLIP_PLANE5 = $3005;
-  GL_2_BYTES = $1407;
-  GL_3_BYTES = $1408;
-  GL_4_BYTES = $1409;
-  GL_AUX0 = $0409;
-  GL_AUX1 = $040A;
-  GL_AUX2 = $040B;
-  GL_AUX3 = $040C;
-  GL_STACK_OVERFLOW = $0503;
-  GL_STACK_UNDERFLOW = $0504;
-  GL_2D = $0600;
-  GL_3D = $0601;
-  GL_3D_COLOR = $0602;
-  GL_3D_COLOR_TEXTURE = $0603;
-  GL_4D_COLOR_TEXTURE = $0604;
-  GL_PASS_THROUGH_TOKEN = $0700;
-  GL_POINT_TOKEN = $0701;
-  GL_LINE_TOKEN = $0702;
-  GL_POLYGON_TOKEN = $0703;
-  GL_BITMAP_TOKEN = $0704;
-  GL_DRAW_PIXEL_TOKEN = $0705;
-  GL_COPY_PIXEL_TOKEN = $0706;
-  GL_LINE_RESET_TOKEN = $0707;
-  GL_EXP = $0800;
-  GL_EXP2 = $0801;
-  GL_COEFF = $0A00;
-  GL_ORDER = $0A01;
-  GL_DOMAIN = $0A02;
-  GL_CURRENT_COLOR = $0B00;
-  GL_CURRENT_INDEX = $0B01;
-  GL_CURRENT_NORMAL = $0B02;
-  GL_CURRENT_TEXTURE_COORDS = $0B03;
-  GL_CURRENT_RASTER_COLOR = $0B04;
-  GL_CURRENT_RASTER_INDEX = $0B05;
-  GL_CURRENT_RASTER_TEXTURE_COORDS = $0B06;
-  GL_CURRENT_RASTER_POSITION = $0B07;
-  GL_CURRENT_RASTER_POSITION_VALID = $0B08;
-  GL_CURRENT_RASTER_DISTANCE = $0B09;
-  GL_POINT_SMOOTH = $0B10;
-  GL_LINE_STIPPLE = $0B24;
-  GL_LINE_STIPPLE_PATTERN = $0B25;
-  GL_LINE_STIPPLE_REPEAT = $0B26;
-  GL_LIST_MODE = $0B30;
-  GL_MAX_LIST_NESTING = $0B31;
-  GL_LIST_BASE = $0B32;
-  GL_LIST_INDEX = $0B33;
-  GL_POLYGON_MODE = $0B40;
-  GL_POLYGON_STIPPLE = $0B42;
-  GL_EDGE_FLAG = $0B43;
-  GL_LIGHTING = $0B50;
-  GL_LIGHT_MODEL_LOCAL_VIEWER = $0B51;
-  GL_LIGHT_MODEL_TWO_SIDE = $0B52;
-  GL_LIGHT_MODEL_AMBIENT = $0B53;
-  GL_SHADE_MODEL = $0B54;
-  GL_COLOR_MATERIAL_FACE = $0B55;
-  GL_COLOR_MATERIAL_PARAMETER = $0B56;
-  GL_COLOR_MATERIAL = $0B57;
-  GL_FOG = $0B60;
-  GL_FOG_INDEX = $0B61;
-  GL_FOG_DENSITY = $0B62;
-  GL_FOG_START = $0B63;
-  GL_FOG_END = $0B64;
-  GL_FOG_MODE = $0B65;
-  GL_FOG_COLOR = $0B66;
-  GL_ACCUM_CLEAR_VALUE = $0B80;
-  GL_MATRIX_MODE = $0BA0;
-  GL_NORMALIZE = $0BA1;
-  GL_MODELVIEW_STACK_DEPTH = $0BA3;
-  GL_PROJECTION_STACK_DEPTH = $0BA4;
-  GL_TEXTURE_STACK_DEPTH = $0BA5;
-  GL_MODELVIEW_MATRIX = $0BA6;
-  GL_PROJECTION_MATRIX = $0BA7;
-  GL_TEXTURE_MATRIX = $0BA8;
-  GL_ATTRIB_STACK_DEPTH = $0BB0;
-  GL_CLIENT_ATTRIB_STACK_DEPTH = $0BB1;
-  GL_ALPHA_TEST = $0BC0;
-  GL_ALPHA_TEST_FUNC = $0BC1;
-  GL_ALPHA_TEST_REF = $0BC2;
-  GL_INDEX_LOGIC_OP = $0BF1;
-  GL_AUX_BUFFERS = $0C00;
-  GL_INDEX_CLEAR_VALUE = $0C20;
-  GL_INDEX_WRITEMASK = $0C21;
-  GL_INDEX_MODE = $0C30;
-  GL_RGBA_MODE = $0C31;
-  GL_RENDER_MODE = $0C40;
-  GL_PERSPECTIVE_CORRECTION_HINT = $0C50;
-  GL_POINT_SMOOTH_HINT = $0C51;
-  GL_FOG_HINT = $0C54;
-  GL_TEXTURE_GEN_S = $0C60;
-  GL_TEXTURE_GEN_T = $0C61;
-  GL_TEXTURE_GEN_R = $0C62;
-  GL_TEXTURE_GEN_Q = $0C63;
-  GL_PIXEL_MAP_I_TO_I = $0C70;
-  GL_PIXEL_MAP_S_TO_S = $0C71;
-  GL_PIXEL_MAP_I_TO_R = $0C72;
-  GL_PIXEL_MAP_I_TO_G = $0C73;
-  GL_PIXEL_MAP_I_TO_B = $0C74;
-  GL_PIXEL_MAP_I_TO_A = $0C75;
-  GL_PIXEL_MAP_R_TO_R = $0C76;
-  GL_PIXEL_MAP_G_TO_G = $0C77;
-  GL_PIXEL_MAP_B_TO_B = $0C78;
-  GL_PIXEL_MAP_A_TO_A = $0C79;
-  GL_PIXEL_MAP_I_TO_I_SIZE = $0CB0;
-  GL_PIXEL_MAP_S_TO_S_SIZE = $0CB1;
-  GL_PIXEL_MAP_I_TO_R_SIZE = $0CB2;
-  GL_PIXEL_MAP_I_TO_G_SIZE = $0CB3;
-  GL_PIXEL_MAP_I_TO_B_SIZE = $0CB4;
-  GL_PIXEL_MAP_I_TO_A_SIZE = $0CB5;
-  GL_PIXEL_MAP_R_TO_R_SIZE = $0CB6;
-  GL_PIXEL_MAP_G_TO_G_SIZE = $0CB7;
-  GL_PIXEL_MAP_B_TO_B_SIZE = $0CB8;
-  GL_PIXEL_MAP_A_TO_A_SIZE = $0CB9;
-  GL_MAP_COLOR = $0D10;
-  GL_MAP_STENCIL = $0D11;
-  GL_INDEX_SHIFT = $0D12;
-  GL_INDEX_OFFSET = $0D13;
-  GL_RED_SCALE = $0D14;
-  GL_RED_BIAS = $0D15;
-  GL_ZOOM_X = $0D16;
-  GL_ZOOM_Y = $0D17;
-  GL_GREEN_SCALE = $0D18;
-  GL_GREEN_BIAS = $0D19;
-  GL_BLUE_SCALE = $0D1A;
-  GL_BLUE_BIAS = $0D1B;
-  GL_ALPHA_SCALE = $0D1C;
-  GL_ALPHA_BIAS = $0D1D;
-  GL_DEPTH_SCALE = $0D1E;
-  GL_DEPTH_BIAS = $0D1F;
-  GL_MAX_EVAL_ORDER = $0D30;
-  GL_MAX_LIGHTS = $0D31;
-  GL_MAX_CLIP_PLANES = $0D32;
-  GL_MAX_PIXEL_MAP_TABLE = $0D34;
-  GL_MAX_ATTRIB_STACK_DEPTH = $0D35;
-  GL_MAX_MODELVIEW_STACK_DEPTH = $0D36;
-  GL_MAX_NAME_STACK_DEPTH = $0D37;
-  GL_MAX_PROJECTION_STACK_DEPTH = $0D38;
-  GL_MAX_TEXTURE_STACK_DEPTH = $0D39;
-  GL_MAX_CLIENT_ATTRIB_STACK_DEPTH = $0D3B;
-  GL_INDEX_BITS = $0D51;
-  GL_RED_BITS = $0D52;
-  GL_GREEN_BITS = $0D53;
-  GL_BLUE_BITS = $0D54;
-  GL_ALPHA_BITS = $0D55;
-  GL_DEPTH_BITS = $0D56;
-  GL_STENCIL_BITS = $0D57;
-  GL_ACCUM_RED_BITS = $0D58;
-  GL_ACCUM_GREEN_BITS = $0D59;
-  GL_ACCUM_BLUE_BITS = $0D5A;
-  GL_ACCUM_ALPHA_BITS = $0D5B;
-  GL_NAME_STACK_DEPTH = $0D70;
-  GL_AUTO_NORMAL = $0D80;
-  GL_MAP1_COLOR_4 = $0D90;
-  GL_MAP1_INDEX = $0D91;
-  GL_MAP1_NORMAL = $0D92;
-  GL_MAP1_TEXTURE_COORD_1 = $0D93;
-  GL_MAP1_TEXTURE_COORD_2 = $0D94;
-  GL_MAP1_TEXTURE_COORD_3 = $0D95;
-  GL_MAP1_TEXTURE_COORD_4 = $0D96;
-  GL_MAP1_VERTEX_3 = $0D97;
-  GL_MAP1_VERTEX_4 = $0D98;
-  GL_MAP2_COLOR_4 = $0DB0;
-  GL_MAP2_INDEX = $0DB1;
-  GL_MAP2_NORMAL = $0DB2;
-  GL_MAP2_TEXTURE_COORD_1 = $0DB3;
-  GL_MAP2_TEXTURE_COORD_2 = $0DB4;
-  GL_MAP2_TEXTURE_COORD_3 = $0DB5;
-  GL_MAP2_TEXTURE_COORD_4 = $0DB6;
-  GL_MAP2_VERTEX_3 = $0DB7;
-  GL_MAP2_VERTEX_4 = $0DB8;
-  GL_MAP1_GRID_DOMAIN = $0DD0;
-  GL_MAP1_GRID_SEGMENTS = $0DD1;
-  GL_MAP2_GRID_DOMAIN = $0DD2;
-  GL_MAP2_GRID_SEGMENTS = $0DD3;
-  GL_FEEDBACK_BUFFER_POINTER = $0DF0;
-  GL_FEEDBACK_BUFFER_SIZE = $0DF1;
-  GL_FEEDBACK_BUFFER_TYPE = $0DF2;
-  GL_SELECTION_BUFFER_POINTER = $0DF3;
-  GL_SELECTION_BUFFER_SIZE = $0DF4;
-  GL_LIGHT0 = $4000;
-  GL_LIGHT1 = $4001;
-  GL_LIGHT2 = $4002;
-  GL_LIGHT3 = $4003;
-  GL_LIGHT4 = $4004;
-  GL_LIGHT5 = $4005;
-  GL_LIGHT6 = $4006;
-  GL_LIGHT7 = $4007;
-  GL_AMBIENT = $1200;
-  GL_DIFFUSE = $1201;
-  GL_SPECULAR = $1202;
-  GL_POSITION = $1203;
-  GL_SPOT_DIRECTION = $1204;
-  GL_SPOT_EXPONENT = $1205;
-  GL_SPOT_CUTOFF = $1206;
-  GL_CONSTANT_ATTENUATION = $1207;
-  GL_LINEAR_ATTENUATION = $1208;
-  GL_QUADRATIC_ATTENUATION = $1209;
-  GL_COMPILE = $1300;
-  GL_COMPILE_AND_EXECUTE = $1301;
-  GL_EMISSION = $1600;
-  GL_SHININESS = $1601;
-  GL_AMBIENT_AND_DIFFUSE = $1602;
-  GL_COLOR_INDEXES = $1603;
-  GL_MODELVIEW = $1700;
-  GL_PROJECTION = $1701;
-  GL_COLOR_INDEX = $1900;
-  GL_LUMINANCE = $1909;
-  GL_LUMINANCE_ALPHA = $190A;
-  GL_BITMAP = $1A00;
-  GL_RENDER = $1C00;
-  GL_FEEDBACK = $1C01;
-  GL_SELECT = $1C02;
-  GL_FLAT = $1D00;
-  GL_SMOOTH = $1D01;
-  GL_S = $2000;
-  GL_T = $2001;
-  GL_R = $2002;
-  GL_Q = $2003;
-  GL_MODULATE = $2100;
-  GL_DECAL = $2101;
-  GL_TEXTURE_ENV_MODE = $2200;
-  GL_TEXTURE_ENV_COLOR = $2201;
-  GL_TEXTURE_ENV = $2300;
-  GL_EYE_LINEAR = $2400;
-  GL_OBJECT_LINEAR = $2401;
-  GL_SPHERE_MAP = $2402;
-  GL_TEXTURE_GEN_MODE = $2500;
-  GL_OBJECT_PLANE = $2501;
-  GL_EYE_PLANE = $2502;
-  GL_CLAMP = $2900;
-  GL_CLIENT_PIXEL_STORE_BIT = $00000001;
-  GL_CLIENT_VERTEX_ARRAY_BIT = $00000002;
-  GL_CLIENT_ALL_ATTRIB_BITS = $FFFFFFFF;
-  GL_ALPHA4 = $803B;
-  GL_ALPHA8 = $803C;
-  GL_ALPHA12 = $803D;
-  GL_ALPHA16 = $803E;
-  GL_LUMINANCE4 = $803F;
-  GL_LUMINANCE8 = $8040;
-  GL_LUMINANCE12 = $8041;
-  GL_LUMINANCE16 = $8042;
-  GL_LUMINANCE4_ALPHA4 = $8043;
-  GL_LUMINANCE6_ALPHA2 = $8044;
-  GL_LUMINANCE8_ALPHA8 = $8045;
-  GL_LUMINANCE12_ALPHA4 = $8046;
-  GL_LUMINANCE12_ALPHA12 = $8047;
-  GL_LUMINANCE16_ALPHA16 = $8048;
-  GL_INTENSITY = $8049;
-  GL_INTENSITY4 = $804A;
-  GL_INTENSITY8 = $804B;
-  GL_INTENSITY12 = $804C;
-  GL_INTENSITY16 = $804D;
-  GL_TEXTURE_LUMINANCE_SIZE = $8060;
-  GL_TEXTURE_INTENSITY_SIZE = $8061;
-  GL_TEXTURE_PRIORITY = $8066;
-  GL_TEXTURE_RESIDENT = $8067;
-  GL_VERTEX_ARRAY = $8074;
-  GL_NORMAL_ARRAY = $8075;
-  GL_COLOR_ARRAY = $8076;
-  GL_INDEX_ARRAY = $8077;
-  GL_TEXTURE_COORD_ARRAY = $8078;
-  GL_EDGE_FLAG_ARRAY = $8079;
-  GL_VERTEX_ARRAY_SIZE = $807A;
-  GL_VERTEX_ARRAY_TYPE = $807B;
-  GL_VERTEX_ARRAY_STRIDE = $807C;
-  GL_NORMAL_ARRAY_TYPE = $807E;
-  GL_NORMAL_ARRAY_STRIDE = $807F;
-  GL_COLOR_ARRAY_SIZE = $8081;
-  GL_COLOR_ARRAY_TYPE = $8082;
-  GL_COLOR_ARRAY_STRIDE = $8083;
-  GL_INDEX_ARRAY_TYPE = $8085;
-  GL_INDEX_ARRAY_STRIDE = $8086;
-  GL_TEXTURE_COORD_ARRAY_SIZE = $8088;
-  GL_TEXTURE_COORD_ARRAY_TYPE = $8089;
-  GL_TEXTURE_COORD_ARRAY_STRIDE = $808A;
-  GL_EDGE_FLAG_ARRAY_STRIDE = $808C;
-  GL_VERTEX_ARRAY_POINTER = $808E;
-  GL_NORMAL_ARRAY_POINTER = $808F;
-  GL_COLOR_ARRAY_POINTER = $8090;
-  GL_INDEX_ARRAY_POINTER = $8091;
-  GL_TEXTURE_COORD_ARRAY_POINTER = $8092;
-  GL_EDGE_FLAG_ARRAY_POINTER = $8093;
-  GL_V2F = $2A20;
-  GL_V3F = $2A21;
-  GL_C4UB_V2F = $2A22;
-  GL_C4UB_V3F = $2A23;
-  GL_C3F_V3F = $2A24;
-  GL_N3F_V3F = $2A25;
-  GL_C4F_N3F_V3F = $2A26;
-  GL_T2F_V3F = $2A27;
-  GL_T4F_V4F = $2A28;
-  GL_T2F_C4UB_V3F = $2A29;
-  GL_T2F_C3F_V3F = $2A2A;
-  GL_T2F_N3F_V3F = $2A2B;
-  GL_T2F_C4F_N3F_V3F = $2A2C;
-  GL_T4F_C4F_N3F_V4F = $2A2D;
-  GL_COLOR_TABLE_FORMAT_EXT = $80D8;
-  GL_COLOR_TABLE_WIDTH_EXT = $80D9;
-  GL_COLOR_TABLE_RED_SIZE_EXT = $80DA;
-  GL_COLOR_TABLE_GREEN_SIZE_EXT = $80DB;
-  GL_COLOR_TABLE_BLUE_SIZE_EXT = $80DC;
-  GL_COLOR_TABLE_ALPHA_SIZE_EXT = $80DD;
-  GL_COLOR_TABLE_LUMINANCE_SIZE_EXT = $80DE;
-  GL_COLOR_TABLE_INTENSITY_SIZE_EXT = $80DF;
-  GL_LOGIC_OP = GL_INDEX_LOGIC_OP;
-  GL_TEXTURE_COMPONENTS = GL_TEXTURE_INTERNAL_FORMAT;
-{$endif}
-
-  // GL_VERSION_1_2
-  GL_UNSIGNED_BYTE_3_3_2 = $8032;
-  GL_UNSIGNED_SHORT_4_4_4_4 = $8033;
-  GL_UNSIGNED_SHORT_5_5_5_1 = $8034;
-  GL_UNSIGNED_INT_8_8_8_8 = $8035;
-  GL_UNSIGNED_INT_10_10_10_2 = $8036;
-  GL_TEXTURE_BINDING_3D = $806A;
-  GL_PACK_SKIP_IMAGES = $806B;
-  GL_PACK_IMAGE_HEIGHT = $806C;
-  GL_UNPACK_SKIP_IMAGES = $806D;
-  GL_UNPACK_IMAGE_HEIGHT = $806E;
-  GL_TEXTURE_3D = $806F;
-  GL_PROXY_TEXTURE_3D = $8070;
-  GL_TEXTURE_DEPTH = $8071;
-  GL_TEXTURE_WRAP_R = $8072;
-  GL_MAX_3D_TEXTURE_SIZE = $8073;
-  GL_UNSIGNED_BYTE_2_3_3_REV = $8362;
-  GL_UNSIGNED_SHORT_5_6_5 = $8363;
-  GL_UNSIGNED_SHORT_5_6_5_REV = $8364;
-  GL_UNSIGNED_SHORT_4_4_4_4_REV = $8365;
-  GL_UNSIGNED_SHORT_1_5_5_5_REV = $8366;
-  GL_UNSIGNED_INT_8_8_8_8_REV = $8367;
-  GL_UNSIGNED_INT_2_10_10_10_REV = $8368;
-  GL_BGR = $80E0;
-  GL_BGRA = $80E1;
-  GL_MAX_ELEMENTS_VERTICES = $80E8;
-  GL_MAX_ELEMENTS_INDICES = $80E9;
-  GL_CLAMP_TO_EDGE = $812F;
-  GL_TEXTURE_MIN_LOD = $813A;
-  GL_TEXTURE_MAX_LOD = $813B;
-  GL_TEXTURE_BASE_LEVEL = $813C;
-  GL_TEXTURE_MAX_LEVEL = $813D;
-  GL_SMOOTH_POINT_SIZE_RANGE = $0B12;
-  GL_SMOOTH_POINT_SIZE_GRANULARITY = $0B13;
-  GL_SMOOTH_LINE_WIDTH_RANGE = $0B22;
-  GL_SMOOTH_LINE_WIDTH_GRANULARITY = $0B23;
-  GL_ALIASED_LINE_WIDTH_RANGE = $846E;
-{$ifdef DGL_DEPRECATED}
-  GL_RESCALE_NORMAL = $803A;
-  GL_LIGHT_MODEL_COLOR_CONTROL = $81F8;
-  GL_SINGLE_COLOR = $81F9;
-  GL_SEPARATE_SPECULAR_COLOR = $81FA;
-  GL_ALIASED_POINT_SIZE_RANGE = $846D;
-{$endif}
-
-  // GL_VERSION_1_3
-  GL_TEXTURE0 = $84C0;
-  GL_TEXTURE1 = $84C1;
-  GL_TEXTURE2 = $84C2;
-  GL_TEXTURE3 = $84C3;
-  GL_TEXTURE4 = $84C4;
-  GL_TEXTURE5 = $84C5;
-  GL_TEXTURE6 = $84C6;
-  GL_TEXTURE7 = $84C7;
-  GL_TEXTURE8 = $84C8;
-  GL_TEXTURE9 = $84C9;
-  GL_TEXTURE10 = $84CA;
-  GL_TEXTURE11 = $84CB;
-  GL_TEXTURE12 = $84CC;
-  GL_TEXTURE13 = $84CD;
-  GL_TEXTURE14 = $84CE;
-  GL_TEXTURE15 = $84CF;
-  GL_TEXTURE16 = $84D0;
-  GL_TEXTURE17 = $84D1;
-  GL_TEXTURE18 = $84D2;
-  GL_TEXTURE19 = $84D3;
-  GL_TEXTURE20 = $84D4;
-  GL_TEXTURE21 = $84D5;
-  GL_TEXTURE22 = $84D6;
-  GL_TEXTURE23 = $84D7;
-  GL_TEXTURE24 = $84D8;
-  GL_TEXTURE25 = $84D9;
-  GL_TEXTURE26 = $84DA;
-  GL_TEXTURE27 = $84DB;
-  GL_TEXTURE28 = $84DC;
-  GL_TEXTURE29 = $84DD;
-  GL_TEXTURE30 = $84DE;
-  GL_TEXTURE31 = $84DF;
-  GL_ACTIVE_TEXTURE = $84E0;
-  GL_MULTISAMPLE = $809D;
-  GL_SAMPLE_ALPHA_TO_COVERAGE = $809E;
-  GL_SAMPLE_ALPHA_TO_ONE = $809F;
-  GL_SAMPLE_COVERAGE = $80A0;
-  GL_SAMPLE_BUFFERS = $80A8;
-  GL_SAMPLES = $80A9;
-  GL_SAMPLE_COVERAGE_VALUE = $80AA;
-  GL_SAMPLE_COVERAGE_INVERT = $80AB;
-  GL_TEXTURE_CUBE_MAP = $8513;
-  GL_TEXTURE_BINDING_CUBE_MAP = $8514;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_X = $8515;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_X = $8516;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Y = $8517;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = $8518;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Z = $8519;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = $851A;
-  GL_PROXY_TEXTURE_CUBE_MAP = $851B;
-  GL_MAX_CUBE_MAP_TEXTURE_SIZE = $851C;
-  GL_COMPRESSED_RGB = $84ED;
-  GL_COMPRESSED_RGBA = $84EE;
-  GL_TEXTURE_COMPRESSION_HINT = $84EF;
-  GL_TEXTURE_COMPRESSED_IMAGE_SIZE = $86A0;
-  GL_TEXTURE_COMPRESSED = $86A1;
-  GL_NUM_COMPRESSED_TEXTURE_FORMATS = $86A2;
-  GL_COMPRESSED_TEXTURE_FORMATS = $86A3;
-  GL_CLAMP_TO_BORDER = $812D;
-{$ifdef DGL_DEPRECATED}
-  GL_CLIENT_ACTIVE_TEXTURE = $84E1;
-  GL_MAX_TEXTURE_UNITS = $84E2;
-  GL_TRANSPOSE_MODELVIEW_MATRIX = $84E3;
-  GL_TRANSPOSE_PROJECTION_MATRIX = $84E4;
-  GL_TRANSPOSE_TEXTURE_MATRIX = $84E5;
-  GL_TRANSPOSE_COLOR_MATRIX = $84E6;
-  GL_MULTISAMPLE_BIT = $20000000;
-  GL_NORMAL_MAP = $8511;
-  GL_REFLECTION_MAP = $8512;
-  GL_COMPRESSED_ALPHA = $84E9;
-  GL_COMPRESSED_LUMINANCE = $84EA;
-  GL_COMPRESSED_LUMINANCE_ALPHA = $84EB;
-  GL_COMPRESSED_INTENSITY = $84EC;
-  GL_COMBINE = $8570;
-  GL_COMBINE_RGB = $8571;
-  GL_COMBINE_ALPHA = $8572;
-  GL_SOURCE0_RGB = $8580;
-  GL_SOURCE1_RGB = $8581;
-  GL_SOURCE2_RGB = $8582;
-  GL_SOURCE0_ALPHA = $8588;
-  GL_SOURCE1_ALPHA = $8589;
-  GL_SOURCE2_ALPHA = $858A;
-  GL_OPERAND0_RGB = $8590;
-  GL_OPERAND1_RGB = $8591;
-  GL_OPERAND2_RGB = $8592;
-  GL_OPERAND0_ALPHA = $8598;
-  GL_OPERAND1_ALPHA = $8599;
-  GL_OPERAND2_ALPHA = $859A;
-  GL_RGB_SCALE = $8573;
-  GL_ADD_SIGNED = $8574;
-  GL_INTERPOLATE = $8575;
-  GL_SUBTRACT = $84E7;
-  GL_CONSTANT = $8576;
-  GL_PRIMARY_COLOR = $8577;
-  GL_PREVIOUS = $8578;
-  GL_DOT3_RGB = $86AE;
-  GL_DOT3_RGBA = $86AF;
-{$endif}
-
-  // GL_VERSION_1_4
-  GL_BLEND_DST_RGB = $80C8;
-  GL_BLEND_SRC_RGB = $80C9;
-  GL_BLEND_DST_ALPHA = $80CA;
-  GL_BLEND_SRC_ALPHA = $80CB;
-  GL_POINT_FADE_THRESHOLD_SIZE = $8128;
-  GL_DEPTH_COMPONENT16 = $81A5;
-  GL_DEPTH_COMPONENT24 = $81A6;
-  GL_DEPTH_COMPONENT32 = $81A7;
-  GL_MIRRORED_REPEAT = $8370;
-  GL_MAX_TEXTURE_LOD_BIAS = $84FD;
-  GL_TEXTURE_LOD_BIAS = $8501;
-  GL_INCR_WRAP = $8507;
-  GL_DECR_WRAP = $8508;
-  GL_TEXTURE_DEPTH_SIZE = $884A;
-  GL_TEXTURE_COMPARE_MODE = $884C;
-  GL_TEXTURE_COMPARE_FUNC = $884D;
-{$ifdef DGL_DEPRECATED}
-  GL_POINT_SIZE_MIN = $8126;
-  GL_POINT_SIZE_MAX = $8127;
-  GL_POINT_DISTANCE_ATTENUATION = $8129;
-  GL_GENERATE_MIPMAP = $8191;
-  GL_GENERATE_MIPMAP_HINT = $8192;
-  GL_FOG_COORDINATE_SOURCE = $8450;
-  GL_FOG_COORDINATE = $8451;
-  GL_FRAGMENT_DEPTH = $8452;
-  GL_CURRENT_FOG_COORDINATE = $8453;
-  GL_FOG_COORDINATE_ARRAY_TYPE = $8454;
-  GL_FOG_COORDINATE_ARRAY_STRIDE = $8455;
-  GL_FOG_COORDINATE_ARRAY_POINTER = $8456;
-  GL_FOG_COORDINATE_ARRAY = $8457;
-  GL_COLOR_SUM = $8458;
-  GL_CURRENT_SECONDARY_COLOR = $8459;
-  GL_SECONDARY_COLOR_ARRAY_SIZE = $845A;
-  GL_SECONDARY_COLOR_ARRAY_TYPE = $845B;
-  GL_SECONDARY_COLOR_ARRAY_STRIDE = $845C;
-  GL_SECONDARY_COLOR_ARRAY_POINTER = $845D;
-  GL_SECONDARY_COLOR_ARRAY = $845E;
-  GL_TEXTURE_FILTER_CONTROL = $8500;
-  GL_DEPTH_TEXTURE_MODE = $884B;
-  GL_COMPARE_R_TO_TEXTURE = $884E;
-{$endif}
-
-  // GL_VERSION_1_5
-  GL_BUFFER_SIZE = $8764;
-  GL_BUFFER_USAGE = $8765;
-  GL_QUERY_COUNTER_BITS = $8864;
-  GL_CURRENT_QUERY = $8865;
-  GL_QUERY_RESULT = $8866;
-  GL_QUERY_RESULT_AVAILABLE = $8867;
-  GL_ARRAY_BUFFER = $8892;
-  GL_ELEMENT_ARRAY_BUFFER = $8893;
-  GL_ARRAY_BUFFER_BINDING = $8894;
-  GL_ELEMENT_ARRAY_BUFFER_BINDING = $8895;
-  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = $889F;
-  GL_READ_ONLY = $88B8;
-  GL_WRITE_ONLY = $88B9;
-  GL_READ_WRITE = $88BA;
-  GL_BUFFER_ACCESS = $88BB;
-  GL_BUFFER_MAPPED = $88BC;
-  GL_BUFFER_MAP_POINTER = $88BD;
-  GL_STREAM_DRAW = $88E0;
-  GL_STREAM_READ = $88E1;
-  GL_STREAM_COPY = $88E2;
-  GL_STATIC_DRAW = $88E4;
-  GL_STATIC_READ = $88E5;
-  GL_STATIC_COPY = $88E6;
-  GL_DYNAMIC_DRAW = $88E8;
-  GL_DYNAMIC_READ = $88E9;
-  GL_DYNAMIC_COPY = $88EA;
-  GL_SAMPLES_PASSED = $8914;
-{$ifdef DGL_DEPRECATED}
-  GL_VERTEX_ARRAY_BUFFER_BINDING = $8896;
-  GL_NORMAL_ARRAY_BUFFER_BINDING = $8897;
-  GL_COLOR_ARRAY_BUFFER_BINDING = $8898;
-  GL_INDEX_ARRAY_BUFFER_BINDING = $8899;
-  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = $889A;
-  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING = $889B;
-  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING = $889C;
-  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING = $889D;
-  GL_WEIGHT_ARRAY_BUFFER_BINDING = $889E;
-  GL_FOG_COORD_SRC = $8450;
-  GL_FOG_COORD = $8451;
-  GL_CURRENT_FOG_COORD = $8453;
-  GL_FOG_COORD_ARRAY_TYPE = $8454;
-  GL_FOG_COORD_ARRAY_STRIDE = $8455;
-  GL_FOG_COORD_ARRAY_POINTER = $8456;
-  GL_FOG_COORD_ARRAY = $8457;
-  GL_FOG_COORD_ARRAY_BUFFER_BINDING = $889D;
-  GL_SRC0_RGB = $8580;
-  GL_SRC1_RGB = $8581;
-  GL_SRC2_RGB = $8582;
-  GL_SRC0_ALPHA = $8588;
-  GL_SRC1_ALPHA = $8589;
-  GL_SRC2_ALPHA = $858A;
-{$endif}
-
-  // GL_VERSION_2_0
-  GL_BLEND_EQUATION_RGB = $8009;
-  GL_VERTEX_ATTRIB_ARRAY_ENABLED = $8622;
-  GL_VERTEX_ATTRIB_ARRAY_SIZE = $8623;
-  GL_VERTEX_ATTRIB_ARRAY_STRIDE = $8624;
-  GL_VERTEX_ATTRIB_ARRAY_TYPE = $8625;
-  GL_CURRENT_VERTEX_ATTRIB = $8626;
-  GL_VERTEX_PROGRAM_POINT_SIZE = $8642;
-  GL_VERTEX_ATTRIB_ARRAY_POINTER = $8645;
-  GL_STENCIL_BACK_FUNC = $8800;
-  GL_STENCIL_BACK_FAIL = $8801;
-  GL_STENCIL_BACK_PASS_DEPTH_FAIL = $8802;
-  GL_STENCIL_BACK_PASS_DEPTH_PASS = $8803;
-  GL_MAX_DRAW_BUFFERS = $8824;
-  GL_DRAW_BUFFER0 = $8825;
-  GL_DRAW_BUFFER1 = $8826;
-  GL_DRAW_BUFFER2 = $8827;
-  GL_DRAW_BUFFER3 = $8828;
-  GL_DRAW_BUFFER4 = $8829;
-  GL_DRAW_BUFFER5 = $882A;
-  GL_DRAW_BUFFER6 = $882B;
-  GL_DRAW_BUFFER7 = $882C;
-  GL_DRAW_BUFFER8 = $882D;
-  GL_DRAW_BUFFER9 = $882E;
-  GL_DRAW_BUFFER10 = $882F;
-  GL_DRAW_BUFFER11 = $8830;
-  GL_DRAW_BUFFER12 = $8831;
-  GL_DRAW_BUFFER13 = $8832;
-  GL_DRAW_BUFFER14 = $8833;
-  GL_DRAW_BUFFER15 = $8834;
-  GL_BLEND_EQUATION_ALPHA = $883D;
-  GL_MAX_VERTEX_ATTRIBS = $8869;
-  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED = $886A;
-  GL_MAX_TEXTURE_IMAGE_UNITS = $8872;
-  GL_FRAGMENT_SHADER = $8B30;
-  GL_VERTEX_SHADER = $8B31;
-  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = $8B49;
-  GL_MAX_VERTEX_UNIFORM_COMPONENTS = $8B4A;
-  GL_MAX_VARYING_FLOATS = $8B4B;
-  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = $8B4C;
-  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = $8B4D;
-  GL_SHADER_TYPE = $8B4F;
-  GL_FLOAT_VEC2 = $8B50;
-  GL_FLOAT_VEC3 = $8B51;
-  GL_FLOAT_VEC4 = $8B52;
-  GL_INT_VEC2 = $8B53;
-  GL_INT_VEC3 = $8B54;
-  GL_INT_VEC4 = $8B55;
-  GL_BOOL = $8B56;
-  GL_BOOL_VEC2 = $8B57;
-  GL_BOOL_VEC3 = $8B58;
-  GL_BOOL_VEC4 = $8B59;
-  GL_FLOAT_MAT2 = $8B5A;
-  GL_FLOAT_MAT3 = $8B5B;
-  GL_FLOAT_MAT4 = $8B5C;
-  GL_SAMPLER_1D = $8B5D;
-  GL_SAMPLER_2D = $8B5E;
-  GL_SAMPLER_3D = $8B5F;
-  GL_SAMPLER_CUBE = $8B60;
-  GL_SAMPLER_1D_SHADOW = $8B61;
-  GL_SAMPLER_2D_SHADOW = $8B62;
-  GL_DELETE_STATUS = $8B80;
-  GL_COMPILE_STATUS = $8B81;
-  GL_LINK_STATUS = $8B82;
-  GL_VALIDATE_STATUS = $8B83;
-  GL_INFO_LOG_LENGTH = $8B84;
-  GL_ATTACHED_SHADERS = $8B85;
-  GL_ACTIVE_UNIFORMS = $8B86;
-  GL_ACTIVE_UNIFORM_MAX_LENGTH = $8B87;
-  GL_SHADER_SOURCE_LENGTH = $8B88;
-  GL_ACTIVE_ATTRIBUTES = $8B89;
-  GL_ACTIVE_ATTRIBUTE_MAX_LENGTH = $8B8A;
-  GL_FRAGMENT_SHADER_DERIVATIVE_HINT = $8B8B;
-  GL_SHADING_LANGUAGE_VERSION = $8B8C;
-  GL_CURRENT_PROGRAM = $8B8D;
-  GL_POINT_SPRITE_COORD_ORIGIN = $8CA0;
-  GL_LOWER_LEFT = $8CA1;
-  GL_UPPER_LEFT = $8CA2;
-  GL_STENCIL_BACK_REF = $8CA3;
-  GL_STENCIL_BACK_VALUE_MASK = $8CA4;
-  GL_STENCIL_BACK_WRITEMASK = $8CA5;
-{$ifdef DGL_DEPRECATED}
-  GL_VERTEX_PROGRAM_TWO_SIDE = $8643;
-  GL_POINT_SPRITE = $8861;
-  GL_COORD_REPLACE = $8862;
-  GL_MAX_TEXTURE_COORDS = $8871;
-{$endif}
-
-  // GL_VERSION_2_1
-  GL_PIXEL_PACK_BUFFER = $88EB;
-  GL_PIXEL_UNPACK_BUFFER = $88EC;
-  GL_PIXEL_PACK_BUFFER_BINDING = $88ED;
-  GL_PIXEL_UNPACK_BUFFER_BINDING = $88EF;
-  GL_FLOAT_MAT2x3 = $8B65;
-  GL_FLOAT_MAT2x4 = $8B66;
-  GL_FLOAT_MAT3x2 = $8B67;
-  GL_FLOAT_MAT3x4 = $8B68;
-  GL_FLOAT_MAT4x2 = $8B69;
-  GL_FLOAT_MAT4x3 = $8B6A;
-  GL_SRGB = $8C40;
-  GL_SRGB8 = $8C41;
-  GL_SRGB_ALPHA = $8C42;
-  GL_SRGB8_ALPHA8 = $8C43;
-  GL_COMPRESSED_SRGB = $8C48;
-  GL_COMPRESSED_SRGB_ALPHA = $8C49;
-{$ifdef DGL_DEPRECATED}
-  GL_CURRENT_RASTER_SECONDARY_COLOR = $845F;
-  GL_SLUMINANCE_ALPHA = $8C44;
-  GL_SLUMINANCE8_ALPHA8 = $8C45;
-  GL_SLUMINANCE = $8C46;
-  GL_SLUMINANCE8 = $8C47;
-  GL_COMPRESSED_SLUMINANCE = $8C4A;
-  GL_COMPRESSED_SLUMINANCE_ALPHA = $8C4B;
-{$endif}
-
-  // GL_VERSION_3_0
-  GL_COMPARE_REF_TO_TEXTURE = $884E;
-  GL_CLIP_DISTANCE0 = $3000;
-  GL_CLIP_DISTANCE1 = $3001;
-  GL_CLIP_DISTANCE2 = $3002;
-  GL_CLIP_DISTANCE3 = $3003;
-  GL_CLIP_DISTANCE4 = $3004;
-  GL_CLIP_DISTANCE5 = $3005;
-  GL_CLIP_DISTANCE6 = $3006;
-  GL_CLIP_DISTANCE7 = $3007;
-  GL_MAX_CLIP_DISTANCES = $0D32;
-  GL_MAJOR_VERSION = $821B;
-  GL_MINOR_VERSION = $821C;
-  GL_NUM_EXTENSIONS = $821D;
-  GL_CONTEXT_FLAGS = $821E;
-  GL_DEPTH_BUFFER = $8223;
-  GL_STENCIL_BUFFER = $8224;
-  GL_COMPRESSED_RED = $8225;
-  GL_COMPRESSED_RG = $8226;
-  GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = $0001;
-  GL_RGBA32F = $8814;
-  GL_RGB32F = $8815;
-  GL_RGBA16F = $881A;
-  GL_RGB16F = $881B;
-  GL_VERTEX_ATTRIB_ARRAY_INTEGER = $88FD;
-  GL_MAX_ARRAY_TEXTURE_LAYERS = $88FF;
-  GL_MIN_PROGRAM_TEXEL_OFFSET = $8904;
-  GL_MAX_PROGRAM_TEXEL_OFFSET = $8905;
-  GL_CLAMP_READ_COLOR = $891C;
-  GL_FIXED_ONLY = $891D;
-  GL_MAX_VARYING_COMPONENTS = $8B4B;
-  GL_TEXTURE_1D_ARRAY = $8C18;
-  GL_PROXY_TEXTURE_1D_ARRAY = $8C19;
-  GL_TEXTURE_2D_ARRAY = $8C1A;
-  GL_PROXY_TEXTURE_2D_ARRAY = $8C1B;
-  GL_TEXTURE_BINDING_1D_ARRAY = $8C1C;
-  GL_TEXTURE_BINDING_2D_ARRAY = $8C1D;
-  GL_R11F_G11F_B10F = $8C3A;
-  GL_UNSIGNED_INT_10F_11F_11F_REV = $8C3B;
-  GL_RGB9_E5 = $8C3D;
-  GL_UNSIGNED_INT_5_9_9_9_REV = $8C3E;
-  GL_TEXTURE_SHARED_SIZE = $8C3F;
-  GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH = $8C76;
-  GL_TRANSFORM_FEEDBACK_BUFFER_MODE = $8C7F;
-  GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = $8C80;
-  GL_TRANSFORM_FEEDBACK_VARYINGS = $8C83;
-  GL_TRANSFORM_FEEDBACK_BUFFER_START = $8C84;
-  GL_TRANSFORM_FEEDBACK_BUFFER_SIZE = $8C85;
-  GL_PRIMITIVES_GENERATED = $8C87;
-  GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = $8C88;
-  GL_RASTERIZER_DISCARD = $8C89;
-  GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = $8C8A;
-  GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = $8C8B;
-  GL_INTERLEAVED_ATTRIBS = $8C8C;
-  GL_SEPARATE_ATTRIBS = $8C8D;
-  GL_TRANSFORM_FEEDBACK_BUFFER = $8C8E;
-  GL_TRANSFORM_FEEDBACK_BUFFER_BINDING = $8C8F;
-  GL_RGBA32UI = $8D70;
-  GL_RGB32UI = $8D71;
-  GL_RGBA16UI = $8D76;
-  GL_RGB16UI = $8D77;
-  GL_RGBA8UI = $8D7C;
-  GL_RGB8UI = $8D7D;
-  GL_RGBA32I = $8D82;
-  GL_RGB32I = $8D83;
-  GL_RGBA16I = $8D88;
-  GL_RGB16I = $8D89;
-  GL_RGBA8I = $8D8E;
-  GL_RGB8I = $8D8F;
-  GL_RED_INTEGER = $8D94;
-  GL_GREEN_INTEGER = $8D95;
-  GL_BLUE_INTEGER = $8D96;
-  GL_RGB_INTEGER = $8D98;
-  GL_RGBA_INTEGER = $8D99;
-  GL_BGR_INTEGER = $8D9A;
-  GL_BGRA_INTEGER = $8D9B;
-  GL_SAMPLER_1D_ARRAY = $8DC0;
-  GL_SAMPLER_2D_ARRAY = $8DC1;
-  GL_SAMPLER_1D_ARRAY_SHADOW = $8DC3;
-  GL_SAMPLER_2D_ARRAY_SHADOW = $8DC4;
-  GL_SAMPLER_CUBE_SHADOW = $8DC5;
-  GL_UNSIGNED_INT_VEC2 = $8DC6;
-  GL_UNSIGNED_INT_VEC3 = $8DC7;
-  GL_UNSIGNED_INT_VEC4 = $8DC8;
-  GL_INT_SAMPLER_1D = $8DC9;
-  GL_INT_SAMPLER_2D = $8DCA;
-  GL_INT_SAMPLER_3D = $8DCB;
-  GL_INT_SAMPLER_CUBE = $8DCC;
-  GL_INT_SAMPLER_1D_ARRAY = $8DCE;
-  GL_INT_SAMPLER_2D_ARRAY = $8DCF;
-  GL_UNSIGNED_INT_SAMPLER_1D = $8DD1;
-  GL_UNSIGNED_INT_SAMPLER_2D = $8DD2;
-  GL_UNSIGNED_INT_SAMPLER_3D = $8DD3;
-  GL_UNSIGNED_INT_SAMPLER_CUBE = $8DD4;
-  GL_UNSIGNED_INT_SAMPLER_1D_ARRAY = $8DD6;
-  GL_UNSIGNED_INT_SAMPLER_2D_ARRAY = $8DD7;
-  GL_QUERY_WAIT = $8E13;
-  GL_QUERY_NO_WAIT = $8E14;
-  GL_QUERY_BY_REGION_WAIT = $8E15;
-  GL_QUERY_BY_REGION_NO_WAIT = $8E16;
-  GL_BUFFER_ACCESS_FLAGS = $911F;
-  GL_BUFFER_MAP_LENGTH = $9120;
-  GL_BUFFER_MAP_OFFSET = $9121;
-  { Reuse tokens from ARB_depth_buffer_float }
-  { reuse GL_DEPTH_COMPONENT32F }
-  { reuse GL_DEPTH32F_STENCIL8 }
-  { reuse GL_FLOAT_32_UNSIGNED_INT_24_8_REV }
-  { Reuse tokens from ARB_framebuffer_object }
-  { reuse GL_INVALID_FRAMEBUFFER_OPERATION }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE }
-  { reuse GL_FRAMEBUFFER_DEFAULT }
-  { reuse GL_FRAMEBUFFER_UNDEFINED }
-  { reuse GL_DEPTH_STENCIL_ATTACHMENT }
-  { reuse GL_INDEX }
-  { reuse GL_MAX_RENDERBUFFER_SIZE }
-  { reuse GL_DEPTH_STENCIL }
-  { reuse GL_UNSIGNED_INT_24_8 }
-  { reuse GL_DEPTH24_STENCIL8 }
-  { reuse GL_TEXTURE_STENCIL_SIZE }
-  { reuse GL_TEXTURE_RED_TYPE }
-  { reuse GL_TEXTURE_GREEN_TYPE }
-  { reuse GL_TEXTURE_BLUE_TYPE }
-  { reuse GL_TEXTURE_ALPHA_TYPE }
-  { reuse GL_TEXTURE_DEPTH_TYPE }
-  { reuse GL_UNSIGNED_NORMALIZED }
-  { reuse GL_FRAMEBUFFER_BINDING }
-  { reuse GL_DRAW_FRAMEBUFFER_BINDING }
-  { reuse GL_RENDERBUFFER_BINDING }
-  { reuse GL_READ_FRAMEBUFFER }
-  { reuse GL_DRAW_FRAMEBUFFER }
-  { reuse GL_READ_FRAMEBUFFER_BINDING }
-  { reuse GL_RENDERBUFFER_SAMPLES }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER }
-  { reuse GL_FRAMEBUFFER_COMPLETE }
-  { reuse GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT }
-  { reuse GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT }
-  { reuse GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER }
-  { reuse GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER }
-  { reuse GL_FRAMEBUFFER_UNSUPPORTED }
-  { reuse GL_MAX_COLOR_ATTACHMENTS }
-  { reuse GL_COLOR_ATTACHMENT0 }
-  { reuse GL_COLOR_ATTACHMENT1 }
-  { reuse GL_COLOR_ATTACHMENT2 }
-  { reuse GL_COLOR_ATTACHMENT3 }
-  { reuse GL_COLOR_ATTACHMENT4 }
-  { reuse GL_COLOR_ATTACHMENT5 }
-  { reuse GL_COLOR_ATTACHMENT6 }
-  { reuse GL_COLOR_ATTACHMENT7 }
-  { reuse GL_COLOR_ATTACHMENT8 }
-  { reuse GL_COLOR_ATTACHMENT9 }
-  { reuse GL_COLOR_ATTACHMENT10 }
-  { reuse GL_COLOR_ATTACHMENT11 }
-  { reuse GL_COLOR_ATTACHMENT12 }
-  { reuse GL_COLOR_ATTACHMENT13 }
-  { reuse GL_COLOR_ATTACHMENT14 }
-  { reuse GL_COLOR_ATTACHMENT15 }
-  { reuse GL_DEPTH_ATTACHMENT }
-  { reuse GL_STENCIL_ATTACHMENT }
-  { reuse GL_FRAMEBUFFER }
-  { reuse GL_RENDERBUFFER }
-  { reuse GL_RENDERBUFFER_WIDTH }
-  { reuse GL_RENDERBUFFER_HEIGHT }
-  { reuse GL_RENDERBUFFER_INTERNAL_FORMAT }
-  { reuse GL_STENCIL_INDEX1 }
-  { reuse GL_STENCIL_INDEX4 }
-  { reuse GL_STENCIL_INDEX8 }
-  { reuse GL_STENCIL_INDEX16 }
-  { reuse GL_RENDERBUFFER_RED_SIZE }
-  { reuse GL_RENDERBUFFER_GREEN_SIZE }
-  { reuse GL_RENDERBUFFER_BLUE_SIZE }
-  { reuse GL_RENDERBUFFER_ALPHA_SIZE }
-  { reuse GL_RENDERBUFFER_DEPTH_SIZE }
-  { reuse GL_RENDERBUFFER_STENCIL_SIZE }
-  { reuse GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE }
-  { reuse GL_MAX_SAMPLES }
-  { Reuse tokens from ARB_framebuffer_sRGB }
-  { reuse GL_FRAMEBUFFER_SRGB }
-  { Reuse tokens from ARB_half_float_vertex }
-  { reuse GL_HALF_FLOAT }
-  { Reuse tokens from ARB_map_buffer_range }
-  { reuse GL_MAP_READ_BIT }
-  { reuse GL_MAP_WRITE_BIT }
-  { reuse GL_MAP_INVALIDATE_RANGE_BIT }
-  { reuse GL_MAP_INVALIDATE_BUFFER_BIT }
-  { reuse GL_MAP_FLUSH_EXPLICIT_BIT }
-  { reuse GL_MAP_UNSYNCHRONIZED_BIT }
-  { Reuse tokens from ARB_texture_compression_rgtc }
-  { reuse GL_COMPRESSED_RED_RGTC1 }
-  { reuse GL_COMPRESSED_SIGNED_RED_RGTC1 }
-  { reuse GL_COMPRESSED_RG_RGTC2 }
-  { reuse GL_COMPRESSED_SIGNED_RG_RGTC2 }
-  { Reuse tokens from ARB_texture_rg }
-  { reuse GL_RG }
-  { reuse GL_RG_INTEGER }
-  { reuse GL_R8 }
-  { reuse GL_R16 }
-  { reuse GL_RG8 }
-  { reuse GL_RG16 }
-  { reuse GL_R16F }
-  { reuse GL_R32F }
-  { reuse GL_RG16F }
-  { reuse GL_RG32F }
-  { reuse GL_R8I }
-  { reuse GL_R8UI }
-  { reuse GL_R16I }
-  { reuse GL_R16UI }
-  { reuse GL_R32I }
-  { reuse GL_R32UI }
-  { reuse GL_RG8I }
-  { reuse GL_RG8UI }
-  { reuse GL_RG16I }
-  { reuse GL_RG16UI }
-  { reuse GL_RG32I }
-  { reuse GL_RG32UI }
-  { Reuse tokens from ARB_vertex_array_object }
-  { reuse GL_VERTEX_ARRAY_BINDING }
-{$ifdef DGL_DEPRECATED}
-  GL_CLAMP_VERTEX_COLOR = $891A;
-  GL_CLAMP_FRAGMENT_COLOR = $891B;
-  GL_ALPHA_INTEGER = $8D97;
-  { Reuse tokens from ARB_framebuffer_object }
-  { reuse GL_TEXTURE_LUMINANCE_TYPE }
-  { reuse GL_TEXTURE_INTENSITY_TYPE }
-{$endif}
-
-  // GL_VERSION_3_1
-  GL_SAMPLER_2D_RECT = $8B63;
-  GL_SAMPLER_2D_RECT_SHADOW = $8B64;
-  GL_SAMPLER_BUFFER = $8DC2;
-  GL_INT_SAMPLER_2D_RECT = $8DCD;
-  GL_INT_SAMPLER_BUFFER = $8DD0;
-  GL_UNSIGNED_INT_SAMPLER_2D_RECT = $8DD5;
-  GL_UNSIGNED_INT_SAMPLER_BUFFER = $8DD8;
-  GL_TEXTURE_BUFFER = $8C2A;
-  GL_MAX_TEXTURE_BUFFER_SIZE = $8C2B;
-  GL_TEXTURE_BINDING_BUFFER = $8C2C;
-  GL_TEXTURE_BUFFER_DATA_STORE_BINDING = $8C2D;
-  GL_TEXTURE_BUFFER_FORMAT = $8C2E;
-  GL_TEXTURE_RECTANGLE = $84F5;
-  GL_TEXTURE_BINDING_RECTANGLE = $84F6;
-  GL_PROXY_TEXTURE_RECTANGLE = $84F7;
-  GL_MAX_RECTANGLE_TEXTURE_SIZE = $84F8;
-  GL_RED_SNORM = $8F90;
-  GL_RG_SNORM = $8F91;
-  GL_RGB_SNORM = $8F92;
-  GL_RGBA_SNORM = $8F93;
-  GL_R8_SNORM = $8F94;
-  GL_RG8_SNORM = $8F95;
-  GL_RGB8_SNORM = $8F96;
-  GL_RGBA8_SNORM = $8F97;
-  GL_R16_SNORM = $8F98;
-  GL_RG16_SNORM = $8F99;
-  GL_RGB16_SNORM = $8F9A;
-  GL_RGBA16_SNORM = $8F9B;
-  GL_SIGNED_NORMALIZED = $8F9C;
-  GL_PRIMITIVE_RESTART = $8F9D;
-  GL_PRIMITIVE_RESTART_INDEX = $8F9E;
-  { Reuse tokens from ARB_copy_buffer }
-  { reuse GL_COPY_READ_BUFFER }
-  { reuse GL_COPY_WRITE_BUFFER }
-  { Would reuse tokens from ARB_draw_instanced, but it has none }
-  { Reuse tokens from ARB_uniform_buffer_object }
-  { reuse GL_UNIFORM_BUFFER }
-  { reuse GL_UNIFORM_BUFFER_BINDING }
-  { reuse GL_UNIFORM_BUFFER_START }
-  { reuse GL_UNIFORM_BUFFER_SIZE }
-  { reuse GL_MAX_VERTEX_UNIFORM_BLOCKS }
-  { reuse GL_MAX_FRAGMENT_UNIFORM_BLOCKS }
-  { reuse GL_MAX_COMBINED_UNIFORM_BLOCKS }
-  { reuse GL_MAX_UNIFORM_BUFFER_BINDINGS }
-  { reuse GL_MAX_UNIFORM_BLOCK_SIZE }
-  { reuse GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS }
-  { reuse GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS }
-  { reuse GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT }
-  { reuse GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH }
-  { reuse GL_ACTIVE_UNIFORM_BLOCKS }
-  { reuse GL_UNIFORM_TYPE }
-  { reuse GL_UNIFORM_SIZE }
-  { reuse GL_UNIFORM_NAME_LENGTH }
-  { reuse GL_UNIFORM_BLOCK_INDEX }
-  { reuse GL_UNIFORM_OFFSET }
-  { reuse GL_UNIFORM_ARRAY_STRIDE }
-  { reuse GL_UNIFORM_MATRIX_STRIDE }
-  { reuse GL_UNIFORM_IS_ROW_MAJOR }
-  { reuse GL_UNIFORM_BLOCK_BINDING }
-  { reuse GL_UNIFORM_BLOCK_DATA_SIZE }
-  { reuse GL_UNIFORM_BLOCK_NAME_LENGTH }
-  { reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS }
-  { reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES }
-  { reuse GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER }
-  { reuse GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER }
-  { reuse GL_INVALID_INDEX }
-
-  // GL_VERSION_3_2
-  GL_CONTEXT_CORE_PROFILE_BIT = $00000001;
-  GL_CONTEXT_COMPATIBILITY_PROFILE_BIT = $00000002;
-  GL_LINES_ADJACENCY = $000A;
-  GL_LINE_STRIP_ADJACENCY = $000B;
-  GL_TRIANGLES_ADJACENCY = $000C;
-  GL_TRIANGLE_STRIP_ADJACENCY = $000D;
-  GL_PROGRAM_POINT_SIZE = $8642;
-  GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = $8C29;
-  GL_FRAMEBUFFER_ATTACHMENT_LAYERED = $8DA7;
-  GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = $8DA8;
-  GL_GEOMETRY_SHADER = $8DD9;
-  GL_GEOMETRY_VERTICES_OUT = $8916;
-  GL_GEOMETRY_INPUT_TYPE = $8917;
-  GL_GEOMETRY_OUTPUT_TYPE = $8918;
-  GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = $8DDF;
-  GL_MAX_GEOMETRY_OUTPUT_VERTICES = $8DE0;
-  GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = $8DE1;
-  GL_MAX_VERTEX_OUTPUT_COMPONENTS = $9122;
-  GL_MAX_GEOMETRY_INPUT_COMPONENTS = $9123;
-  GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = $9124;
-  GL_MAX_FRAGMENT_INPUT_COMPONENTS = $9125;
-  GL_CONTEXT_PROFILE_MASK = $9126;
-  { reuse GL_MAX_VARYING_COMPONENTS }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER }
-  { Reuse tokens from ARB_depth_clamp }
-  { reuse GL_DEPTH_CLAMP }
-  { Would reuse tokens from ARB_draw_elements_base_vertex, but it has none }
-  { Would reuse tokens from ARB_fragment_coord_conventions, but it has none }
-  { Reuse tokens from ARB_provoking_vertex }
-  { reuse GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION }
-  { reuse GL_FIRST_VERTEX_CONVENTION }
-  { reuse GL_LAST_VERTEX_CONVENTION }
-  { reuse GL_PROVOKING_VERTEX }
-  { Reuse tokens from ARB_seamless_cube_map }
-  { reuse GL_TEXTURE_CUBE_MAP_SEAMLESS }
-  { Reuse tokens from ARB_sync }
-  { reuse GL_MAX_SERVER_WAIT_TIMEOUT }
-  { reuse GL_OBJECT_TYPE }
-  { reuse GL_SYNC_CONDITION }
-  { reuse GL_SYNC_STATUS }
-  { reuse GL_SYNC_FLAGS }
-  { reuse GL_SYNC_FENCE }
-  { reuse GL_SYNC_GPU_COMMANDS_COMPLETE }
-  { reuse GL_UNSIGNALED }
-  { reuse GL_SIGNALED }
-  { reuse GL_ALREADY_SIGNALED }
-  { reuse GL_TIMEOUT_EXPIRED }
-  { reuse GL_CONDITION_SATISFIED }
-  { reuse GL_WAIT_FAILED }
-  { reuse GL_TIMEOUT_IGNORED }
-  { reuse GL_SYNC_FLUSH_COMMANDS_BIT }
-  { reuse GL_TIMEOUT_IGNORED }
-  { Reuse tokens from ARB_texture_multisample }
-  { reuse GL_SAMPLE_POSITION }
-  { reuse GL_SAMPLE_MASK }
-  { reuse GL_SAMPLE_MASK_VALUE }
-  { reuse GL_MAX_SAMPLE_MASK_WORDS }
-  { reuse GL_TEXTURE_2D_MULTISAMPLE }
-  { reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE }
-  { reuse GL_TEXTURE_2D_MULTISAMPLE_ARRAY }
-  { reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY }
-  { reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE }
-  { reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY }
-  { reuse GL_TEXTURE_SAMPLES }
-  { reuse GL_TEXTURE_FIXED_SAMPLE_LOCATIONS }
-  { reuse GL_SAMPLER_2D_MULTISAMPLE }
-  { reuse GL_INT_SAMPLER_2D_MULTISAMPLE }
-  { reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE }
-  { reuse GL_SAMPLER_2D_MULTISAMPLE_ARRAY }
-  { reuse GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY }
-  { reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY }
-  { reuse GL_MAX_COLOR_TEXTURE_SAMPLES }
-  { reuse GL_MAX_DEPTH_TEXTURE_SAMPLES }
-  { reuse GL_MAX_INTEGER_SAMPLES }
-  { Don't need to reuse tokens from ARB_vertex_array_bgra since they're already in 1.2 core }
-
-  // GL_3DFX_multisample
-  GL_MULTISAMPLE_3DFX = $86B2;
-  GL_SAMPLE_BUFFERS_3DFX = $86B3;
-  GL_SAMPLES_3DFX = $86B4;
-  GL_MULTISAMPLE_BIT_3DFX = $20000000;
-
-  // GL_3DFX_texture_compression_FXT1
-  GL_COMPRESSED_RGB_FXT1_3DFX = $86B0;
-  GL_COMPRESSED_RGBA_FXT1_3DFX = $86B1;
-
-  // GL_APPLE_client_storage
-  GL_UNPACK_CLIENT_STORAGE_APPLE = $85B2;
-
-  // GL_APPLE_element_array
-  GL_ELEMENT_ARRAY_APPLE = $8768;
-  GL_ELEMENT_ARRAY_TYPE_APPLE = $8769;
-  GL_ELEMENT_ARRAY_POINTER_APPLE = $876A;
-
-  // GL_APPLE_fence
-  GL_DRAW_PIXELS_APPLE = $8A0A;
-  GL_FENCE_APPLE = $8A0B;
-
-  // GL_APPLE_specular_vector
-  GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE = $85B0;
-
-  // GL_APPLE_transform_hint
-  GL_TRANSFORM_HINT_APPLE = $85B1;
-
-  // GL_APPLE_vertex_array_object
-  GL_VERTEX_ARRAY_BINDING_APPLE = $85B5;
-
-  // GL_APPLE_vertex_array_range
-  GL_VERTEX_ARRAY_RANGE_APPLE = $851D;
-  GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE = $851E;
-  GL_VERTEX_ARRAY_STORAGE_HINT_APPLE = $851F;
-  GL_VERTEX_ARRAY_RANGE_POINTER_APPLE = $8521;
-  GL_STORAGE_CACHED_APPLE = $85BE;
-  GL_STORAGE_SHARED_APPLE = $85BF;
-
-  // GL_APPLE_ycbcr_422
-  GL_YCBCR_422_APPLE = $85B9;
-  GL_UNSIGNED_SHORT_8_8_APPLE = $85BA;
-  GL_UNSIGNED_SHORT_8_8_REV_APPLE = $85BB;
-
-  // GL_APPLE_texture_range
-  GL_TEXTURE_RANGE_LENGTH_APPLE = $85B7;
-  GL_TEXTURE_RANGE_POINTER_APPLE = $85B8;
-  GL_TEXTURE_STORAGE_HINT_APPLE = $85BC;
-  GL_STORAGE_PRIVATE_APPLE = $85BD;
-  { reuse GL_STORAGE_CACHED_APPLE }
-  { reuse GL_STORAGE_SHARED_APPLE }
-
-  // GL_APPLE_float_pixels
-  GL_HALF_APPLE = $140B;
-  GL_RGBA_FLOAT32_APPLE = $8814;
-  GL_RGB_FLOAT32_APPLE = $8815;
-  GL_ALPHA_FLOAT32_APPLE = $8816;
-  GL_INTENSITY_FLOAT32_APPLE = $8817;
-  GL_LUMINANCE_FLOAT32_APPLE = $8818;
-  GL_LUMINANCE_ALPHA_FLOAT32_APPLE = $8819;
-  GL_RGBA_FLOAT16_APPLE = $881A;
-  GL_RGB_FLOAT16_APPLE = $881B;
-  GL_ALPHA_FLOAT16_APPLE = $881C;
-  GL_INTENSITY_FLOAT16_APPLE = $881D;
-  GL_LUMINANCE_FLOAT16_APPLE = $881E;
-  GL_LUMINANCE_ALPHA_FLOAT16_APPLE = $881F;
-  GL_COLOR_FLOAT_APPLE = $8A0F;
-
-  // GL_APPLE_vertex_program_evaluators
-  GL_VERTEX_ATTRIB_MAP1_APPLE = $8A00;
-  GL_VERTEX_ATTRIB_MAP2_APPLE = $8A01;
-  GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE = $8A02;
-  GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE = $8A03;
-  GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE = $8A04;
-  GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE = $8A05;
-  GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE = $8A06;
-  GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE = $8A07;
-  GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE = $8A08;
-  GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE = $8A09;
-
-  // GL_APPLE_aux_depth_stencil
-  GL_AUX_DEPTH_STENCIL_APPLE = $8A14;
-
-  // GL_APPLE_object_purgeable
-  GL_BUFFER_OBJECT_APPLE = $85B3;
-  GL_RELEASED_APPLE = $8A19;
-  GL_VOLATILE_APPLE = $8A1A;
-  GL_RETAINED_APPLE = $8A1B;
-  GL_UNDEFINED_APPLE = $8A1C;
-  GL_PURGEABLE_APPLE = $8A1D;
-
-  // GL_APPLE_row_bytes
-  GL_PACK_ROW_BYTES_APPLE = $8A15;
-  GL_UNPACK_ROW_BYTES_APPLE = $8A16;
-  
-  
-  // GL_ARB_depth_texture
-  GL_DEPTH_COMPONENT16_ARB = $81A5;
-  GL_DEPTH_COMPONENT24_ARB = $81A6;
-  GL_DEPTH_COMPONENT32_ARB = $81A7;
-  GL_TEXTURE_DEPTH_SIZE_ARB = $884A;
-  GL_DEPTH_TEXTURE_MODE_ARB = $884B;
-
-  // GL_ARB_fragment_program
-  GL_FRAGMENT_PROGRAM_ARB = $8804;
-  GL_PROGRAM_ALU_INSTRUCTIONS_ARB = $8805;
-  GL_PROGRAM_TEX_INSTRUCTIONS_ARB = $8806;
-  GL_PROGRAM_TEX_INDIRECTIONS_ARB = $8807;
-  GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = $8808;
-  GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = $8809;
-  GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = $880A;
-  GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB = $880B;
-  GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB = $880C;
-  GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB = $880D;
-  GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = $880E;
-  GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = $880F;
-  GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = $8810;
-  GL_MAX_TEXTURE_COORDS_ARB = $8871;
-  GL_MAX_TEXTURE_IMAGE_UNITS_ARB = $8872;
-
-  // GL_ARB_imaging
-  GL_CONSTANT_COLOR_ARB = $8001;
-  GL_ONE_MINUS_CONSTANT_COLOR = $8002;
-  GL_CONSTANT_ALPHA = $8003;
-  GL_ONE_MINUS_CONSTANT_ALPHA = $8004;
-  GL_BLEND_COLOR = $8005;
-  GL_FUNC_ADD = $8006;
-  GL_MIN = $8007;
-  GL_MAX = $8008;
-  GL_BLEND_EQUATION = $8009;
-  GL_FUNC_SUBTRACT = $800A;
-  GL_FUNC_REVERSE_SUBTRACT = $800B;
-{$ifdef DGL_DEPRECATED}
-  GL_CONVOLUTION_1D = $8010;
-  GL_CONVOLUTION_2D = $8011;
-  GL_SEPARABLE_2D = $8012;
-  GL_CONVOLUTION_BORDER_MODE = $8013;
-  GL_CONVOLUTION_FILTER_SCALE = $8014;
-  GL_CONVOLUTION_FILTER_BIAS = $8015;
-  GL_REDUCE = $8016;
-  GL_CONVOLUTION_FORMAT = $8017;
-  GL_CONVOLUTION_WIDTH = $8018;
-  GL_CONVOLUTION_HEIGHT = $8019;
-  GL_MAX_CONVOLUTION_WIDTH = $801A;
-  GL_MAX_CONVOLUTION_HEIGHT = $801B;
-  GL_POST_CONVOLUTION_RED_SCALE = $801C;
-  GL_POST_CONVOLUTION_GREEN_SCALE = $801D;
-  GL_POST_CONVOLUTION_BLUE_SCALE = $801E;
-  GL_POST_CONVOLUTION_ALPHA_SCALE = $801F;
-  GL_POST_CONVOLUTION_RED_BIAS = $8020;
-  GL_POST_CONVOLUTION_GREEN_BIAS = $8021;
-  GL_POST_CONVOLUTION_BLUE_BIAS = $8022;
-  GL_POST_CONVOLUTION_ALPHA_BIAS = $8023;
-  GL_HISTOGRAM = $8024;
-  GL_PROXY_HISTOGRAM = $8025;
-  GL_HISTOGRAM_WIDTH = $8026;
-  GL_HISTOGRAM_FORMAT = $8027;
-  GL_HISTOGRAM_RED_SIZE = $8028;
-  GL_HISTOGRAM_GREEN_SIZE = $8029;
-  GL_HISTOGRAM_BLUE_SIZE = $802A;
-  GL_HISTOGRAM_ALPHA_SIZE = $802B;
-  GL_HISTOGRAM_LUMINANCE_SIZE = $802C;
-  GL_HISTOGRAM_SINK = $802D;
-  GL_MINMAX = $802E;
-  GL_MINMAX_FORMAT = $802F;
-  GL_MINMAX_SINK = $8030;
-  GL_TABLE_TOO_LARGE = $8031;
-  GL_COLOR_MATRIX = $80B1;
-  GL_COLOR_MATRIX_STACK_DEPTH = $80B2;
-  GL_MAX_COLOR_MATRIX_STACK_DEPTH = $80B3;
-  GL_POST_COLOR_MATRIX_RED_SCALE = $80B4;
-  GL_POST_COLOR_MATRIX_GREEN_SCALE = $80B5;
-  GL_POST_COLOR_MATRIX_BLUE_SCALE = $80B6;
-  GL_POST_COLOR_MATRIX_ALPHA_SCALE = $80B7;
-  GL_POST_COLOR_MATRIX_RED_BIAS = $80B8;
-  GL_POST_COLOR_MATRIX_GREEN_BIAS = $80B9;
-  GL_POST_COLOR_MATRIX_BLUE_BIAS = $80BA;
-  GL_POST_COLOR_MATRIX_ALPHA_BIAS = $80BB;
-  GL_COLOR_TABLE = $80D0;
-  GL_POST_CONVOLUTION_COLOR_TABLE = $80D1;
-  GL_POST_COLOR_MATRIX_COLOR_TABLE = $80D2;
-  GL_PROXY_COLOR_TABLE = $80D3;
-  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE = $80D4;
-  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE = $80D5;
-  GL_COLOR_TABLE_SCALE = $80D6;
-  GL_COLOR_TABLE_BIAS = $80D7;
-  GL_COLOR_TABLE_FORMAT = $80D8;
-  GL_COLOR_TABLE_WIDTH = $80D9;
-  GL_COLOR_TABLE_RED_SIZE = $80DA;
-  GL_COLOR_TABLE_GREEN_SIZE = $80DB;
-  GL_COLOR_TABLE_BLUE_SIZE = $80DC;
-  GL_COLOR_TABLE_ALPHA_SIZE = $80DD;
-  GL_COLOR_TABLE_LUMINANCE_SIZE = $80DE;
-  GL_COLOR_TABLE_INTENSITY_SIZE = $80DF;
-  GL_CONSTANT_BORDER = $8151;
-  GL_REPLICATE_BORDER = $8153;
-  GL_CONVOLUTION_BORDER_COLOR = $8154;
-{$endif}
-
-  // GL_ARB_matrix_palette
-  GL_MATRIX_PALETTE_ARB = $8840;
-  GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB = $8841;
-  GL_MAX_PALETTE_MATRICES_ARB = $8842;
-  GL_CURRENT_PALETTE_MATRIX_ARB = $8843;
-  GL_MATRIX_INDEX_ARRAY_ARB = $8844;
-  GL_CURRENT_MATRIX_INDEX_ARB = $8845;
-  GL_MATRIX_INDEX_ARRAY_SIZE_ARB = $8846;
-  GL_MATRIX_INDEX_ARRAY_TYPE_ARB = $8847;
-  GL_MATRIX_INDEX_ARRAY_STRIDE_ARB = $8848;
-  GL_MATRIX_INDEX_ARRAY_POINTER_ARB = $8849;
-
-  // GL_ARB_multisample
-  GL_MULTISAMPLE_ARB = $809D;
-  GL_SAMPLE_ALPHA_TO_COVERAGE_ARB = $809E;
-  GL_SAMPLE_ALPHA_TO_ONE_ARB = $809F;
-  GL_SAMPLE_COVERAGE_ARB = $80A0;
-  GL_SAMPLE_BUFFERS_ARB = $80A8;
-  GL_SAMPLES_ARB = $80A9;
-  GL_SAMPLE_COVERAGE_VALUE_ARB = $80AA;
-  GL_SAMPLE_COVERAGE_INVERT_ARB = $80AB;
-  GL_MULTISAMPLE_BIT_ARB = $20000000;
-
-  // GL_ARB_multitexture
-  GL_TEXTURE0_ARB = $84C0;
-  GL_TEXTURE1_ARB = $84C1;
-  GL_TEXTURE2_ARB = $84C2;
-  GL_TEXTURE3_ARB = $84C3;
-  GL_TEXTURE4_ARB = $84C4;
-  GL_TEXTURE5_ARB = $84C5;
-  GL_TEXTURE6_ARB = $84C6;
-  GL_TEXTURE7_ARB = $84C7;
-  GL_TEXTURE8_ARB = $84C8;
-  GL_TEXTURE9_ARB = $84C9;
-  GL_TEXTURE10_ARB = $84CA;
-  GL_TEXTURE11_ARB = $84CB;
-  GL_TEXTURE12_ARB = $84CC;
-  GL_TEXTURE13_ARB = $84CD;
-  GL_TEXTURE14_ARB = $84CE;
-  GL_TEXTURE15_ARB = $84CF;
-  GL_TEXTURE16_ARB = $84D0;
-  GL_TEXTURE17_ARB = $84D1;
-  GL_TEXTURE18_ARB = $84D2;
-  GL_TEXTURE19_ARB = $84D3;
-  GL_TEXTURE20_ARB = $84D4;
-  GL_TEXTURE21_ARB = $84D5;
-  GL_TEXTURE22_ARB = $84D6;
-  GL_TEXTURE23_ARB = $84D7;
-  GL_TEXTURE24_ARB = $84D8;
-  GL_TEXTURE25_ARB = $84D9;
-  GL_TEXTURE26_ARB = $84DA;
-  GL_TEXTURE27_ARB = $84DB;
-  GL_TEXTURE28_ARB = $84DC;
-  GL_TEXTURE29_ARB = $84DD;
-  GL_TEXTURE30_ARB = $84DE;
-  GL_TEXTURE31_ARB = $84DF;
-  GL_ACTIVE_TEXTURE_ARB = $84E0;
-  GL_CLIENT_ACTIVE_TEXTURE_ARB = $84E1;
-  GL_MAX_TEXTURE_UNITS_ARB = $84E2;
-
-  // GL_ARB_point_parameters
-  GL_POINT_SIZE_MIN_ARB = $8126;
-  GL_POINT_SIZE_MAX_ARB = $8127;
-  GL_POINT_FADE_THRESHOLD_SIZE_ARB = $8128;
-  GL_POINT_DISTANCE_ATTENUATION_ARB = $8129;
-
-  // GL_ARB_shadow
-  GL_TEXTURE_COMPARE_MODE_ARB = $884C;
-  GL_TEXTURE_COMPARE_FUNC_ARB = $884D;
-  GL_COMPARE_R_TO_TEXTURE_ARB = $884E;
-
-  // GL_ARB_shadow_ambient
-  GL_TEXTURE_COMPARE_FAIL_VALUE_ARB = $80BF;
-
-  // GL_ARB_texture_border_clamp
-  GL_CLAMP_TO_BORDER_ARB = $812D;
-
-  // GL_ARB_texture_compression
-  GL_COMPRESSED_ALPHA_ARB = $84E9;
-  GL_COMPRESSED_LUMINANCE_ARB = $84EA;
-  GL_COMPRESSED_LUMINANCE_ALPHA_ARB = $84EB;
-  GL_COMPRESSED_INTENSITY_ARB = $84EC;
-  GL_COMPRESSED_RGB_ARB = $84ED;
-  GL_COMPRESSED_RGBA_ARB = $84EE;
-  GL_TEXTURE_COMPRESSION_HINT_ARB = $84EF;
-  GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB = $86A0;
-  GL_TEXTURE_COMPRESSED_ARB = $86A1;
-  GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB = $86A2;
-  GL_COMPRESSED_TEXTURE_FORMATS_ARB = $86A3;
-
-  // GL_ARB_texture_cube_map
-  GL_NORMAL_MAP_ARB = $8511;
-  GL_REFLECTION_MAP_ARB = $8512;
-  GL_TEXTURE_CUBE_MAP_ARB = $8513;
-  GL_TEXTURE_BINDING_CUBE_MAP_ARB = $8514;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB = $8515;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB = $8516;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB = $8517;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB = $8518;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB = $8519;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB = $851A;
-  GL_PROXY_TEXTURE_CUBE_MAP_ARB = $851B;
-  GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB = $851C;
-
-  // GL_ARB_texture_env_combine
-  GL_COMBINE_ARB = $8570;
-  GL_COMBINE_RGB_ARB = $8571;
-  GL_COMBINE_ALPHA_ARB = $8572;
-  GL_SOURCE0_RGB_ARB = $8580;
-  GL_SOURCE1_RGB_ARB = $8581;
-  GL_SOURCE2_RGB_ARB = $8582;
-  GL_SOURCE0_ALPHA_ARB = $8588;
-  GL_SOURCE1_ALPHA_ARB = $8589;
-  GL_SOURCE2_ALPHA_ARB = $858A;
-  GL_OPERAND0_RGB_ARB = $8590;
-  GL_OPERAND1_RGB_ARB = $8591;
-  GL_OPERAND2_RGB_ARB = $8592;
-  GL_OPERAND0_ALPHA_ARB = $8598;
-  GL_OPERAND1_ALPHA_ARB = $8599;
-  GL_OPERAND2_ALPHA_ARB = $859A;
-  GL_RGB_SCALE_ARB = $8573;
-  GL_ADD_SIGNED_ARB = $8574;
-  GL_INTERPOLATE_ARB = $8575;
-  GL_SUBTRACT_ARB = $84E7;
-  GL_CONSTANT_ARB = $8576;
-  GL_PRIMARY_COLOR_ARB = $8577;
-  GL_PREVIOUS_ARB = $8578;
-
-  // GL_ARB_texture_env_dot3
-  GL_DOT3_RGB_ARB = $86AE;
-  GL_DOT3_RGBA_ARB = $86AF;
-
-  // GL_ARB_texture_mirrored_repeat
-  GL_MIRRORED_REPEAT_ARB = $8370;
-
-  // GL_ARB_transpose_matrix
-  GL_TRANSPOSE_MODELVIEW_MATRIX_ARB = $84E3;
-  GL_TRANSPOSE_PROJECTION_MATRIX_ARB = $84E4;
-  GL_TRANSPOSE_TEXTURE_MATRIX_ARB = $84E5;
-  GL_TRANSPOSE_COLOR_MATRIX_ARB = $84E6;
-
-  // GL_ARB_vertex_blend
-  GL_MAX_VERTEX_UNITS_ARB = $86A4;
-  GL_ACTIVE_VERTEX_UNITS_ARB = $86A5;
-  GL_WEIGHT_SUM_UNITY_ARB = $86A6;
-  GL_VERTEX_BLEND_ARB = $86A7;
-  GL_CURRENT_WEIGHT_ARB = $86A8;
-  GL_WEIGHT_ARRAY_TYPE_ARB = $86A9;
-  GL_WEIGHT_ARRAY_STRIDE_ARB = $86AA;
-  GL_WEIGHT_ARRAY_SIZE_ARB = $86AB;
-  GL_WEIGHT_ARRAY_POINTER_ARB = $86AC;
-  GL_WEIGHT_ARRAY_ARB = $86AD;
-  GL_MODELVIEW0_ARB = $1700;
-  GL_MODELVIEW1_ARB = $850A;
-  GL_MODELVIEW2_ARB = $8722;
-  GL_MODELVIEW3_ARB = $8723;
-  GL_MODELVIEW4_ARB = $8724;
-  GL_MODELVIEW5_ARB = $8725;
-  GL_MODELVIEW6_ARB = $8726;
-  GL_MODELVIEW7_ARB = $8727;
-  GL_MODELVIEW8_ARB = $8728;
-  GL_MODELVIEW9_ARB = $8729;
-  GL_MODELVIEW10_ARB = $872A;
-  GL_MODELVIEW11_ARB = $872B;
-  GL_MODELVIEW12_ARB = $872C;
-  GL_MODELVIEW13_ARB = $872D;
-  GL_MODELVIEW14_ARB = $872E;
-  GL_MODELVIEW15_ARB = $872F;
-  GL_MODELVIEW16_ARB = $8730;
-  GL_MODELVIEW17_ARB = $8731;
-  GL_MODELVIEW18_ARB = $8732;
-  GL_MODELVIEW19_ARB = $8733;
-  GL_MODELVIEW20_ARB = $8734;
-  GL_MODELVIEW21_ARB = $8735;
-  GL_MODELVIEW22_ARB = $8736;
-  GL_MODELVIEW23_ARB = $8737;
-  GL_MODELVIEW24_ARB = $8738;
-  GL_MODELVIEW25_ARB = $8739;
-  GL_MODELVIEW26_ARB = $873A;
-  GL_MODELVIEW27_ARB = $873B;
-  GL_MODELVIEW28_ARB = $873C;
-  GL_MODELVIEW29_ARB = $873D;
-  GL_MODELVIEW30_ARB = $873E;
-  GL_MODELVIEW31_ARB = $873F;
-
-  // GL_ARB_vertex_buffer_object
-  GL_BUFFER_SIZE_ARB = $8764;
-  GL_BUFFER_USAGE_ARB = $8765;
-  GL_ARRAY_BUFFER_ARB = $8892;
-  GL_ELEMENT_ARRAY_BUFFER_ARB = $8893;
-  GL_ARRAY_BUFFER_BINDING_ARB = $8894;
-  GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB = $8895;
-  GL_VERTEX_ARRAY_BUFFER_BINDING_ARB = $8896;
-  GL_NORMAL_ARRAY_BUFFER_BINDING_ARB = $8897;
-  GL_COLOR_ARRAY_BUFFER_BINDING_ARB = $8898;
-  GL_INDEX_ARRAY_BUFFER_BINDING_ARB = $8899;
-  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB = $889A;
-  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB = $889B;
-  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB = $889C;
-  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB = $889D;
-  GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB = $889E;
-  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB = $889F;
-  GL_READ_ONLY_ARB = $88B8;
-  GL_WRITE_ONLY_ARB = $88B9;
-  GL_READ_WRITE_ARB = $88BA;
-  GL_BUFFER_ACCESS_ARB = $88BB;
-  GL_BUFFER_MAPPED_ARB = $88BC;
-  GL_BUFFER_MAP_POINTER_ARB = $88BD;
-  GL_STREAM_DRAW_ARB = $88E0;
-  GL_STREAM_READ_ARB = $88E1;
-  GL_STREAM_COPY_ARB = $88E2;
-  GL_STATIC_DRAW_ARB = $88E4;
-  GL_STATIC_READ_ARB = $88E5;
-  GL_STATIC_COPY_ARB = $88E6;
-  GL_DYNAMIC_DRAW_ARB = $88E8;
-  GL_DYNAMIC_READ_ARB = $88E9;
-  GL_DYNAMIC_COPY_ARB = $88EA;
-
-  // GL_ARB_vertex_program
-  GL_COLOR_SUM_ARB = $8458;
-  GL_VERTEX_PROGRAM_ARB = $8620;
-  GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB = $8622;
-  GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB = $8623;
-  GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB = $8624;
-  GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB = $8625;
-  GL_CURRENT_VERTEX_ATTRIB_ARB = $8626;
-  GL_PROGRAM_LENGTH_ARB = $8627;
-  GL_PROGRAM_STRING_ARB = $8628;
-  GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB = $862E;
-  GL_MAX_PROGRAM_MATRICES_ARB = $862F;
-  GL_CURRENT_MATRIX_STACK_DEPTH_ARB = $8640;
-  GL_CURRENT_MATRIX_ARB = $8641;
-  GL_VERTEX_PROGRAM_POINT_SIZE_ARB = $8642;
-  GL_VERTEX_PROGRAM_TWO_SIDE_ARB = $8643;
-  GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB = $8645;
-  GL_PROGRAM_ERROR_POSITION_ARB = $864B;
-  GL_PROGRAM_BINDING_ARB = $8677;
-  GL_MAX_VERTEX_ATTRIBS_ARB = $8869;
-  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB = $886A;
-  GL_PROGRAM_ERROR_STRING_ARB = $8874;
-  GL_PROGRAM_FORMAT_ASCII_ARB = $8875;
-  GL_PROGRAM_FORMAT_ARB = $8876;
-  GL_PROGRAM_INSTRUCTIONS_ARB = $88A0;
-  GL_MAX_PROGRAM_INSTRUCTIONS_ARB = $88A1;
-  GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB = $88A2;
-  GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB = $88A3;
-  GL_PROGRAM_TEMPORARIES_ARB = $88A4;
-  GL_MAX_PROGRAM_TEMPORARIES_ARB = $88A5;
-  GL_PROGRAM_NATIVE_TEMPORARIES_ARB = $88A6;
-  GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB = $88A7;
-  GL_PROGRAM_PARAMETERS_ARB = $88A8;
-  GL_MAX_PROGRAM_PARAMETERS_ARB = $88A9;
-  GL_PROGRAM_NATIVE_PARAMETERS_ARB = $88AA;
-  GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB = $88AB;
-  GL_PROGRAM_ATTRIBS_ARB = $88AC;
-  GL_MAX_PROGRAM_ATTRIBS_ARB = $88AD;
-  GL_PROGRAM_NATIVE_ATTRIBS_ARB = $88AE;
-  GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB = $88AF;
-  GL_PROGRAM_ADDRESS_REGISTERS_ARB = $88B0;
-  GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB = $88B1;
-  GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = $88B2;
-  GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = $88B3;
-  GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB = $88B4;
-  GL_MAX_PROGRAM_ENV_PARAMETERS_ARB = $88B5;
-  GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB = $88B6;
-  GL_TRANSPOSE_CURRENT_MATRIX_ARB = $88B7;
-  GL_MATRIX0_ARB = $88C0;
-  GL_MATRIX1_ARB = $88C1;
-  GL_MATRIX2_ARB = $88C2;
-  GL_MATRIX3_ARB = $88C3;
-  GL_MATRIX4_ARB = $88C4;
-  GL_MATRIX5_ARB = $88C5;
-  GL_MATRIX6_ARB = $88C6;
-  GL_MATRIX7_ARB = $88C7;
-  GL_MATRIX8_ARB = $88C8;
-  GL_MATRIX9_ARB = $88C9;
-  GL_MATRIX10_ARB = $88CA;
-  GL_MATRIX11_ARB = $88CB;
-  GL_MATRIX12_ARB = $88CC;
-  GL_MATRIX13_ARB = $88CD;
-  GL_MATRIX14_ARB = $88CE;
-  GL_MATRIX15_ARB = $88CF;
-  GL_MATRIX16_ARB = $88D0;
-  GL_MATRIX17_ARB = $88D1;
-  GL_MATRIX18_ARB = $88D2;
-  GL_MATRIX19_ARB = $88D3;
-  GL_MATRIX20_ARB = $88D4;
-  GL_MATRIX21_ARB = $88D5;
-  GL_MATRIX22_ARB = $88D6;
-  GL_MATRIX23_ARB = $88D7;
-  GL_MATRIX24_ARB = $88D8;
-  GL_MATRIX25_ARB = $88D9;
-  GL_MATRIX26_ARB = $88DA;
-  GL_MATRIX27_ARB = $88DB;
-  GL_MATRIX28_ARB = $88DC;
-  GL_MATRIX29_ARB = $88DD;
-  GL_MATRIX30_ARB = $88DE;
-  GL_MATRIX31_ARB = $88DF;
-
-  // GL_ARB_draw_buffers
-  GL_MAX_DRAW_BUFFERS_ARB = $8824;
-  GL_DRAW_BUFFER0_ARB = $8825;
-  GL_DRAW_BUFFER1_ARB = $8826;
-  GL_DRAW_BUFFER2_ARB = $8827;
-  GL_DRAW_BUFFER3_ARB = $8828;
-  GL_DRAW_BUFFER4_ARB = $8829;
-  GL_DRAW_BUFFER5_ARB = $882A;
-  GL_DRAW_BUFFER6_ARB = $882B;
-  GL_DRAW_BUFFER7_ARB = $882C;
-  GL_DRAW_BUFFER8_ARB = $882D;
-  GL_DRAW_BUFFER9_ARB = $882E;
-  GL_DRAW_BUFFER10_ARB = $882F;
-  GL_DRAW_BUFFER11_ARB = $8830;
-  GL_DRAW_BUFFER12_ARB = $8831;
-  GL_DRAW_BUFFER13_ARB = $8832;
-  GL_DRAW_BUFFER14_ARB = $8833;
-  GL_DRAW_BUFFER15_ARB = $8834;
-
-  // GL_ARB_texture_rectangle
-  GL_TEXTURE_RECTANGLE_ARB = $84F5;
-  GL_TEXTURE_BINDING_RECTANGLE_ARB = $84F6;
-  GL_PROXY_TEXTURE_RECTANGLE_ARB = $84F7;
-  GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB = $84F8;
-
-  // GL_ARB_color_buffer_float
-  GL_RGBA_FLOAT_MODE_ARB = $8820;
-  GL_CLAMP_VERTEX_COLOR_ARB = $891A;
-  GL_CLAMP_FRAGMENT_COLOR_ARB = $891B;
-  GL_CLAMP_READ_COLOR_ARB = $891C;
-  GL_FIXED_ONLY_ARB = $891D;
-  WGL_TYPE_RGBA_FLOAT_ARB = $21A0;
-  GLX_RGBA_FLOAT_TYPE = $20B9;
-  GLX_RGBA_FLOAT_BIT = $00000004;
-
-  // GL_ARB_half_float_pixel
-  GL_HALF_FLOAT_ARB = $140B;
-
-  // GL_ARB_texture_float
-  GL_TEXTURE_RED_TYPE_ARB = $8C10;
-  GL_TEXTURE_GREEN_TYPE_ARB = $8C11;
-  GL_TEXTURE_BLUE_TYPE_ARB = $8C12;
-  GL_TEXTURE_ALPHA_TYPE_ARB = $8C13;
-  GL_TEXTURE_LUMINANCE_TYPE_ARB = $8C14;
-  GL_TEXTURE_INTENSITY_TYPE_ARB = $8C15;
-  GL_TEXTURE_DEPTH_TYPE_ARB = $8C16;
-  GL_UNSIGNED_NORMALIZED_ARB = $8C17;
-  GL_RGBA32F_ARB = $8814;
-  GL_RGB32F_ARB = $8815;
-  GL_ALPHA32F_ARB = $8816;
-  GL_INTENSITY32F_ARB = $8817;
-  GL_LUMINANCE32F_ARB = $8818;
-  GL_LUMINANCE_ALPHA32F_ARB = $8819;
-  GL_RGBA16F_ARB = $881A;
-  GL_RGB16F_ARB = $881B;
-  GL_ALPHA16F_ARB = $881C;
-  GL_INTENSITY16F_ARB = $881D;
-  GL_LUMINANCE16F_ARB = $881E;
-  GL_LUMINANCE_ALPHA16F_ARB = $881F;
-
-  // GL_ARB_pixel_buffer_object
-  GL_PIXEL_PACK_BUFFER_ARB = $88EB;
-  GL_PIXEL_UNPACK_BUFFER_ARB = $88EC;
-  GL_PIXEL_PACK_BUFFER_BINDING_ARB = $88ED;
-  GL_PIXEL_UNPACK_BUFFER_BINDING_ARB = $88EF;
-
-  // GL_ARB_depth_buffer_float
-  GL_DEPTH_COMPONENT32F = $8CAC;
-  GL_DEPTH32F_STENCIL8 = $8CAD;
-  GL_FLOAT_32_UNSIGNED_INT_24_8_REV = $8DAD;
-
-  // GL_ARB_framebuffer_object
-  GL_INVALID_FRAMEBUFFER_OPERATION = $0506;
-  GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = $8210;
-  GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = $8211;
-  GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE = $8212;
-  GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = $8213;
-  GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = $8214;
-  GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = $8215;
-  GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = $8216;
-  GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = $8217;
-  GL_FRAMEBUFFER_DEFAULT = $8218;
-  GL_FRAMEBUFFER_UNDEFINED = $8219;
-  GL_DEPTH_STENCIL_ATTACHMENT = $821A;
-  GL_MAX_RENDERBUFFER_SIZE = $84E8;
-  GL_DEPTH_STENCIL = $84F9;
-  GL_UNSIGNED_INT_24_8 = $84FA;
-  GL_DEPTH24_STENCIL8 = $88F0;
-  GL_TEXTURE_STENCIL_SIZE = $88F1;
-  GL_TEXTURE_RED_TYPE = $8C10;
-  GL_TEXTURE_GREEN_TYPE = $8C11;
-  GL_TEXTURE_BLUE_TYPE = $8C12;
-  GL_TEXTURE_ALPHA_TYPE = $8C13;
-  GL_TEXTURE_DEPTH_TYPE = $8C16;
-  GL_UNSIGNED_NORMALIZED = $8C17;
-  GL_FRAMEBUFFER_BINDING = $8CA6;
-  GL_DRAW_FRAMEBUFFER_BINDING = GL_FRAMEBUFFER_BINDING;
-  GL_RENDERBUFFER_BINDING = $8CA7;
-  GL_READ_FRAMEBUFFER = $8CA8;
-  GL_DRAW_FRAMEBUFFER = $8CA9;
-  GL_READ_FRAMEBUFFER_BINDING = $8CAA;
-  GL_RENDERBUFFER_SAMPLES = $8CAB;
-  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = $8CD0;
-  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = $8CD1;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = $8CD2;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = $8CD3;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = $8CD4;
-  GL_FRAMEBUFFER_COMPLETE = $8CD5;
-  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = $8CD6;
-  GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = $8CD7;
-  GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = $8CDB;
-  GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER = $8CDC;
-  GL_FRAMEBUFFER_UNSUPPORTED = $8CDD;
-  GL_MAX_COLOR_ATTACHMENTS = $8CDF;
-  GL_COLOR_ATTACHMENT0 = $8CE0;
-  GL_COLOR_ATTACHMENT1 = $8CE1;
-  GL_COLOR_ATTACHMENT2 = $8CE2;
-  GL_COLOR_ATTACHMENT3 = $8CE3;
-  GL_COLOR_ATTACHMENT4 = $8CE4;
-  GL_COLOR_ATTACHMENT5 = $8CE5;
-  GL_COLOR_ATTACHMENT6 = $8CE6;
-  GL_COLOR_ATTACHMENT7 = $8CE7;
-  GL_COLOR_ATTACHMENT8 = $8CE8;
-  GL_COLOR_ATTACHMENT9 = $8CE9;
-  GL_COLOR_ATTACHMENT10 = $8CEA;
-  GL_COLOR_ATTACHMENT11 = $8CEB;
-  GL_COLOR_ATTACHMENT12 = $8CEC;
-  GL_COLOR_ATTACHMENT13 = $8CED;
-  GL_COLOR_ATTACHMENT14 = $8CEE;
-  GL_COLOR_ATTACHMENT15 = $8CEF;
-  GL_DEPTH_ATTACHMENT = $8D00;
-  GL_STENCIL_ATTACHMENT = $8D20;
-  GL_FRAMEBUFFER = $8D40;
-  GL_RENDERBUFFER = $8D41;
-  GL_RENDERBUFFER_WIDTH = $8D42;
-  GL_RENDERBUFFER_HEIGHT = $8D43;
-  GL_RENDERBUFFER_INTERNAL_FORMAT = $8D44;
-  GL_STENCIL_INDEX1 = $8D46;
-  GL_STENCIL_INDEX4 = $8D47;
-  GL_STENCIL_INDEX8 = $8D48;
-  GL_STENCIL_INDEX16 = $8D49;
-  GL_RENDERBUFFER_RED_SIZE = $8D50;
-  GL_RENDERBUFFER_GREEN_SIZE = $8D51;
-  GL_RENDERBUFFER_BLUE_SIZE = $8D52;
-  GL_RENDERBUFFER_ALPHA_SIZE = $8D53;
-  GL_RENDERBUFFER_DEPTH_SIZE = $8D54;
-  GL_RENDERBUFFER_STENCIL_SIZE = $8D55;
-  GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = $8D56;
-  GL_MAX_SAMPLES = $8D57;
-{$ifdef DGL_DEPRECATED}
-  GL_INDEX = $8222;
-  GL_TEXTURE_LUMINANCE_TYPE = $8C14;
-  GL_TEXTURE_INTENSITY_TYPE = $8C15;
-{$endif}
-
-  // GL_ARB_framebuffer_sRGB
-  GL_FRAMEBUFFER_SRGB = $8DB9;
-
-  // GL_ARB_geometry_shader4
-  GL_LINES_ADJACENCY_ARB = $000A;
-  GL_LINE_STRIP_ADJACENCY_ARB = $000B;
-  GL_TRIANGLES_ADJACENCY_ARB = $000C;
-  GL_TRIANGLE_STRIP_ADJACENCY_ARB = $000D;
-  GL_PROGRAM_POINT_SIZE_ARB = $8642;
-  GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB = $8C29;
-  GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB = $8DA7;
-  GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB = $8DA8;
-  GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB = $8DA9;
-  GL_GEOMETRY_SHADER_ARB = $8DD9;
-  GL_GEOMETRY_VERTICES_OUT_ARB = $8DDA;
-  GL_GEOMETRY_INPUT_TYPE_ARB = $8DDB;
-  GL_GEOMETRY_OUTPUT_TYPE_ARB = $8DDC;
-  GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB = $8DDD;
-  GL_MAX_VERTEX_VARYING_COMPONENTS_ARB = $8DDE;
-  GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB = $8DDF;
-  GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB = $8DE0;
-  GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB = $8DE1;
-  { reuse GL_MAX_VARYING_COMPONENTS }
-  { reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER }
-
-  // GL_ARB_half_float_vertex
-  GL_HALF_FLOAT = $140B;
-
-  // GL_ARB_instanced_arrays
-  GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB = $88FE;
-
-  // GL_ARB_map_buffer_range
-  GL_MAP_READ_BIT = $0001;
-  GL_MAP_WRITE_BIT = $0002;
-  GL_MAP_INVALIDATE_RANGE_BIT = $0004;
-  GL_MAP_INVALIDATE_BUFFER_BIT = $0008;
-  GL_MAP_FLUSH_EXPLICIT_BIT = $0010;
-  GL_MAP_UNSYNCHRONIZED_BIT = $0020;
-
-  // GL_ARB_texture_buffer_object
-  GL_TEXTURE_BUFFER_ARB = $8C2A;
-  GL_MAX_TEXTURE_BUFFER_SIZE_ARB = $8C2B;
-  GL_TEXTURE_BINDING_BUFFER_ARB = $8C2C;
-  GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB = $8C2D;
-  GL_TEXTURE_BUFFER_FORMAT_ARB = $8C2E;
-
-  // GL_ARB_texture_compression_rgtc
-  GL_COMPRESSED_RED_RGTC1 = $8DBB;
-  GL_COMPRESSED_SIGNED_RED_RGTC1 = $8DBC;
-  GL_COMPRESSED_RG_RGTC2 = $8DBD;
-  GL_COMPRESSED_SIGNED_RG_RGTC2 = $8DBE;
-
-  // GL_ARB_texture_rg
-  GL_RG = $8227;
-  GL_RG_INTEGER = $8228;
-  GL_R8 = $8229;
-  GL_R16 = $822A;
-  GL_RG8 = $822B;
-  GL_RG16 = $822C;
-  GL_R16F = $822D;
-  GL_R32F = $822E;
-  GL_RG16F = $822F;
-  GL_RG32F = $8230;
-  GL_R8I = $8231;
-  GL_R8UI = $8232;
-  GL_R16I = $8233;
-  GL_R16UI = $8234;
-  GL_R32I = $8235;
-  GL_R32UI = $8236;
-  GL_RG8I = $8237;
-  GL_RG8UI = $8238;
-  GL_RG16I = $8239;
-  GL_RG16UI = $823A;
-  GL_RG32I = $823B;
-  GL_RG32UI = $823C;
-
-  // GL_ARB_vertex_array_object
-  GL_VERTEX_ARRAY_BINDING = $85B5;
-
-  // GL_ARB_uniform_buffer_object
-  GL_UNIFORM_BUFFER = $8A11;
-  GL_UNIFORM_BUFFER_BINDING = $8A28;
-  GL_UNIFORM_BUFFER_START = $8A29;
-  GL_UNIFORM_BUFFER_SIZE = $8A2A;
-  GL_MAX_VERTEX_UNIFORM_BLOCKS = $8A2B;
-  GL_MAX_GEOMETRY_UNIFORM_BLOCKS = $8A2C;
-  GL_MAX_FRAGMENT_UNIFORM_BLOCKS = $8A2D;
-  GL_MAX_COMBINED_UNIFORM_BLOCKS = $8A2E;
-  GL_MAX_UNIFORM_BUFFER_BINDINGS = $8A2F;
-  GL_MAX_UNIFORM_BLOCK_SIZE = $8A30;
-  GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = $8A31;
-  GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = $8A32;
-  GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = $8A33;
-  GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = $8A34;
-  GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = $8A35;
-  GL_ACTIVE_UNIFORM_BLOCKS = $8A36;
-  GL_UNIFORM_TYPE = $8A37;
-  GL_UNIFORM_SIZE = $8A38;
-  GL_UNIFORM_NAME_LENGTH = $8A39;
-  GL_UNIFORM_BLOCK_INDEX = $8A3A;
-  GL_UNIFORM_OFFSET = $8A3B;
-  GL_UNIFORM_ARRAY_STRIDE = $8A3C;
-  GL_UNIFORM_MATRIX_STRIDE = $8A3D;
-  GL_UNIFORM_IS_ROW_MAJOR = $8A3E;
-  GL_UNIFORM_BLOCK_BINDING = $8A3F;
-  GL_UNIFORM_BLOCK_DATA_SIZE = $8A40;
-  GL_UNIFORM_BLOCK_NAME_LENGTH = $8A41;
-  GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = $8A42;
-  GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = $8A43;
-  GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = $8A44;
-  GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER = $8A45;
-  GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = $8A46;
-  GL_INVALID_INDEX = $FFFFFFFF;
-
-  // GL_ARB_compatibility
-  { ARB_compatibility just defines tokens from core 3.0 }
-
-  // GL_ARB_copy_buffer
-  GL_COPY_READ_BUFFER = $8F36;
-  GL_COPY_WRITE_BUFFER = $8F37;
-
-  // GL_ARB_depth_clamp
-  GL_DEPTH_CLAMP = $864F;
-
-  // GL_ARB_provoking_vertex
-  GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION = $8E4C;
-  GL_FIRST_VERTEX_CONVENTION = $8E4D;
-  GL_LAST_VERTEX_CONVENTION = $8E4E;
-  GL_PROVOKING_VERTEX = $8E4F;
-
-  // GL_ARB_seamless_cube_map
-  GL_TEXTURE_CUBE_MAP_SEAMLESS = $884F;
-
-  // GL_ARB_sync
-  GL_MAX_SERVER_WAIT_TIMEOUT = $9111;
-  GL_OBJECT_TYPE = $9112;
-  GL_SYNC_CONDITION = $9113;
-  GL_SYNC_STATUS = $9114;
-  GL_SYNC_FLAGS = $9115;
-  GL_SYNC_FENCE = $9116;
-  GL_SYNC_GPU_COMMANDS_COMPLETE = $9117;
-  GL_UNSIGNALED = $9118;
-  GL_SIGNALED = $9119;
-  GL_ALREADY_SIGNALED = $911A;
-  GL_TIMEOUT_EXPIRED = $911B;
-  GL_CONDITION_SATISFIED = $911C;
-  GL_WAIT_FAILED = $911D;
-  GL_SYNC_FLUSH_COMMANDS_BIT = $00000001;
-  GL_TIMEOUT_IGNORED = $FFFFFFFFFFFFFFFF;
-
-  // GL_ARB_texture_multisample
-  GL_SAMPLE_POSITION = $8E50;
-  GL_SAMPLE_MASK = $8E51;
-  GL_SAMPLE_MASK_VALUE = $8E52;
-  GL_MAX_SAMPLE_MASK_WORDS = $8E59;
-  GL_TEXTURE_2D_MULTISAMPLE = $9100;
-  GL_PROXY_TEXTURE_2D_MULTISAMPLE = $9101;
-  GL_TEXTURE_2D_MULTISAMPLE_ARRAY = $9102;
-  GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY = $9103;
-  GL_TEXTURE_BINDING_2D_MULTISAMPLE = $9104;
-  GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = $9105;
-  GL_TEXTURE_SAMPLES = $9106;
-  GL_TEXTURE_FIXED_SAMPLE_LOCATIONS = $9107;
-  GL_SAMPLER_2D_MULTISAMPLE = $9108;
-  GL_INT_SAMPLER_2D_MULTISAMPLE = $9109;
-  GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = $910A;
-  GL_SAMPLER_2D_MULTISAMPLE_ARRAY = $910B;
-  GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = $910C;
-  GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = $910D;
-  GL_MAX_COLOR_TEXTURE_SAMPLES = $910E;
-  GL_MAX_DEPTH_TEXTURE_SAMPLES = $910F;
-  GL_MAX_INTEGER_SAMPLES = $9110;
-
-  // GL_ARB_vertex_array_bgra
-  { reuse GL_BGRA }
-
-  // GL_ARB_sample_shading
-  GL_SAMPLE_SHADING = $8C36;
-  GL_MIN_SAMPLE_SHADING_VALUE = $8C37;
-
-  // GL_ARB_texture_cube_map_array
-  GL_TEXTURE_CUBE_MAP_ARRAY = $9009;
-  GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = $900A;
-  GL_PROXY_TEXTURE_CUBE_MAP_ARRAY = $900B;
-  GL_SAMPLER_CUBE_MAP_ARRAY = $900C;
-  GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = $900D;
-  GL_INT_SAMPLER_CUBE_MAP_ARRAY = $900E;
-  GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = $900F;
-
-  // GL_ARB_texture_gather
-  GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET = $8E5E;
-  GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET = $8E5F;
-  GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS = $8F9F;
-
-  // GL_ATI_draw_buffers
-  GL_MAX_DRAW_BUFFERS_ATI = $8824;
-  GL_DRAW_BUFFER0_ATI = $8825;
-  GL_DRAW_BUFFER1_ATI = $8826;
-  GL_DRAW_BUFFER2_ATI = $8827;
-  GL_DRAW_BUFFER3_ATI = $8828;
-  GL_DRAW_BUFFER4_ATI = $8829;
-  GL_DRAW_BUFFER5_ATI = $882A;
-  GL_DRAW_BUFFER6_ATI = $882B;
-  GL_DRAW_BUFFER7_ATI = $882C;
-  GL_DRAW_BUFFER8_ATI = $882D;
-  GL_DRAW_BUFFER9_ATI = $882E;
-  GL_DRAW_BUFFER10_ATI = $882F;
-  GL_DRAW_BUFFER11_ATI = $8830;
-  GL_DRAW_BUFFER12_ATI = $8831;
-  GL_DRAW_BUFFER13_ATI = $8832;
-  GL_DRAW_BUFFER14_ATI = $8833;
-  GL_DRAW_BUFFER15_ATI = $8834;
-
-  // GL_ATI_element_array
-  GL_ELEMENT_ARRAY_ATI = $8768;
-  GL_ELEMENT_ARRAY_TYPE_ATI = $8769;
-  GL_ELEMENT_ARRAY_POINTER_ATI = $876A;
-
-  // GL_ATI_envmap_bumpmap
-  GL_BUMP_ROT_MATRIX_ATI = $8775;
-  GL_BUMP_ROT_MATRIX_SIZE_ATI = $8776;
-  GL_BUMP_NUM_TEX_UNITS_ATI = $8777;
-  GL_BUMP_TEX_UNITS_ATI = $8778;
-  GL_DUDV_ATI = $8779;
-  GL_DU8DV8_ATI = $877A;
-  GL_BUMP_ENVMAP_ATI = $877B;
-  GL_BUMP_TARGET_ATI = $877C;
-
-  // GL_ATI_fragment_shader
-  GL_FRAGMENT_SHADER_ATI = $8920;
-  GL_REG_0_ATI = $8921;
-  GL_REG_1_ATI = $8922;
-  GL_REG_2_ATI = $8923;
-  GL_REG_3_ATI = $8924;
-  GL_REG_4_ATI = $8925;
-  GL_REG_5_ATI = $8926;
-  GL_REG_6_ATI = $8927;
-  GL_REG_7_ATI = $8928;
-  GL_REG_8_ATI = $8929;
-  GL_REG_9_ATI = $892A;
-  GL_REG_10_ATI = $892B;
-  GL_REG_11_ATI = $892C;
-  GL_REG_12_ATI = $892D;
-  GL_REG_13_ATI = $892E;
-  GL_REG_14_ATI = $892F;
-  GL_REG_15_ATI = $8930;
-  GL_REG_16_ATI = $8931;
-  GL_REG_17_ATI = $8932;
-  GL_REG_18_ATI = $8933;
-  GL_REG_19_ATI = $8934;
-  GL_REG_20_ATI = $8935;
-  GL_REG_21_ATI = $8936;
-  GL_REG_22_ATI = $8937;
-  GL_REG_23_ATI = $8938;
-  GL_REG_24_ATI = $8939;
-  GL_REG_25_ATI = $893A;
-  GL_REG_26_ATI = $893B;
-  GL_REG_27_ATI = $893C;
-  GL_REG_28_ATI = $893D;
-  GL_REG_29_ATI = $893E;
-  GL_REG_30_ATI = $893F;
-  GL_REG_31_ATI = $8940;
-  GL_CON_0_ATI = $8941;
-  GL_CON_1_ATI = $8942;
-  GL_CON_2_ATI = $8943;
-  GL_CON_3_ATI = $8944;
-  GL_CON_4_ATI = $8945;
-  GL_CON_5_ATI = $8946;
-  GL_CON_6_ATI = $8947;
-  GL_CON_7_ATI = $8948;
-  GL_CON_8_ATI = $8949;
-  GL_CON_9_ATI = $894A;
-  GL_CON_10_ATI = $894B;
-  GL_CON_11_ATI = $894C;
-  GL_CON_12_ATI = $894D;
-  GL_CON_13_ATI = $894E;
-  GL_CON_14_ATI = $894F;
-  GL_CON_15_ATI = $8950;
-  GL_CON_16_ATI = $8951;
-  GL_CON_17_ATI = $8952;
-  GL_CON_18_ATI = $8953;
-  GL_CON_19_ATI = $8954;
-  GL_CON_20_ATI = $8955;
-  GL_CON_21_ATI = $8956;
-  GL_CON_22_ATI = $8957;
-  GL_CON_23_ATI = $8958;
-  GL_CON_24_ATI = $8959;
-  GL_CON_25_ATI = $895A;
-  GL_CON_26_ATI = $895B;
-  GL_CON_27_ATI = $895C;
-  GL_CON_28_ATI = $895D;
-  GL_CON_29_ATI = $895E;
-  GL_CON_30_ATI = $895F;
-  GL_CON_31_ATI = $8960;
-  GL_MOV_ATI = $8961;
-  GL_ADD_ATI = $8963;
-  GL_MUL_ATI = $8964;
-  GL_SUB_ATI = $8965;
-  GL_DOT3_ATI = $8966;
-  GL_DOT4_ATI = $8967;
-  GL_MAD_ATI = $8968;
-  GL_LERP_ATI = $8969;
-  GL_CND_ATI = $896A;
-  GL_CND0_ATI = $896B;
-  GL_DOT2_ADD_ATI = $896C;
-  GL_SECONDARY_INTERPOLATOR_ATI = $896D;
-  GL_NUM_FRAGMENT_REGISTERS_ATI = $896E;
-  GL_NUM_FRAGMENT_CONSTANTS_ATI = $896F;
-  GL_NUM_PASSES_ATI = $8970;
-  GL_NUM_INSTRUCTIONS_PER_PASS_ATI = $8971;
-  GL_NUM_INSTRUCTIONS_TOTAL_ATI = $8972;
-  GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI = $8973;
-  GL_NUM_LOOPBACK_COMPONENTS_ATI = $8974;
-  GL_COLOR_ALPHA_PAIRING_ATI = $8975;
-  GL_SWIZZLE_STR_ATI = $8976;
-  GL_SWIZZLE_STQ_ATI = $8977;
-  GL_SWIZZLE_STR_DR_ATI = $8978;
-  GL_SWIZZLE_STQ_DQ_ATI = $8979;
-  GL_SWIZZLE_STRQ_ATI = $897A;
-  GL_SWIZZLE_STRQ_DQ_ATI = $897B;
-  GL_RED_BIT_ATI = $00000001;
-  GL_GREEN_BIT_ATI = $00000002;
-  GL_BLUE_BIT_ATI = $00000004;
-  GL_2X_BIT_ATI = $00000001;
-  GL_4X_BIT_ATI = $00000002;
-  GL_8X_BIT_ATI = $00000004;
-  GL_HALF_BIT_ATI = $00000008;
-  GL_QUARTER_BIT_ATI = $00000010;
-  GL_EIGHTH_BIT_ATI = $00000020;
-  GL_SATURATE_BIT_ATI = $00000040;
-  GL_COMP_BIT_ATI = $00000002;
-  GL_NEGATE_BIT_ATI = $00000004;
-  GL_BIAS_BIT_ATI = $00000008;
-
-  // GL_ATI_pn_triangles
-  GL_PN_TRIANGLES_ATI = $87F0;
-  GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI = $87F1;
-  GL_PN_TRIANGLES_POINT_MODE_ATI = $87F2;
-  GL_PN_TRIANGLES_NORMAL_MODE_ATI = $87F3;
-  GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI = $87F4;
-  GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI = $87F5;
-  GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI = $87F6;
-  GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI = $87F7;
-  GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI = $87F8;
-
-  // GL_ATI_separate_stencil
-  GL_STENCIL_BACK_FUNC_ATI = $8800;
-  GL_STENCIL_BACK_FAIL_ATI = $8801;
-  GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI = $8802;
-  GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI = $8803;
-
-  // GL_ATI_text_fragment_shader
-  GL_TEXT_FRAGMENT_SHADER_ATI = $8200;
-
-  // GL_ATI_texture_env_combine3
-  GL_MODULATE_ADD_ATI = $8744;
-  GL_MODULATE_SIGNED_ADD_ATI = $8745;
-  GL_MODULATE_SUBTRACT_ATI = $8746;
-
-  // GL_ATI_texture_float
-  GL_RGBA_FLOAT32_ATI = $8814;
-  GL_RGB_FLOAT32_ATI = $8815;
-  GL_ALPHA_FLOAT32_ATI = $8816;
-  GL_INTENSITY_FLOAT32_ATI = $8817;
-  GL_LUMINANCE_FLOAT32_ATI = $8818;
-  GL_LUMINANCE_ALPHA_FLOAT32_ATI = $8819;
-  GL_RGBA_FLOAT16_ATI = $881A;
-  GL_RGB_FLOAT16_ATI = $881B;
-  GL_ALPHA_FLOAT16_ATI = $881C;
-  GL_INTENSITY_FLOAT16_ATI = $881D;
-  GL_LUMINANCE_FLOAT16_ATI = $881E;
-  GL_LUMINANCE_ALPHA_FLOAT16_ATI = $881F;
-
-  // GL_ATI_texture_mirror_once
-  GL_MIRROR_CLAMP_ATI = $8742;
-  GL_MIRROR_CLAMP_TO_EDGE_ATI = $8743;
-
-  // GL_ATI_vertex_array_object
-  GL_STATIC_ATI = $8760;
-  GL_DYNAMIC_ATI = $8761;
-  GL_PRESERVE_ATI = $8762;
-  GL_DISCARD_ATI = $8763;
-  GL_OBJECT_BUFFER_SIZE_ATI = $8764;
-  GL_OBJECT_BUFFER_USAGE_ATI = $8765;
-  GL_ARRAY_OBJECT_BUFFER_ATI = $8766;
-  GL_ARRAY_OBJECT_OFFSET_ATI = $8767;
-
-  // GL_ATI_vertex_streams
-  GL_MAX_VERTEX_STREAMS_ATI = $876B;
-  GL_VERTEX_STREAM0_ATI = $876C;
-  GL_VERTEX_STREAM1_ATI = $876D;
-  GL_VERTEX_STREAM2_ATI = $876E;
-  GL_VERTEX_STREAM3_ATI = $876F;
-  GL_VERTEX_STREAM4_ATI = $8770;
-  GL_VERTEX_STREAM5_ATI = $8771;
-  GL_VERTEX_STREAM6_ATI = $8772;
-  GL_VERTEX_STREAM7_ATI = $8773;
-  GL_VERTEX_SOURCE_ATI = $8774;
-
-  // GL_ATI_meminfo
-  GL_VBO_FREE_MEMORY_ATI = $87FB;
-  GL_TEXTURE_FREE_MEMORY_ATI = $87FC;
-  GL_RENDERBUFFER_FREE_MEMORY_ATI = $87FD;
-
-  // GL_AMD_performance_monitor
-  GL_COUNTER_TYPE_AMD = $8BC0;
-  GL_COUNTER_RANGE_AMD = $8BC1;
-  GL_UNSIGNED_INT64_AMD = $8BC2;
-  GL_PERCENTAGE_AMD = $8BC3;
-  GL_PERFMON_RESULT_AVAILABLE_AMD = $8BC4;
-  GL_PERFMON_RESULT_SIZE_AMD = $8BC5;
-  GL_PERFMON_RESULT_AMD = $8BC6;
-  
-  // GL_AMD_vertex_shader_tesselator
-  GL_SAMPLER_BUFFER_AMD = $9001;
-  GL_INT_SAMPLER_BUFFER_AMD = $9002;
-  GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD = $9003;
-  GL_TESSELLATION_MODE_AMD = $9004;
-  GL_TESSELLATION_FACTOR_AMD = $9005;
-  GL_DISCRETE_AMD = $9006;
-  GL_CONTINUOUS_AMD = $9007;
-
-  // GL_EXT_422_pixels
-  GL_422_EXT = $80CC;
-  GL_422_REV_EXT = $80CD;
-  GL_422_AVERAGE_EXT = $80CE;
-  GL_422_REV_AVERAGE_EXT = $80CF;
-
-  // GL_EXT_abgr
-  GL_ABGR_EXT = $8000;
-
-  // GL_EXT_bgra
-  GL_BGR_EXT = $80E0;
-  GL_BGRA_EXT = $80E1;
-
-  // GL_EXT_blend_color
-  GL_CONSTANT_COLOR_EXT = $8001;
-  GL_ONE_MINUS_CONSTANT_COLOR_EXT = $8002;
-  GL_CONSTANT_ALPHA_EXT = $8003;
-  GL_ONE_MINUS_CONSTANT_ALPHA_EXT = $8004;
-  GL_BLEND_COLOR_EXT = $8005;
-
-  // GL_EXT_blend_func_separate
-  GL_BLEND_DST_RGB_EXT = $80C8;
-  GL_BLEND_SRC_RGB_EXT = $80C9;
-  GL_BLEND_DST_ALPHA_EXT = $80CA;
-  GL_BLEND_SRC_ALPHA_EXT = $80CB;
-
-  // GL_EXT_blend_minmax
-  GL_FUNC_ADD_EXT = $8006;
-  GL_MIN_EXT = $8007;
-  GL_MAX_EXT = $8008;
-  GL_BLEND_EQUATION_EXT = $8009;
-
-  // GL_EXT_blend_subtract
-  GL_FUNC_SUBTRACT_EXT = $800A;
-  GL_FUNC_REVERSE_SUBTRACT_EXT = $800B;
-
-  // GL_EXT_clip_volume_hint
-  GL_CLIP_VOLUME_CLIPPING_HINT_EXT = $80F0;
-
-  // GL_EXT_cmyka
-  GL_CMYK_EXT = $800C;
-  GL_CMYKA_EXT = $800D;
-  GL_PACK_CMYK_HINT_EXT = $800E;
-  GL_UNPACK_CMYK_HINT_EXT = $800F;
-
-  // GL_EXT_compiled_vertex_array
-  GL_ARRAY_ELEMENT_LOCK_FIRST_EXT = $81A8;
-  GL_ARRAY_ELEMENT_LOCK_COUNT_EXT = $81A9;
-
-  // GL_EXT_convolution
-  GL_CONVOLUTION_1D_EXT = $8010;
-  GL_CONVOLUTION_2D_EXT = $8011;
-  GL_SEPARABLE_2D_EXT = $8012;
-  GL_CONVOLUTION_BORDER_MODE_EXT = $8013;
-  GL_CONVOLUTION_FILTER_SCALE_EXT = $8014;
-  GL_CONVOLUTION_FILTER_BIAS_EXT = $8015;
-  GL_REDUCE_EXT = $8016;
-  GL_CONVOLUTION_FORMAT_EXT = $8017;
-  GL_CONVOLUTION_WIDTH_EXT = $8018;
-  GL_CONVOLUTION_HEIGHT_EXT = $8019;
-  GL_MAX_CONVOLUTION_WIDTH_EXT = $801A;
-  GL_MAX_CONVOLUTION_HEIGHT_EXT = $801B;
-  GL_POST_CONVOLUTION_RED_SCALE_EXT = $801C;
-  GL_POST_CONVOLUTION_GREEN_SCALE_EXT = $801D;
-  GL_POST_CONVOLUTION_BLUE_SCALE_EXT = $801E;
-  GL_POST_CONVOLUTION_ALPHA_SCALE_EXT = $801F;
-  GL_POST_CONVOLUTION_RED_BIAS_EXT = $8020;
-  GL_POST_CONVOLUTION_GREEN_BIAS_EXT = $8021;
-  GL_POST_CONVOLUTION_BLUE_BIAS_EXT = $8022;
-  GL_POST_CONVOLUTION_ALPHA_BIAS_EXT = $8023;
-
-  // GL_EXT_coordinate_frame
-  GL_TANGENT_ARRAY_EXT = $8439;
-  GL_BINORMAL_ARRAY_EXT = $843A;
-  GL_CURRENT_TANGENT_EXT = $843B;
-  GL_CURRENT_BINORMAL_EXT = $843C;
-  GL_TANGENT_ARRAY_TYPE_EXT = $843E;
-  GL_TANGENT_ARRAY_STRIDE_EXT = $843F;
-  GL_BINORMAL_ARRAY_TYPE_EXT = $8440;
-  GL_BINORMAL_ARRAY_STRIDE_EXT = $8441;
-  GL_TANGENT_ARRAY_POINTER_EXT = $8442;
-  GL_BINORMAL_ARRAY_POINTER_EXT = $8443;
-  GL_MAP1_TANGENT_EXT = $8444;
-  GL_MAP2_TANGENT_EXT = $8445;
-  GL_MAP1_BINORMAL_EXT = $8446;
-  GL_MAP2_BINORMAL_EXT = $8447;
-
-  // GL_EXT_cull_vertex
-  GL_CULL_VERTEX_EXT = $81AA;
-  GL_CULL_VERTEX_EYE_POSITION_EXT = $81AB;
-  GL_CULL_VERTEX_OBJECT_POSITION_EXT = $81AC;
-
-  // GL_EXT_draw_range_elements
-  GL_MAX_ELEMENTS_VERTICES_EXT = $80E8;
-  GL_MAX_ELEMENTS_INDICES_EXT = $80E9;
-
-  // GL_EXT_fog_coord
-  GL_FOG_COORDINATE_SOURCE_EXT = $8450;
-  GL_FOG_COORDINATE_EXT = $8451;
-  GL_FRAGMENT_DEPTH_EXT = $8452;
-  GL_CURRENT_FOG_COORDINATE_EXT = $8453;
-  GL_FOG_COORDINATE_ARRAY_TYPE_EXT = $8454;
-  GL_FOG_COORDINATE_ARRAY_STRIDE_EXT = $8455;
-  GL_FOG_COORDINATE_ARRAY_POINTER_EXT = $8456;
-  GL_FOG_COORDINATE_ARRAY_EXT = $8457;
-
-  // GL_EXT_framebuffer_object
-  GL_FRAMEBUFFER_EXT = $8D40;
-  GL_RENDERBUFFER_EXT = $8D41;
-  GL_STENCIL_INDEX_EXT = $8D45;
-  GL_STENCIL_INDEX1_EXT = $8D46;
-  GL_STENCIL_INDEX4_EXT = $8D47;
-  GL_STENCIL_INDEX8_EXT = $8D48;
-  GL_STENCIL_INDEX16_EXT = $8D49;
-  GL_RENDERBUFFER_WIDTH_EXT = $8D42;
-  GL_RENDERBUFFER_HEIGHT_EXT = $8D43;
-  GL_RENDERBUFFER_INTERNAL_FORMAT_EXT = $8D44;
-  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT = $8CD0;
-  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT = $8CD1;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT = $8CD2;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT = $8CD3;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT = $8CD4;
-  GL_COLOR_ATTACHMENT0_EXT = $8CE0;
-  GL_COLOR_ATTACHMENT1_EXT = $8CE1;
-  GL_COLOR_ATTACHMENT2_EXT = $8CE2;
-  GL_COLOR_ATTACHMENT3_EXT = $8CE3;
-  GL_COLOR_ATTACHMENT4_EXT = $8CE4;
-  GL_COLOR_ATTACHMENT5_EXT = $8CE5;
-  GL_COLOR_ATTACHMENT6_EXT = $8CE6;
-  GL_COLOR_ATTACHMENT7_EXT = $8CE7;
-  GL_COLOR_ATTACHMENT8_EXT = $8CE8;
-  GL_COLOR_ATTACHMENT9_EXT = $8CE9;
-  GL_COLOR_ATTACHMENT10_EXT = $8CEA;
-  GL_COLOR_ATTACHMENT11_EXT = $8CEB;
-  GL_COLOR_ATTACHMENT12_EXT = $8CEC;
-  GL_COLOR_ATTACHMENT13_EXT = $8CED;
-  GL_COLOR_ATTACHMENT14_EXT = $8CEE;
-  GL_COLOR_ATTACHMENT15_EXT = $8CEF;
-  GL_DEPTH_ATTACHMENT_EXT = $8D00;
-  GL_STENCIL_ATTACHMENT_EXT = $8D20;
-  GL_FRAMEBUFFER_COMPLETE_EXT = $8CD5;
-  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT = $8CD6;
-  GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT = $8CD7;
-  GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT = $8CD8;
-  GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT = $8CD9;
-  GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT = $8CDA;
-  GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT = $8CDB;
-  GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT = $8CDC;
-  GL_FRAMEBUFFER_UNSUPPORTED_EXT = $8CDD;
-  GL_FRAMEBUFFER_STATUS_ERROR_EXT = $8CDE;
-  GL_FRAMEBUFFER_BINDING_EXT = $8CA6;
-  GL_RENDERBUFFER_BINDING_EXT = $8CA7;
-  GL_MAX_COLOR_ATTACHMENTS_EXT = $8CDF;
-  GL_MAX_RENDERBUFFER_SIZE_EXT = $84E8;
-  GL_INVALID_FRAMEBUFFER_OPERATION_EXT = $0506;
-
-  // GL_EXT_histogram
-  GL_HISTOGRAM_EXT = $8024;
-  GL_PROXY_HISTOGRAM_EXT = $8025;
-  GL_HISTOGRAM_WIDTH_EXT = $8026;
-  GL_HISTOGRAM_FORMAT_EXT = $8027;
-  GL_HISTOGRAM_RED_SIZE_EXT = $8028;
-  GL_HISTOGRAM_GREEN_SIZE_EXT = $8029;
-  GL_HISTOGRAM_BLUE_SIZE_EXT = $802A;
-  GL_HISTOGRAM_ALPHA_SIZE_EXT = $802B;
-  GL_HISTOGRAM_LUMINANCE_SIZE_EXT = $802C;
-  GL_HISTOGRAM_SINK_EXT = $802D;
-  GL_MINMAX_EXT = $802E;
-  GL_MINMAX_FORMAT_EXT = $802F;
-  GL_MINMAX_SINK_EXT = $8030;
-  GL_TABLE_TOO_LARGE_EXT = $8031;
-
-  // GL_EXT_index_array_formats
-  GL_IUI_V2F_EXT = $81AD;
-  GL_IUI_V3F_EXT = $81AE;
-  GL_IUI_N3F_V2F_EXT = $81AF;
-  GL_IUI_N3F_V3F_EXT = $81B0;
-  GL_T2F_IUI_V2F_EXT = $81B1;
-  GL_T2F_IUI_V3F_EXT = $81B2;
-  GL_T2F_IUI_N3F_V2F_EXT = $81B3;
-  GL_T2F_IUI_N3F_V3F_EXT = $81B4;
-
-  // GL_EXT_index_func
-  GL_INDEX_TEST_EXT = $81B5;
-  GL_INDEX_TEST_FUNC_EXT = $81B6;
-  GL_INDEX_TEST_REF_EXT = $81B7;
-
-  // GL_EXT_index_material
-  GL_INDEX_MATERIAL_EXT = $81B8;
-  GL_INDEX_MATERIAL_PARAMETER_EXT = $81B9;
-  GL_INDEX_MATERIAL_FACE_EXT = $81BA;
-
-  // GL_EXT_light_texture
-  GL_FRAGMENT_MATERIAL_EXT = $8349;
-  GL_FRAGMENT_NORMAL_EXT = $834A;
-  GL_FRAGMENT_COLOR_EXT = $834C;
-  GL_ATTENUATION_EXT = $834D;
-  GL_SHADOW_ATTENUATION_EXT = $834E;
-  GL_TEXTURE_APPLICATION_MODE_EXT = $834F;
-  GL_TEXTURE_LIGHT_EXT = $8350;
-  GL_TEXTURE_MATERIAL_FACE_EXT = $8351;
-  GL_TEXTURE_MATERIAL_PARAMETER_EXT = $8352;
-
-  // GL_EXT_multisample
-  GL_MULTISAMPLE_EXT = $809D;
-  GL_SAMPLE_ALPHA_TO_MASK_EXT = $809E;
-  GL_SAMPLE_ALPHA_TO_ONE_EXT = $809F;
-  GL_SAMPLE_MASK_EXT = $80A0;
-  GL_1PASS_EXT = $80A1;
-  GL_2PASS_0_EXT = $80A2;
-  GL_2PASS_1_EXT = $80A3;
-  GL_4PASS_0_EXT = $80A4;
-  GL_4PASS_1_EXT = $80A5;
-  GL_4PASS_2_EXT = $80A6;
-  GL_4PASS_3_EXT = $80A7;
-  GL_SAMPLE_BUFFERS_EXT = $80A8;
-  GL_SAMPLES_EXT = $80A9;
-  GL_SAMPLE_MASK_VALUE_EXT = $80AA;
-  GL_SAMPLE_MASK_INVERT_EXT = $80AB;
-  GL_SAMPLE_PATTERN_EXT = $80AC;
-  GL_MULTISAMPLE_BIT_EXT = $20000000;
-
-  // GL_EXT_packed_pixels
-  GL_UNSIGNED_BYTE_3_3_2_EXT = $8032;
-  GL_UNSIGNED_SHORT_4_4_4_4_EXT = $8033;
-  GL_UNSIGNED_SHORT_5_5_5_1_EXT = $8034;
-  GL_UNSIGNED_INT_8_8_8_8_EXT = $8035;
-  GL_UNSIGNED_INT_10_10_10_2_EXT = $8036;
-
-  // GL_EXT_paletted_texture
-  GL_COLOR_INDEX1_EXT = $80E2;
-  GL_COLOR_INDEX2_EXT = $80E3;
-  GL_COLOR_INDEX4_EXT = $80E4;
-  GL_COLOR_INDEX8_EXT = $80E5;
-  GL_COLOR_INDEX12_EXT = $80E6;
-  GL_COLOR_INDEX16_EXT = $80E7;
-  GL_TEXTURE_INDEX_SIZE_EXT = $80ED;
-
-  // GL_EXT_pixel_transform
-  GL_PIXEL_TRANSFORM_2D_EXT = $8330;
-  GL_PIXEL_MAG_FILTER_EXT = $8331;
-  GL_PIXEL_MIN_FILTER_EXT = $8332;
-  GL_PIXEL_CUBIC_WEIGHT_EXT = $8333;
-  GL_CUBIC_EXT = $8334;
-  GL_AVERAGE_EXT = $8335;
-  GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT = $8336;
-  GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT = $8337;
-  GL_PIXEL_TRANSFORM_2D_MATRIX_EXT = $8338;
-
-  // GL_EXT_point_parameters
-  GL_POINT_SIZE_MIN_EXT = $8126;
-  GL_POINT_SIZE_MAX_EXT = $8127;
-  GL_POINT_FADE_THRESHOLD_SIZE_EXT = $8128;
-  GL_DISTANCE_ATTENUATION_EXT = $8129;
-
-  // GL_EXT_polygon_offset
-  GL_POLYGON_OFFSET_EXT = $8037;
-  GL_POLYGON_OFFSET_FACTOR_EXT = $8038;
-  GL_POLYGON_OFFSET_BIAS_EXT = $8039;
-
-  // GL_EXT_rescale_normal
-  GL_RESCALE_NORMAL_EXT = $803A;
-
-  // GL_EXT_secondary_color
-  GL_COLOR_SUM_EXT = $8458;
-  GL_CURRENT_SECONDARY_COLOR_EXT = $8459;
-  GL_SECONDARY_COLOR_ARRAY_SIZE_EXT = $845A;
-  GL_SECONDARY_COLOR_ARRAY_TYPE_EXT = $845B;
-  GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT = $845C;
-  GL_SECONDARY_COLOR_ARRAY_POINTER_EXT = $845D;
-  GL_SECONDARY_COLOR_ARRAY_EXT = $845E;
-
-  // GL_EXT_separate_specular_color
-  GL_LIGHT_MODEL_COLOR_CONTROL_EXT = $81F8;
-  GL_SINGLE_COLOR_EXT = $81F9;
-  GL_SEPARATE_SPECULAR_COLOR_EXT = $81FA;
-
-  // GL_EXT_shared_texture_palette
-  GL_SHARED_TEXTURE_PALETTE_EXT = $81FB;
-
-  // GL_EXT_stencil_two_side
-  GL_STENCIL_TEST_TWO_SIDE_EXT = $8910;
-  GL_ACTIVE_STENCIL_FACE_EXT = $8911;
-
-  // GL_EXT_stencil_wrap
-  GL_INCR_WRAP_EXT = $8507;
-  GL_DECR_WRAP_EXT = $8508;
-
-  // GL_EXT_texture
-  GL_ALPHA4_EXT = $803B;
-  GL_ALPHA8_EXT = $803C;
-  GL_ALPHA12_EXT = $803D;
-  GL_ALPHA16_EXT = $803E;
-  GL_LUMINANCE4_EXT = $803F;
-  GL_LUMINANCE8_EXT = $8040;
-  GL_LUMINANCE12_EXT = $8041;
-  GL_LUMINANCE16_EXT = $8042;
-  GL_LUMINANCE4_ALPHA4_EXT = $8043;
-  GL_LUMINANCE6_ALPHA2_EXT = $8044;
-  GL_LUMINANCE8_ALPHA8_EXT = $8045;
-  GL_LUMINANCE12_ALPHA4_EXT = $8046;
-  GL_LUMINANCE12_ALPHA12_EXT = $8047;
-  GL_LUMINANCE16_ALPHA16_EXT = $8048;
-  GL_INTENSITY_EXT = $8049;
-  GL_INTENSITY4_EXT = $804A;
-  GL_INTENSITY8_EXT = $804B;
-  GL_INTENSITY12_EXT = $804C;
-  GL_INTENSITY16_EXT = $804D;
-  GL_RGB2_EXT = $804E;
-  GL_RGB4_EXT = $804F;
-  GL_RGB5_EXT = $8050;
-  GL_RGB8_EXT = $8051;
-  GL_RGB10_EXT = $8052;
-  GL_RGB12_EXT = $8053;
-  GL_RGB16_EXT = $8054;
-  GL_RGBA2_EXT = $8055;
-  GL_RGBA4_EXT = $8056;
-  GL_RGB5_A1_EXT = $8057;
-  GL_RGBA8_EXT = $8058;
-  GL_RGB10_A2_EXT = $8059;
-  GL_RGBA12_EXT = $805A;
-  GL_RGBA16_EXT = $805B;
-  GL_TEXTURE_RED_SIZE_EXT = $805C;
-  GL_TEXTURE_GREEN_SIZE_EXT = $805D;
-  GL_TEXTURE_BLUE_SIZE_EXT = $805E;
-  GL_TEXTURE_ALPHA_SIZE_EXT = $805F;
-  GL_TEXTURE_LUMINANCE_SIZE_EXT = $8060;
-  GL_TEXTURE_INTENSITY_SIZE_EXT = $8061;
-  GL_REPLACE_EXT = $8062;
-  GL_PROXY_TEXTURE_1D_EXT = $8063;
-  GL_PROXY_TEXTURE_2D_EXT = $8064;
-  GL_TEXTURE_TOO_LARGE_EXT = $8065;
-
-  // GL_EXT_texture3D
-  GL_PACK_SKIP_IMAGES_EXT = $806B;
-  GL_PACK_IMAGE_HEIGHT_EXT = $806C;
-  GL_UNPACK_SKIP_IMAGES_EXT = $806D;
-  GL_UNPACK_IMAGE_HEIGHT_EXT = $806E;
-  GL_TEXTURE_3D_EXT = $806F;
-  GL_PROXY_TEXTURE_3D_EXT = $8070;
-  GL_TEXTURE_DEPTH_EXT = $8071;
-  GL_TEXTURE_WRAP_R_EXT = $8072;
-  GL_MAX_3D_TEXTURE_SIZE_EXT = $8073;
-
-  // GL_EXT_texture_compression_s3tc
-  GL_COMPRESSED_RGB_S3TC_DXT1_EXT = $83F0;
-  GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = $83F1;
-  GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = $83F2;
-  GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = $83F3;
-
-  // GL_EXT_texture_cube_map
-  GL_NORMAL_MAP_EXT = $8511;
-  GL_REFLECTION_MAP_EXT = $8512;
-  GL_TEXTURE_CUBE_MAP_EXT = $8513;
-  GL_TEXTURE_BINDING_CUBE_MAP_EXT = $8514;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT = $8515;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT = $8516;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT = $8517;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT = $8518;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT = $8519;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT = $851A;
-  GL_PROXY_TEXTURE_CUBE_MAP_EXT = $851B;
-  GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT = $851C;
-
-  // GL_EXT_texture_edge_clamp
-  GL_CLAMP_TO_EDGE_EXT = $812F;
-
-  // GL_EXT_texture_env_combine
-  GL_COMBINE_EXT = $8570;
-  GL_COMBINE_RGB_EXT = $8571;
-  GL_COMBINE_ALPHA_EXT = $8572;
-  GL_RGB_SCALE_EXT = $8573;
-  GL_ADD_SIGNED_EXT = $8574;
-  GL_INTERPOLATE_EXT = $8575;
-  GL_CONSTANT_EXT = $8576;
-  GL_PRIMARY_COLOR_EXT = $8577;
-  GL_PREVIOUS_EXT = $8578;
-  GL_SOURCE0_RGB_EXT = $8580;
-  GL_SOURCE1_RGB_EXT = $8581;
-  GL_SOURCE2_RGB_EXT = $8582;
-  GL_SOURCE0_ALPHA_EXT = $8588;
-  GL_SOURCE1_ALPHA_EXT = $8589;
-  GL_SOURCE2_ALPHA_EXT = $858A;
-  GL_OPERAND0_RGB_EXT = $8590;
-  GL_OPERAND1_RGB_EXT = $8591;
-  GL_OPERAND2_RGB_EXT = $8592;
-  GL_OPERAND0_ALPHA_EXT = $8598;
-  GL_OPERAND1_ALPHA_EXT = $8599;
-  GL_OPERAND2_ALPHA_EXT = $859A;
-
-  // GL_EXT_texture_env_dot3
-  GL_DOT3_RGB_EXT = $8740;
-  GL_DOT3_RGBA_EXT = $8741;
-
-  // GL_EXT_texture_filter_anisotropic
-  GL_TEXTURE_MAX_ANISOTROPY_EXT = $84FE;
-  GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = $84FF;
-
-  // GL_EXT_texture_lod_bias
-  GL_MAX_TEXTURE_LOD_BIAS_EXT = $84FD;
-  GL_TEXTURE_FILTER_CONTROL_EXT = $8500;
-  GL_TEXTURE_LOD_BIAS_EXT = $8501;
-
-  // GL_EXT_texture_object
-  GL_TEXTURE_PRIORITY_EXT = $8066;
-  GL_TEXTURE_RESIDENT_EXT = $8067;
-  GL_TEXTURE_1D_BINDING_EXT = $8068;
-  GL_TEXTURE_2D_BINDING_EXT = $8069;
-  GL_TEXTURE_3D_BINDING_EXT = $806A;
-
-  // GL_EXT_texture_perturb_normal
-  GL_PERTURB_EXT = $85AE;
-  GL_TEXTURE_NORMAL_EXT = $85AF;
-
-  // GL_EXT_texture_rectangle
-  GL_TEXTURE_RECTANGLE_EXT = $84F5;
-  GL_TEXTURE_BINDING_RECTANGLE_EXT = $84F6;
-  GL_PROXY_TEXTURE_RECTANGLE_EXT = $84F7;
-  GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT = $84F8;
-
-  // GL_EXT_vertex_array
-  GL_VERTEX_ARRAY_EXT = $8074;
-  GL_NORMAL_ARRAY_EXT = $8075;
-  GL_COLOR_ARRAY_EXT = $8076;
-  GL_INDEX_ARRAY_EXT = $8077;
-  GL_TEXTURE_COORD_ARRAY_EXT = $8078;
-  GL_EDGE_FLAG_ARRAY_EXT = $8079;
-  GL_VERTEX_ARRAY_SIZE_EXT = $807A;
-  GL_VERTEX_ARRAY_TYPE_EXT = $807B;
-  GL_VERTEX_ARRAY_STRIDE_EXT = $807C;
-  GL_VERTEX_ARRAY_COUNT_EXT = $807D;
-  GL_NORMAL_ARRAY_TYPE_EXT = $807E;
-  GL_NORMAL_ARRAY_STRIDE_EXT = $807F;
-  GL_NORMAL_ARRAY_COUNT_EXT = $8080;
-  GL_COLOR_ARRAY_SIZE_EXT = $8081;
-  GL_COLOR_ARRAY_TYPE_EXT = $8082;
-  GL_COLOR_ARRAY_STRIDE_EXT = $8083;
-  GL_COLOR_ARRAY_COUNT_EXT = $8084;
-  GL_INDEX_ARRAY_TYPE_EXT = $8085;
-  GL_INDEX_ARRAY_STRIDE_EXT = $8086;
-  GL_INDEX_ARRAY_COUNT_EXT = $8087;
-  GL_TEXTURE_COORD_ARRAY_SIZE_EXT = $8088;
-  GL_TEXTURE_COORD_ARRAY_TYPE_EXT = $8089;
-  GL_TEXTURE_COORD_ARRAY_STRIDE_EXT = $808A;
-  GL_TEXTURE_COORD_ARRAY_COUNT_EXT = $808B;
-  GL_EDGE_FLAG_ARRAY_STRIDE_EXT = $808C;
-  GL_EDGE_FLAG_ARRAY_COUNT_EXT = $808D;
-  GL_VERTEX_ARRAY_POINTER_EXT = $808E;
-  GL_NORMAL_ARRAY_POINTER_EXT = $808F;
-  GL_COLOR_ARRAY_POINTER_EXT = $8090;
-  GL_INDEX_ARRAY_POINTER_EXT = $8091;
-  GL_TEXTURE_COORD_ARRAY_POINTER_EXT = $8092;
-  GL_EDGE_FLAG_ARRAY_POINTER_EXT = $8093;
-
-  // GL_EXT_vertex_shader
-  GL_VERTEX_SHADER_EXT = $8780;
-  GL_VERTEX_SHADER_BINDING_EXT = $8781;
-  GL_OP_INDEX_EXT = $8782;
-  GL_OP_NEGATE_EXT = $8783;
-  GL_OP_DOT3_EXT = $8784;
-  GL_OP_DOT4_EXT = $8785;
-  GL_OP_MUL_EXT = $8786;
-  GL_OP_ADD_EXT = $8787;
-  GL_OP_MADD_EXT = $8788;
-  GL_OP_FRAC_EXT = $8789;
-  GL_OP_MAX_EXT = $878A;
-  GL_OP_MIN_EXT = $878B;
-  GL_OP_SET_GE_EXT = $878C;
-  GL_OP_SET_LT_EXT = $878D;
-  GL_OP_CLAMP_EXT = $878E;
-  GL_OP_FLOOR_EXT = $878F;
-  GL_OP_ROUND_EXT = $8790;
-  GL_OP_EXP_BASE_2_EXT = $8791;
-  GL_OP_LOG_BASE_2_EXT = $8792;
-  GL_OP_POWER_EXT = $8793;
-  GL_OP_RECIP_EXT = $8794;
-  GL_OP_RECIP_SQRT_EXT = $8795;
-  GL_OP_SUB_EXT = $8796;
-  GL_OP_CROSS_PRODUCT_EXT = $8797;
-  GL_OP_MULTIPLY_MATRIX_EXT = $8798;
-  GL_OP_MOV_EXT = $8799;
-  GL_OUTPUT_VERTEX_EXT = $879A;
-  GL_OUTPUT_COLOR0_EXT = $879B;
-  GL_OUTPUT_COLOR1_EXT = $879C;
-  GL_OUTPUT_TEXTURE_COORD0_EXT = $879D;
-  GL_OUTPUT_TEXTURE_COORD1_EXT = $879E;
-  GL_OUTPUT_TEXTURE_COORD2_EXT = $879F;
-  GL_OUTPUT_TEXTURE_COORD3_EXT = $87A0;
-  GL_OUTPUT_TEXTURE_COORD4_EXT = $87A1;
-  GL_OUTPUT_TEXTURE_COORD5_EXT = $87A2;
-  GL_OUTPUT_TEXTURE_COORD6_EXT = $87A3;
-  GL_OUTPUT_TEXTURE_COORD7_EXT = $87A4;
-  GL_OUTPUT_TEXTURE_COORD8_EXT = $87A5;
-  GL_OUTPUT_TEXTURE_COORD9_EXT = $87A6;
-  GL_OUTPUT_TEXTURE_COORD10_EXT = $87A7;
-  GL_OUTPUT_TEXTURE_COORD11_EXT = $87A8;
-  GL_OUTPUT_TEXTURE_COORD12_EXT = $87A9;
-  GL_OUTPUT_TEXTURE_COORD13_EXT = $87AA;
-  GL_OUTPUT_TEXTURE_COORD14_EXT = $87AB;
-  GL_OUTPUT_TEXTURE_COORD15_EXT = $87AC;
-  GL_OUTPUT_TEXTURE_COORD16_EXT = $87AD;
-  GL_OUTPUT_TEXTURE_COORD17_EXT = $87AE;
-  GL_OUTPUT_TEXTURE_COORD18_EXT = $87AF;
-  GL_OUTPUT_TEXTURE_COORD19_EXT = $87B0;
-  GL_OUTPUT_TEXTURE_COORD20_EXT = $87B1;
-  GL_OUTPUT_TEXTURE_COORD21_EXT = $87B2;
-  GL_OUTPUT_TEXTURE_COORD22_EXT = $87B3;
-  GL_OUTPUT_TEXTURE_COORD23_EXT = $87B4;
-  GL_OUTPUT_TEXTURE_COORD24_EXT = $87B5;
-  GL_OUTPUT_TEXTURE_COORD25_EXT = $87B6;
-  GL_OUTPUT_TEXTURE_COORD26_EXT = $87B7;
-  GL_OUTPUT_TEXTURE_COORD27_EXT = $87B8;
-  GL_OUTPUT_TEXTURE_COORD28_EXT = $87B9;
-  GL_OUTPUT_TEXTURE_COORD29_EXT = $87BA;
-  GL_OUTPUT_TEXTURE_COORD30_EXT = $87BB;
-  GL_OUTPUT_TEXTURE_COORD31_EXT = $87BC;
-  GL_OUTPUT_FOG_EXT = $87BD;
-  GL_SCALAR_EXT = $87BE;
-  GL_VECTOR_EXT = $87BF;
-  GL_MATRIX_EXT = $87C0;
-  GL_VARIANT_EXT = $87C1;
-  GL_INVARIANT_EXT = $87C2;
-  GL_LOCAL_CONSTANT_EXT = $87C3;
-  GL_LOCAL_EXT = $87C4;
-  GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT = $87C5;
-  GL_MAX_VERTEX_SHADER_VARIANTS_EXT = $87C6;
-  GL_MAX_VERTEX_SHADER_INVARIANTS_EXT = $87C7;
-  GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = $87C8;
-  GL_MAX_VERTEX_SHADER_LOCALS_EXT = $87C9;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT = $87CA;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT = $87CB;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = $87CC;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT = $87CD;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT = $87CE;
-  GL_VERTEX_SHADER_INSTRUCTIONS_EXT = $87CF;
-  GL_VERTEX_SHADER_VARIANTS_EXT = $87D0;
-  GL_VERTEX_SHADER_INVARIANTS_EXT = $87D1;
-  GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = $87D2;
-  GL_VERTEX_SHADER_LOCALS_EXT = $87D3;
-  GL_VERTEX_SHADER_OPTIMIZED_EXT = $87D4;
-  GL_X_EXT = $87D5;
-  GL_Y_EXT = $87D6;
-  GL_Z_EXT = $87D7;
-  GL_W_EXT = $87D8;
-  GL_NEGATIVE_X_EXT = $87D9;
-  GL_NEGATIVE_Y_EXT = $87DA;
-  GL_NEGATIVE_Z_EXT = $87DB;
-  GL_NEGATIVE_W_EXT = $87DC;
-  GL_ZERO_EXT = $87DD;
-  GL_ONE_EXT = $87DE;
-  GL_NEGATIVE_ONE_EXT = $87DF;
-  GL_NORMALIZED_RANGE_EXT = $87E0;
-  GL_FULL_RANGE_EXT = $87E1;
-  GL_CURRENT_VERTEX_EXT = $87E2;
-  GL_MVP_MATRIX_EXT = $87E3;
-  GL_VARIANT_VALUE_EXT = $87E4;
-  GL_VARIANT_DATATYPE_EXT = $87E5;
-  GL_VARIANT_ARRAY_STRIDE_EXT = $87E6;
-  GL_VARIANT_ARRAY_TYPE_EXT = $87E7;
-  GL_VARIANT_ARRAY_EXT = $87E8;
-  GL_VARIANT_ARRAY_POINTER_EXT = $87E9;
-  GL_INVARIANT_VALUE_EXT = $87EA;
-  GL_INVARIANT_DATATYPE_EXT = $87EB;
-  GL_LOCAL_CONSTANT_VALUE_EXT = $87EC;
-  GL_LOCAL_CONSTANT_DATATYPE_EXT = $87ED;
-
-  // GL_EXT_vertex_weighting
-  GL_MODELVIEW0_STACK_DEPTH_EXT = $0BA3;
-  GL_MODELVIEW1_STACK_DEPTH_EXT = $8502;
-  GL_MODELVIEW0_MATRIX_EXT = $0BA6;
-  GL_MODELVIEW1_MATRIX_EXT = $8506;
-  GL_VERTEX_WEIGHTING_EXT = $8509;
-  GL_MODELVIEW0_EXT = $1700;
-  GL_MODELVIEW1_EXT = $850A;
-  GL_CURRENT_VERTEX_WEIGHT_EXT = $850B;
-  GL_VERTEX_WEIGHT_ARRAY_EXT = $850C;
-  GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT = $850D;
-  GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT = $850E;
-  GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT = $850F;
-  GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT = $8510;
-
-  // GL_EXT_depth_bounds_test
-  GL_DEPTH_BOUNDS_TEST_EXT = $8890;
-  GL_DEPTH_BOUNDS_EXT = $8891;
-
-  // GL_EXT_texture_mirror_clamp
-  GL_MIRROR_CLAMP_EXT = $8742;
-  GL_MIRROR_CLAMP_TO_EDGE_EXT = $8743;
-  GL_MIRROR_CLAMP_TO_BORDER_EXT = $8912;
-
-  // GL_EXT_blend_equation_separate
-  GL_BLEND_EQUATION_RGB_EXT = $8009; 
-  GL_BLEND_EQUATION_ALPHA_EXT = $883D;
-
-  // GL_EXT_pixel_buffer_object
-  GL_PIXEL_PACK_BUFFER_EXT = $88EB;
-  GL_PIXEL_UNPACK_BUFFER_EXT = $88EC;
-  GL_PIXEL_PACK_BUFFER_BINDING_EXT = $88ED;
-  GL_PIXEL_UNPACK_BUFFER_BINDING_EXT = $88EF;
-
-  // GL_EXT_stencil_clear_tag
-  GL_STENCIL_TAG_BITS_EXT = $88F2;
-  GL_STENCIL_CLEAR_TAG_VALUE_EXT = $88F3;
-
-  // GL_EXT_packed_depth_stencil
-  GL_DEPTH_STENCIL_EXT = $84F9;
-  GL_UNSIGNED_INT_24_8_EXT = $84FA;
-  GL_DEPTH24_STENCIL8_EXT = $88F0;
-  GL_TEXTURE_STENCIL_SIZE_EXT = $88F1;
-
-  // GL_EXT_texture_sRGB
-  GL_SRGB_EXT = $8C40;
-  GL_SRGB8_EXT = $8C41;
-  GL_SRGB_ALPHA_EXT = $8C42;
-  GL_SRGB8_ALPHA8_EXT = $8C43;
-  GL_SLUMINANCE_ALPHA_EXT = $8C44;
-  GL_SLUMINANCE8_ALPHA8_EXT = $8C45;
-  GL_SLUMINANCE_EXT = $8C46;
-  GL_SLUMINANCE8_EXT = $8C47;
-  GL_COMPRESSED_SRGB_EXT = $8C48;
-  GL_COMPRESSED_SRGB_ALPHA_EXT = $8C49;
-  GL_COMPRESSED_SLUMINANCE_EXT = $8C4A;
-  GL_COMPRESSED_SLUMINANCE_ALPHA_EXT = $8C4B;
-  GL_COMPRESSED_SRGB_S3TC_DXT1_EXT = $8C4C;
-  GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = $8C4D;
-  GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = $8C4E;
-  GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = $8C4F;
-
-  // GL_EXT_framebuffer_blit
-  GL_READ_FRAMEBUFFER_EXT = $8CA8;
-  GL_DRAW_FRAMEBUFFER_EXT = $8CA9;
-  GL_READ_FRAMEBUFFER_BINDING_EXT = GL_FRAMEBUFFER_BINDING_EXT;
-  GL_DRAW_FRAMEBUFFER_BINDING_EXT = $8CAA;
-
-  // GL_EXT_framebuffer_multisample
-  GL_RENDERBUFFER_SAMPLES_EXT = $8CAB;
-  GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT = $8D56;
-  GL_MAX_SAMPLES_EXT = $8D57;
-
-  // GL_EXT_timer_query
-  GL_TIME_ELAPSED_EXT = $88BF;
-
-  // GL_EXT_bindable_uniform
-  GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT = $8DE2;
-  GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT = $8DE3;
-  GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT = $8DE4;
-  GL_MAX_BINDABLE_UNIFORM_SIZE_EXT = $8DED;
-  GL_UNIFORM_BUFFER_BINDING_EXT = $8DEF;
-
-  // GL_EXT_framebuffer_sRGB
-  GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT = $20B2;
-  WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT = $20A9;
-  GL_FRAMEBUFFER_SRGB_EXT = $8DB9;
-  GL_FRAMEBUFFER_SRGB_CAPABLE_EXT = $8DBA;
-
-  // GL_EXT_geometry_shader4
-  GL_GEOMETRY_SHADER_EXT = $8DD9;
-  GL_GEOMETRY_VERTICES_OUT_EXT = $8DDA;
-  GL_GEOMETRY_INPUT_TYPE_EXT = $8DDB;
-  GL_GEOMETRY_OUTPUT_TYPE_EXT = $8DDC;
-  GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT = $8C29;
-  GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT = $8DDD;
-  GL_MAX_VERTEX_VARYING_COMPONENTS_EXT = $8DDE;
-  GL_MAX_VARYING_COMPONENTS_EXT = $8B4B;
-  GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT = $8DDF;
-  GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT = $8DE0;
-  GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT = $8DE1;
-  GL_LINES_ADJACENCY_EXT = $A;
-  GL_LINE_STRIP_ADJACENCY_EXT = $B;
-  GL_TRIANGLES_ADJACENCY_EXT = $C;
-  GL_TRIANGLE_STRIP_ADJACENCY_EXT = $D;
-  GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT = $8DA8;
-  GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT = $8DA9;
-  GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT = $8DA7;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT = $8CD4;
-  GL_PROGRAM_POINT_SIZE_EXT = $8642;
-
-  // GL_EXT_gpu_shader4
-  GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT = $88FD;
-  GL_SAMPLER_1D_ARRAY_EXT = $8DC0;
-  GL_SAMPLER_2D_ARRAY_EXT = $8DC1;
-  GL_SAMPLER_BUFFER_EXT = $8DC2;
-  GL_SAMPLER_1D_ARRAY_SHADOW_EXT = $8DC3;
-  GL_SAMPLER_2D_ARRAY_SHADOW_EXT = $8DC4;
-  GL_SAMPLER_CUBE_SHADOW_EXT = $8DC5;
-  GL_UNSIGNED_INT_VEC2_EXT = $8DC6;
-  GL_UNSIGNED_INT_VEC3_EXT = $8DC7;
-  GL_UNSIGNED_INT_VEC4_EXT = $8DC8;
-  GL_INT_SAMPLER_1D_EXT = $8DC9;
-  GL_INT_SAMPLER_2D_EXT = $8DCA;
-  GL_INT_SAMPLER_3D_EXT = $8DCB;
-  GL_INT_SAMPLER_CUBE_EXT = $8DCC;
-  GL_INT_SAMPLER_2D_RECT_EXT = $8DCD;
-  GL_INT_SAMPLER_1D_ARRAY_EXT = $8DCE;
-  GL_INT_SAMPLER_2D_ARRAY_EXT = $8DCF;
-  GL_INT_SAMPLER_BUFFER_EXT = $8DD0;
-  GL_UNSIGNED_INT_SAMPLER_1D_EXT = $8DD1;
-  GL_UNSIGNED_INT_SAMPLER_2D_EXT = $8DD2;
-  GL_UNSIGNED_INT_SAMPLER_3D_EXT = $8DD3;
-  GL_UNSIGNED_INT_SAMPLER_CUBE_EXT = $8DD4;
-  GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT = $8DD5;
-  GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT = $8DD6;
-  GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT = $8DD7;
-  GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT = $8DD8;
-  GL_MIN_PROGRAM_TEXEL_OFFSET_EXT = $8904;
-  GL_MAX_PROGRAM_TEXEL_OFFSET_EXT = $8905;
-
-  // GL_EXT_packed_float
-  GL_R11F_G11F_B10F_EXT = $8C3A;
-  GL_UNSIGNED_INT_10F_11F_11F_REV_EXT = $8C3B;
-  RGBA_SIGNED_COMPONENTS_EXT = $8C3C;
-  WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT = $20A8;
-  GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT = $20B1;
-  GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT = $00000008;
-
-  // GL_EXT_texture_array
-  GL_TEXTURE_1D_ARRAY_EXT = $8C18;
-  GL_TEXTURE_2D_ARRAY_EXT = $8C1A;
-  GL_PROXY_TEXTURE_2D_ARRAY_EXT = $8C1B;
-  GL_PROXY_TEXTURE_1D_ARRAY_EXT = $8C19;
-  GL_TEXTURE_BINDING_1D_ARRAY_EXT = $8C1C;
-  GL_TEXTURE_BINDING_2D_ARRAY_EXT = $8C1D;
-  GL_MAX_ARRAY_TEXTURE_LAYERS_EXT = $88FF;
-  GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT = $884E;
-
-  // GL_EXT_texture_buffer_object
-  GL_TEXTURE_BUFFER_EXT = $8C2A;
-  GL_MAX_TEXTURE_BUFFER_SIZE_EXT = $8C2B;
-  GL_TEXTURE_BINDING_BUFFER_EXT = $8C2C;
-  GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT = $8C2D;
-  GL_TEXTURE_BUFFER_FORMAT_EXT = $8C2E;
-
-  // GL_EXT_texture_compression_latc
-  GL_COMPRESSED_LUMINANCE_LATC1_EXT = $8C70;
-  GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = $8C71;
-  GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = $8C72;
-  GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = $8C73;
-
-  // GL_EXT_texture_compression_rgtc
-  GL_COMPRESSED_RED_RGTC1_EXT = $8DBB;
-  GL_COMPRESSED_SIGNED_RED_RGTC1_EXT = $8DBC;
-  GL_COMPRESSED_RED_GREEN_RGTC2_EXT = $8DBD;
-  GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = $8DBE;
-
-  // GL_EXT_texture_integer
-  GL_RGBA_INTEGER_MODE_EXT = $8D9E;
-  GL_RGBA32UI_EXT = $8D70;
-  GL_RGB32UI_EXT = $8D71;
-  GL_ALPHA32UI_EXT = $8D72;
-  GL_INTENSITY32UI_EXT = $8D73;
-  GL_LUMINANCE32UI_EXT = $8D74;
-  GL_LUMINANCE_ALPHA32UI_EXT = $8D75;
-  GL_RGBA16UI_EXT = $8D76;
-  GL_RGB16UI_EXT = $8D77;
-  GL_ALPHA16UI_EXT = $8D78;
-  GL_INTENSITY16UI_EXT = $8D79;
-  GL_LUMINANCE16UI_EXT = $8D7A;
-  GL_LUMINANCE_ALPHA16UI_EXT = $8D7B;
-  GL_RGBA8UI_EXT = $8D7C;
-  GL_RGB8UI_EXT = $8D7D;
-  GL_ALPHA8UI_EXT = $8D7E;
-  GL_INTENSITY8UI_EXT = $8D7F;
-  GL_LUMINANCE8UI_EXT = $8D80;
-  GL_LUMINANCE_ALPHA8UI_EXT = $8D81;
-  GL_RGBA32I_EXT = $8D82;
-  GL_RGB32I_EXT = $8D83;
-  GL_ALPHA32I_EXT = $8D84;
-  GL_INTENSITY32I_EXT = $8D85;
-  GL_LUMINANCE32I_EXT = $8D86;
-  GL_LUMINANCE_ALPHA32I_EXT = $8D87;
-  GL_RGBA16I_EXT = $8D88;
-  GL_RGB16I_EXT = $8D89;
-  GL_ALPHA16I_EXT = $8D8A;
-  GL_INTENSITY16I_EXT = $8D8B;
-  GL_LUMINANCE16I_EXT = $8D8C;
-  GL_LUMINANCE_ALPHA16I_EXT = $8D8D;
-  GL_RGBA8I_EXT = $8D8E;
-  GL_RGB8I_EXT = $8D8F;
-  GL_ALPHA8I_EXT = $8D90;
-  GL_INTENSITY8I_EXT = $8D91;
-  GL_LUMINANCE8I_EXT = $8D92;
-  GL_LUMINANCE_ALPHA8I_EXT = $8D93;
-  GL_RED_INTEGER_EXT = $8D94;
-  GL_GREEN_INTEGER_EXT = $8D95;
-  GL_BLUE_INTEGER_EXT = $8D96;
-  GL_ALPHA_INTEGER_EXT = $8D97;
-  GL_RGB_INTEGER_EXT = $8D98;
-  GL_RGBA_INTEGER_EXT = $8D99;
-  GL_BGR_INTEGER_EXT = $8D9A;
-  GL_BGRA_INTEGER_EXT = $8D9B;
-  GL_LUMINANCE_INTEGER_EXT = $8D9C;
-  GL_LUMINANCE_ALPHA_INTEGER_EXT = $8D9D;
-
-  // GL_EXT_texture_shared_exponent
-  GL_RGB9_E5_EXT = $8C3D;
-  GL_UNSIGNED_INT_5_9_9_9_REV_EXT = $8C3E;
-  GL_TEXTURE_SHARED_SIZE_EXT = $8C3F;
-
-  // GL_EXT_transform_feedback
-  GL_TRANSFORM_FEEDBACK_BUFFER_EXT = $8C8E;
-  GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT = $8C84;
-  GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT = $8C85;
-  GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT = $8C8F;
-  GL_INTERLEAVED_ATTRIBS_EXT = $8C8C;
-  GL_SEPARATE_ATTRIBS_EXT = $8C8D;
-  GL_PRIMITIVES_GENERATED_EXT = $8C87;
-  GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT = $8C88;
-  GL_RASTERIZER_DISCARD_EXT = $8C89;
-  GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT = $8C8A;
-  GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT = $8C8B;
-  GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT = $8C80;
-  GL_TRANSFORM_FEEDBACK_VARYINGS_EXT = $8C83;
-  GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT = $8C7F;
-  GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT = $8C76;
-
-  // GL_EXT_direct_state_access
-  GL_PROGRAM_MATRIX_EXT = $8E2D;
-  GL_TRANSPOSE_PROGRAM_MATRIX_EXT = $8E2E;
-  GL_PROGRAM_MATRIX_STACK_DEPTH_EXT = $8E2F;
-
-  // GL_EXT_texture_swizzle
-  GL_TEXTURE_SWIZZLE_R_EXT = $8E42;
-  GL_TEXTURE_SWIZZLE_G_EXT = $8E43;
-  GL_TEXTURE_SWIZZLE_B_EXT = $8E44;
-  GL_TEXTURE_SWIZZLE_A_EXT = $8E45;
-  GL_TEXTURE_SWIZZLE_RGBA_EXT = $8E46;
-
-  // GL_EXT_provoking_vertex
-  GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT = $8E4C;
-  GL_FIRST_VERTEX_CONVENTION_EXT = $8E4D;
-  GL_LAST_VERTEX_CONVENTION_EXT = $8E4E;
-  GL_PROVOKING_VERTEX_EXT = $8E4F;
-  
-  // GL_EXT_texture_snorm
-  GL_ALPHA_SNORM = $9010;
-  GL_LUMINANCE_SNORM = $9011;
-  GL_LUMINANCE_ALPHA_SNORM = $9012;
-  GL_INTENSITY_SNORM = $9013;
-  GL_ALPHA8_SNORM = $9014;
-  GL_LUMINANCE8_SNORM = $9015;
-  GL_LUMINANCE8_ALPHA8_SNORM = $9016;
-  GL_INTENSITY8_SNORM = $9017;
-  GL_ALPHA16_SNORM = $9018;
-  GL_LUMINANCE16_SNORM = $9019;
-  GL_LUMINANCE16_ALPHA16_SNORM = $901A;
-  GL_INTENSITY16_SNORM = $901B;
-  { reuse GL_R_SNORM }
-  { reuse GL_RG_SNORM }
-  { reuse GL_RGB_SNORM }
-  { reuse GL_RGBA_SNORM }
-  { reuse GL_R8_SNORM }
-  { reuse GL_RG8_SNORM }
-  { reuse GL_RGB8_SNORM }
-  { reuse GL_RGBA8_SNORM }
-  { reuse GL_R16_SNORM }
-  { reuse GL_RG16_SNORM }
-  { reuse GL_RGB16_SNORM }
-  { reuse GL_RGBA16_SNORM }
-  { reuse GL_SIGNED_NORMALIZED }
-  
-  // GL_FfdMaskSGIX
-  GL_TEXTURE_DEFORMATION_BIT_SGIX = $00000001;
-  GL_GEOMETRY_DEFORMATION_BIT_SGIX = $00000002;
-
-  // GL_HP_convolution_border_modes
-  GL_IGNORE_BORDER_HP = $8150;
-  GL_CONSTANT_BORDER_HP = $8151;
-  GL_REPLICATE_BORDER_HP = $8153;
-  GL_CONVOLUTION_BORDER_COLOR_HP = $8154;
-
-  // GL_HP_image_transform
-  GL_IMAGE_SCALE_X_HP = $8155;
-  GL_IMAGE_SCALE_Y_HP = $8156;
-  GL_IMAGE_TRANSLATE_X_HP = $8157;
-  GL_IMAGE_TRANSLATE_Y_HP = $8158;
-  GL_IMAGE_ROTATE_ANGLE_HP = $8159;
-  GL_IMAGE_ROTATE_ORIGIN_X_HP = $815A;
-  GL_IMAGE_ROTATE_ORIGIN_Y_HP = $815B;
-  GL_IMAGE_MAG_FILTER_HP = $815C;
-  GL_IMAGE_MIN_FILTER_HP = $815D;
-  GL_IMAGE_CUBIC_WEIGHT_HP = $815E;
-  GL_CUBIC_HP = $815F;
-  GL_AVERAGE_HP = $8160;
-  GL_IMAGE_TRANSFORM_2D_HP = $8161;
-  GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP = $8162;
-  GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP = $8163;
-
-  // GL_HP_occlusion_test
-  GL_OCCLUSION_TEST_HP = $8165;
-  GL_OCCLUSION_TEST_RESULT_HP = $8166;
-
-  // GL_HP_texture_lighting
-  GL_TEXTURE_LIGHTING_MODE_HP = $8167;
-  GL_TEXTURE_POST_SPECULAR_HP = $8168;
-  GL_TEXTURE_PRE_SPECULAR_HP = $8169;
-
-  // GL_IBM_cull_vertex
-  GL_CULL_VERTEX_IBM = 103050;
-
-  // GL_IBM_rasterpos_clip
-  GL_RASTER_POSITION_UNCLIPPED_IBM = $19262;
-
-  // GL_IBM_texture_mirrored_repeat
-  GL_MIRRORED_REPEAT_IBM = $8370;
-
-  // GL_IBM_vertex_array_lists
-  GL_VERTEX_ARRAY_LIST_IBM = 103070;
-  GL_NORMAL_ARRAY_LIST_IBM = 103071;
-  GL_COLOR_ARRAY_LIST_IBM = 103072;
-  GL_INDEX_ARRAY_LIST_IBM = 103073;
-  GL_TEXTURE_COORD_ARRAY_LIST_IBM = 103074;
-  GL_EDGE_FLAG_ARRAY_LIST_IBM = 103075;
-  GL_FOG_COORDINATE_ARRAY_LIST_IBM = 103076;
-  GL_SECONDARY_COLOR_ARRAY_LIST_IBM = 103077;
-  GL_VERTEX_ARRAY_LIST_STRIDE_IBM = 103080;
-  GL_NORMAL_ARRAY_LIST_STRIDE_IBM = 103081;
-  GL_COLOR_ARRAY_LIST_STRIDE_IBM = 103082;
-  GL_INDEX_ARRAY_LIST_STRIDE_IBM = 103083;
-  GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM = 103084;
-  GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM = 103085;
-  GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM = 103086;
-  GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM = 103087;
-
-  // GL_INGR_color_clamp
-  GL_RED_MIN_CLAMP_INGR = $8560;
-  GL_GREEN_MIN_CLAMP_INGR = $8561;
-  GL_BLUE_MIN_CLAMP_INGR = $8562;
-  GL_ALPHA_MIN_CLAMP_INGR = $8563;
-  GL_RED_MAX_CLAMP_INGR = $8564;
-  GL_GREEN_MAX_CLAMP_INGR = $8565;
-  GL_BLUE_MAX_CLAMP_INGR = $8566;
-  GL_ALPHA_MAX_CLAMP_INGR = $8567;
-
-  // GL_INGR_interlace_read
-  GL_INTERLACE_READ_INGR = $8568;
-
-  // GL_INTEL_parallel_arrays
-  GL_PARALLEL_ARRAYS_INTEL = $83F4;
-  GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL = $83F5;
-  GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL = $83F6;
-  GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL = $83F7;
-  GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL = $83F8;
-
-  // GL_NV_copy_depth_to_color
-  GL_DEPTH_STENCIL_TO_RGBA_NV = $886E;
-  GL_DEPTH_STENCIL_TO_BGRA_NV = $886F;
-
-  // GL_NV_depth_clamp
-  GL_DEPTH_CLAMP_NV = $864F;
-
-  // GL_NV_evaluators
-  GL_EVAL_2D_NV = $86C0;
-  GL_EVAL_TRIANGULAR_2D_NV = $86C1;
-  GL_MAP_TESSELLATION_NV = $86C2;
-  GL_MAP_ATTRIB_U_ORDER_NV = $86C3;
-  GL_MAP_ATTRIB_V_ORDER_NV = $86C4;
-  GL_EVAL_FRACTIONAL_TESSELLATION_NV = $86C5;
-  GL_EVAL_VERTEX_ATTRIB0_NV = $86C6;
-  GL_EVAL_VERTEX_ATTRIB1_NV = $86C7;
-  GL_EVAL_VERTEX_ATTRIB2_NV = $86C8;
-  GL_EVAL_VERTEX_ATTRIB3_NV = $86C9;
-  GL_EVAL_VERTEX_ATTRIB4_NV = $86CA;
-  GL_EVAL_VERTEX_ATTRIB5_NV = $86CB;
-  GL_EVAL_VERTEX_ATTRIB6_NV = $86CC;
-  GL_EVAL_VERTEX_ATTRIB7_NV = $86CD;
-  GL_EVAL_VERTEX_ATTRIB8_NV = $86CE;
-  GL_EVAL_VERTEX_ATTRIB9_NV = $86CF;
-  GL_EVAL_VERTEX_ATTRIB10_NV = $86D0;
-  GL_EVAL_VERTEX_ATTRIB11_NV = $86D1;
-  GL_EVAL_VERTEX_ATTRIB12_NV = $86D2;
-  GL_EVAL_VERTEX_ATTRIB13_NV = $86D3;
-  GL_EVAL_VERTEX_ATTRIB14_NV = $86D4;
-  GL_EVAL_VERTEX_ATTRIB15_NV = $86D5;
-  GL_MAX_MAP_TESSELLATION_NV = $86D6;
-  GL_MAX_RATIONAL_EVAL_ORDER_NV = $86D7;
-
-  // GL_NV_fence
-  GL_ALL_COMPLETED_NV = $84F2;
-  GL_FENCE_STATUS_NV = $84F3;
-  GL_FENCE_CONDITION_NV = $84F4;
-
-  // GL_NV_float_buffer
-  GL_FLOAT_R_NV = $8880;
-  GL_FLOAT_RG_NV = $8881;
-  GL_FLOAT_RGB_NV = $8882;
-  GL_FLOAT_RGBA_NV = $8883;
-  GL_FLOAT_R16_NV = $8884;
-  GL_FLOAT_R32_NV = $8885;
-  GL_FLOAT_RG16_NV = $8886;
-  GL_FLOAT_RG32_NV = $8887;
-  GL_FLOAT_RGB16_NV = $8888;
-  GL_FLOAT_RGB32_NV = $8889;
-  GL_FLOAT_RGBA16_NV = $888A;
-  GL_FLOAT_RGBA32_NV = $888B;
-  GL_TEXTURE_FLOAT_COMPONENTS_NV = $888C;
-  GL_FLOAT_CLEAR_COLOR_VALUE_NV = $888D;
-  GL_FLOAT_RGBA_MODE_NV = $888E;
-
-  // GL_NV_fog_distance
-  GL_FOG_DISTANCE_MODE_NV = $855A;
-  GL_EYE_RADIAL_NV = $855B;
-  GL_EYE_PLANE_ABSOLUTE_NV = $855C;
-
-  // GL_NV_fragment_program
-  GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV = $8868;
-  GL_FRAGMENT_PROGRAM_NV = $8870;
-  GL_MAX_TEXTURE_COORDS_NV = $8871;
-  GL_MAX_TEXTURE_IMAGE_UNITS_NV = $8872;
-  GL_FRAGMENT_PROGRAM_BINDING_NV = $8873;
-  GL_PROGRAM_ERROR_STRING_NV = $8874;
-
-  // GL_NV_half_float
-  GL_HALF_FLOAT_NV = $140B;
-
-  // GL_NV_light_max_exponent
-  GL_MAX_SHININESS_NV = $8504;
-  GL_MAX_SPOT_EXPONENT_NV = $8505;
-
-  // GL_NV_multisample_filter_hint
-  GL_MULTISAMPLE_FILTER_HINT_NV = $8534;
-
-  // GL_NV_occlusion_query
-  GL_PIXEL_COUNTER_BITS_NV = $8864;
-  GL_CURRENT_OCCLUSION_QUERY_ID_NV = $8865;
-  GL_PIXEL_COUNT_NV = $8866;
-  GL_PIXEL_COUNT_AVAILABLE_NV = $8867;
-
-  // GL_NV_packed_depth_stencil
-  GL_DEPTH_STENCIL_NV = $84F9;
-  GL_UNSIGNED_INT_24_8_NV = $84FA;
-
-  // GL_NV_pixel_data_range
-  GL_WRITE_PIXEL_DATA_RANGE_NV = $8878;
-  GL_READ_PIXEL_DATA_RANGE_NV = $8879;
-  GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV = $887A;
-  GL_READ_PIXEL_DATA_RANGE_LENGTH_NV = $887B;
-  GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV = $887C;
-  GL_READ_PIXEL_DATA_RANGE_POINTER_NV = $887D;
-
-  // GL_NV_point_sprite
-  GL_POINT_SPRITE_NV = $8861;
-  GL_COORD_REPLACE_NV = $8862;
-  GL_POINT_SPRITE_R_MODE_NV = $8863;
-
-  // GL_NV_primitive_restart
-  GL_PRIMITIVE_RESTART_NV = $8558;
-  GL_PRIMITIVE_RESTART_INDEX_NV = $8559;
-
-  // GL_NV_register_combiners
-  GL_REGISTER_COMBINERS_NV = $8522;
-  GL_VARIABLE_A_NV = $8523;
-  GL_VARIABLE_B_NV = $8524;
-  GL_VARIABLE_C_NV = $8525;
-  GL_VARIABLE_D_NV = $8526;
-  GL_VARIABLE_E_NV = $8527;
-  GL_VARIABLE_F_NV = $8528;
-  GL_VARIABLE_G_NV = $8529;
-  GL_CONSTANT_COLOR0_NV = $852A;
-  GL_CONSTANT_COLOR1_NV = $852B;
-  GL_PRIMARY_COLOR_NV = $852C;
-  GL_SECONDARY_COLOR_NV = $852D;
-  GL_SPARE0_NV = $852E;
-  GL_SPARE1_NV = $852F;
-  GL_DISCARD_NV = $8530;
-  GL_E_TIMES_F_NV = $8531;
-  GL_SPARE0_PLUS_SECONDARY_COLOR_NV = $8532;
-  GL_UNSIGNED_IDENTITY_NV = $8536;
-  GL_UNSIGNED_INVERT_NV = $8537;
-  GL_EXPAND_NORMAL_NV = $8538;
-  GL_EXPAND_NEGATE_NV = $8539;
-  GL_HALF_BIAS_NORMAL_NV = $853A;
-  GL_HALF_BIAS_NEGATE_NV = $853B;
-  GL_SIGNED_IDENTITY_NV = $853C;
-  GL_SIGNED_NEGATE_NV = $853D;
-  GL_SCALE_BY_TWO_NV = $853E;
-  GL_SCALE_BY_FOUR_NV = $853F;
-  GL_SCALE_BY_ONE_HALF_NV = $8540;
-  GL_BIAS_BY_NEGATIVE_ONE_HALF_NV = $8541;
-  GL_COMBINER_INPUT_NV = $8542;
-  GL_COMBINER_MAPPING_NV = $8543;
-  GL_COMBINER_COMPONENT_USAGE_NV = $8544;
-  GL_COMBINER_AB_DOT_PRODUCT_NV = $8545;
-  GL_COMBINER_CD_DOT_PRODUCT_NV = $8546;
-  GL_COMBINER_MUX_SUM_NV = $8547;
-  GL_COMBINER_SCALE_NV = $8548;
-  GL_COMBINER_BIAS_NV = $8549;
-  GL_COMBINER_AB_OUTPUT_NV = $854A;
-  GL_COMBINER_CD_OUTPUT_NV = $854B;
-  GL_COMBINER_SUM_OUTPUT_NV = $854C;
-  GL_MAX_GENERAL_COMBINERS_NV = $854D;
-  GL_NUM_GENERAL_COMBINERS_NV = $854E;
-  GL_COLOR_SUM_CLAMP_NV = $854F;
-  GL_COMBINER0_NV = $8550;
-  GL_COMBINER1_NV = $8551;
-  GL_COMBINER2_NV = $8552;
-  GL_COMBINER3_NV = $8553;
-  GL_COMBINER4_NV = $8554;
-  GL_COMBINER5_NV = $8555;
-  GL_COMBINER6_NV = $8556;
-  GL_COMBINER7_NV = $8557;
-
-  // GL_NV_register_combiners2
-  GL_PER_STAGE_CONSTANTS_NV = $8535;
-
-  // GL_NV_texgen_emboss
-  GL_EMBOSS_LIGHT_NV = $855D;
-  GL_EMBOSS_CONSTANT_NV = $855E;
-  GL_EMBOSS_MAP_NV = $855F;
-
-  // GL_NV_texgen_reflection
-  GL_NORMAL_MAP_NV = $8511;
-  GL_REFLECTION_MAP_NV = $8512;
-
-  // GL_NV_texture_env_combine4
-  GL_COMBINE4_NV = $8503;
-  GL_SOURCE3_RGB_NV = $8583;
-  GL_SOURCE3_ALPHA_NV = $858B;
-  GL_OPERAND3_RGB_NV = $8593;
-  GL_OPERAND3_ALPHA_NV = $859B;
-
-  // GL_NV_texture_expand_normal
-  GL_TEXTURE_UNSIGNED_REMAP_MODE_NV = $888F;
-
-  // GL_NV_texture_rectangle
-  GL_TEXTURE_RECTANGLE_NV = $84F5;
-  GL_TEXTURE_BINDING_RECTANGLE_NV = $84F6;
-  GL_PROXY_TEXTURE_RECTANGLE_NV = $84F7;
-  GL_MAX_RECTANGLE_TEXTURE_SIZE_NV = $84F8;
-
-  // GL_NV_texture_shader
-  GL_OFFSET_TEXTURE_RECTANGLE_NV = $864C;
-  GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV = $864D;
-  GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV = $864E;
-  GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV = $86D9;
-  GL_UNSIGNED_INT_S8_S8_8_8_NV = $86DA;
-  GL_UNSIGNED_INT_8_8_S8_S8_REV_NV = $86DB;
-  GL_DSDT_MAG_INTENSITY_NV = $86DC;
-  GL_SHADER_CONSISTENT_NV = $86DD;
-  GL_TEXTURE_SHADER_NV = $86DE;
-  GL_SHADER_OPERATION_NV = $86DF;
-  GL_CULL_MODES_NV = $86E0;
-  GL_OFFSET_TEXTURE_MATRIX_NV = $86E1;
-  GL_OFFSET_TEXTURE_SCALE_NV = $86E2;
-  GL_OFFSET_TEXTURE_BIAS_NV = $86E3;
-  GL_OFFSET_TEXTURE_2D_MATRIX_NV = GL_OFFSET_TEXTURE_MATRIX_NV;
-  GL_OFFSET_TEXTURE_2D_SCALE_NV = GL_OFFSET_TEXTURE_SCALE_NV;
-  GL_OFFSET_TEXTURE_2D_BIAS_NV = GL_OFFSET_TEXTURE_BIAS_NV;
-  GL_PREVIOUS_TEXTURE_INPUT_NV = $86E4;
-  GL_CONST_EYE_NV = $86E5;
-  GL_PASS_THROUGH_NV = $86E6;
-  GL_CULL_FRAGMENT_NV = $86E7;
-  GL_OFFSET_TEXTURE_2D_NV = $86E8;
-  GL_DEPENDENT_AR_TEXTURE_2D_NV = $86E9;
-  GL_DEPENDENT_GB_TEXTURE_2D_NV = $86EA;
-  GL_DOT_PRODUCT_NV = $86EC;
-  GL_DOT_PRODUCT_DEPTH_REPLACE_NV = $86ED;
-  GL_DOT_PRODUCT_TEXTURE_2D_NV = $86EE;
-  GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV = $86F0;
-  GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV = $86F1;
-  GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV = $86F2;
-  GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV = $86F3;
-  GL_HILO_NV = $86F4;
-  GL_DSDT_NV = $86F5;
-  GL_DSDT_MAG_NV = $86F6;
-  GL_DSDT_MAG_VIB_NV = $86F7;
-  GL_HILO16_NV = $86F8;
-  GL_SIGNED_HILO_NV = $86F9;
-  GL_SIGNED_HILO16_NV = $86FA;
-  GL_SIGNED_RGBA_NV = $86FB;
-  GL_SIGNED_RGBA8_NV = $86FC;
-  GL_SIGNED_RGB_NV = $86FE;
-  GL_SIGNED_RGB8_NV = $86FF;
-  GL_SIGNED_LUMINANCE_NV = $8701;
-  GL_SIGNED_LUMINANCE8_NV = $8702;
-  GL_SIGNED_LUMINANCE_ALPHA_NV = $8703;
-  GL_SIGNED_LUMINANCE8_ALPHA8_NV = $8704;
-  GL_SIGNED_ALPHA_NV = $8705;
-  GL_SIGNED_ALPHA8_NV = $8706;
-  GL_SIGNED_INTENSITY_NV = $8707;
-  GL_SIGNED_INTENSITY8_NV = $8708;
-  GL_DSDT8_NV = $8709;
-  GL_DSDT8_MAG8_NV = $870A;
-  GL_DSDT8_MAG8_INTENSITY8_NV = $870B;
-  GL_SIGNED_RGB_UNSIGNED_ALPHA_NV = $870C;
-  GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV = $870D;
-  GL_HI_SCALE_NV = $870E;
-  GL_LO_SCALE_NV = $870F;
-  GL_DS_SCALE_NV = $8710;
-  GL_DT_SCALE_NV = $8711;
-  GL_MAGNITUDE_SCALE_NV = $8712;
-  GL_VIBRANCE_SCALE_NV = $8713;
-  GL_HI_BIAS_NV = $8714;
-  GL_LO_BIAS_NV = $8715;
-  GL_DS_BIAS_NV = $8716;
-  GL_DT_BIAS_NV = $8717;
-  GL_MAGNITUDE_BIAS_NV = $8718;
-  GL_VIBRANCE_BIAS_NV = $8719;
-  GL_TEXTURE_BORDER_VALUES_NV = $871A;
-  GL_TEXTURE_HI_SIZE_NV = $871B;
-  GL_TEXTURE_LO_SIZE_NV = $871C;
-  GL_TEXTURE_DS_SIZE_NV = $871D;
-  GL_TEXTURE_DT_SIZE_NV = $871E;
-  GL_TEXTURE_MAG_SIZE_NV = $871F;
-
-  // GL_NV_texture_shader2
-  GL_DOT_PRODUCT_TEXTURE_3D_NV = $86EF;
-
-  // GL_NV_texture_shader3
-  GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV = $8850;
-  GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV = $8851;
-  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV = $8852;
-  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV = $8853;
-  GL_OFFSET_HILO_TEXTURE_2D_NV = $8854;
-  GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV = $8855;
-  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV = $8856;
-  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV = $8857;
-  GL_DEPENDENT_HILO_TEXTURE_2D_NV = $8858;
-  GL_DEPENDENT_RGB_TEXTURE_3D_NV = $8859;
-  GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV = $885A;
-  GL_DOT_PRODUCT_PASS_THROUGH_NV = $885B;
-  GL_DOT_PRODUCT_TEXTURE_1D_NV = $885C;
-  GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV = $885D;
-  GL_HILO8_NV = $885E;
-  GL_SIGNED_HILO8_NV = $885F;
-  GL_FORCE_BLUE_TO_ONE_NV = $8860;
-
-  // GL_NV_vertex_array_range
-  GL_VERTEX_ARRAY_RANGE_NV = $851D;
-  GL_VERTEX_ARRAY_RANGE_LENGTH_NV = $851E;
-  GL_VERTEX_ARRAY_RANGE_VALID_NV = $851F;
-  GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV = $8520;
-  GL_VERTEX_ARRAY_RANGE_POINTER_NV = $8521;
-
-  // GL_NV_vertex_array_range2
-  GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV = $8533;
-
-  // GL_NV_vertex_program
-  GL_VERTEX_PROGRAM_NV = $8620;
-  GL_VERTEX_STATE_PROGRAM_NV = $8621;
-  GL_ATTRIB_ARRAY_SIZE_NV = $8623;
-  GL_ATTRIB_ARRAY_STRIDE_NV = $8624;
-  GL_ATTRIB_ARRAY_TYPE_NV = $8625;
-  GL_CURRENT_ATTRIB_NV = $8626;
-  GL_PROGRAM_LENGTH_NV = $8627;
-  GL_PROGRAM_STRING_NV = $8628;
-  GL_MODELVIEW_PROJECTION_NV = $8629;
-  GL_IDENTITY_NV = $862A;
-  GL_INVERSE_NV = $862B;
-  GL_TRANSPOSE_NV = $862C;
-  GL_INVERSE_TRANSPOSE_NV = $862D;
-  GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV = $862E;
-  GL_MAX_TRACK_MATRICES_NV = $862F;
-  GL_MATRIX0_NV = $8630;
-  GL_MATRIX1_NV = $8631;
-  GL_MATRIX2_NV = $8632;
-  GL_MATRIX3_NV = $8633;
-  GL_MATRIX4_NV = $8634;
-  GL_MATRIX5_NV = $8635;
-  GL_MATRIX6_NV = $8636;
-  GL_MATRIX7_NV = $8637;
-  GL_CURRENT_MATRIX_STACK_DEPTH_NV = $8640;
-  GL_CURRENT_MATRIX_NV = $8641;
-  GL_VERTEX_PROGRAM_POINT_SIZE_NV = $8642;
-  GL_VERTEX_PROGRAM_TWO_SIDE_NV = $8643;
-  GL_PROGRAM_PARAMETER_NV = $8644;
-  GL_ATTRIB_ARRAY_POINTER_NV = $8645;
-  GL_PROGRAM_TARGET_NV = $8646;
-  GL_PROGRAM_RESIDENT_NV = $8647;
-  GL_TRACK_MATRIX_NV = $8648;
-  GL_TRACK_MATRIX_TRANSFORM_NV = $8649;
-  GL_VERTEX_PROGRAM_BINDING_NV = $864A;
-  GL_PROGRAM_ERROR_POSITION_NV = $864B;
-  GL_VERTEX_ATTRIB_ARRAY0_NV = $8650;
-  GL_VERTEX_ATTRIB_ARRAY1_NV = $8651;
-  GL_VERTEX_ATTRIB_ARRAY2_NV = $8652;
-  GL_VERTEX_ATTRIB_ARRAY3_NV = $8653;
-  GL_VERTEX_ATTRIB_ARRAY4_NV = $8654;
-  GL_VERTEX_ATTRIB_ARRAY5_NV = $8655;
-  GL_VERTEX_ATTRIB_ARRAY6_NV = $8656;
-  GL_VERTEX_ATTRIB_ARRAY7_NV = $8657;
-  GL_VERTEX_ATTRIB_ARRAY8_NV = $8658;
-  GL_VERTEX_ATTRIB_ARRAY9_NV = $8659;
-  GL_VERTEX_ATTRIB_ARRAY10_NV = $865A;
-  GL_VERTEX_ATTRIB_ARRAY11_NV = $865B;
-  GL_VERTEX_ATTRIB_ARRAY12_NV = $865C;
-  GL_VERTEX_ATTRIB_ARRAY13_NV = $865D;
-  GL_VERTEX_ATTRIB_ARRAY14_NV = $865E;
-  GL_VERTEX_ATTRIB_ARRAY15_NV = $865F;
-  GL_MAP1_VERTEX_ATTRIB0_4_NV = $8660;
-  GL_MAP1_VERTEX_ATTRIB1_4_NV = $8661;
-  GL_MAP1_VERTEX_ATTRIB2_4_NV = $8662;
-  GL_MAP1_VERTEX_ATTRIB3_4_NV = $8663;
-  GL_MAP1_VERTEX_ATTRIB4_4_NV = $8664;
-  GL_MAP1_VERTEX_ATTRIB5_4_NV = $8665;
-  GL_MAP1_VERTEX_ATTRIB6_4_NV = $8666;
-  GL_MAP1_VERTEX_ATTRIB7_4_NV = $8667;
-  GL_MAP1_VERTEX_ATTRIB8_4_NV = $8668;
-  GL_MAP1_VERTEX_ATTRIB9_4_NV = $8669;
-  GL_MAP1_VERTEX_ATTRIB10_4_NV = $866A;
-  GL_MAP1_VERTEX_ATTRIB11_4_NV = $866B;
-  GL_MAP1_VERTEX_ATTRIB12_4_NV = $866C;
-  GL_MAP1_VERTEX_ATTRIB13_4_NV = $866D;
-  GL_MAP1_VERTEX_ATTRIB14_4_NV = $866E;
-  GL_MAP1_VERTEX_ATTRIB15_4_NV = $866F;
-  GL_MAP2_VERTEX_ATTRIB0_4_NV = $8670;
-  GL_MAP2_VERTEX_ATTRIB1_4_NV = $8671;
-  GL_MAP2_VERTEX_ATTRIB2_4_NV = $8672;
-  GL_MAP2_VERTEX_ATTRIB3_4_NV = $8673;
-  GL_MAP2_VERTEX_ATTRIB4_4_NV = $8674;
-  GL_MAP2_VERTEX_ATTRIB5_4_NV = $8675;
-  GL_MAP2_VERTEX_ATTRIB6_4_NV = $8676;
-  GL_MAP2_VERTEX_ATTRIB7_4_NV = $8677;
-  GL_MAP2_VERTEX_ATTRIB8_4_NV = $8678;
-  GL_MAP2_VERTEX_ATTRIB9_4_NV = $8679;
-  GL_MAP2_VERTEX_ATTRIB10_4_NV = $867A;
-  GL_MAP2_VERTEX_ATTRIB11_4_NV = $867B;
-  GL_MAP2_VERTEX_ATTRIB12_4_NV = $867C;
-  GL_MAP2_VERTEX_ATTRIB13_4_NV = $867D;
-  GL_MAP2_VERTEX_ATTRIB14_4_NV = $867E;
-  GL_MAP2_VERTEX_ATTRIB15_4_NV = $867F;
-
-  // GL_NV_fragment_program2 and GL_NV_vertex_program2_option
-  GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV = $88F4;
-  GL_MAX_PROGRAM_CALL_DEPTH_NV = $88F5;
-
-  // GL_NV_fragment_program2
-  GL_MAX_PROGRAM_IF_DEPTH_NV = $88F6;
-  GL_MAX_PROGRAM_LOOP_DEPTH_NV = $88F7;
-  GL_MAX_PROGRAM_LOOP_COUNT_NV = $88F8;
-
-  // GL_NV_vertex_program3
-  MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB = $8B4C;
-
-  // GL_NV_depth_buffer_float
-  GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV = $8DAD;
-  GL_DEPTH_BUFFER_FLOAT_MODE_NV = $8DAF;
-
-  // GL_NV_framebuffer_multisample_coverage
-  GL_RENDERBUFFER_COVERAGE_SAMPLES_NV = $8CAB;
-  GL_RENDERBUFFER_COLOR_SAMPLES_NV = $8E10;
-
-  // GL_NV_geometry_program4
-  GL_GEOMETRY_PROGRAM_NV = $8C26;
-  GL_MAX_PROGRAM_OUTPUT_VERTICES_NV = $8C27;
-  GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV = $8C28;
-
-  // GL_NV_gpu_program4
-  GL_PROGRAM_ATTRIB_COMPONENTS_NV = $8906;
-  GL_PROGRAM_RESULT_COMPONENTS_NV = $8907;
-  GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV = $8908;
-  GL_MAX_PROGRAM_RESULT_COMPONENTS_NV = $8909;
-  GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV = $8DA5;
-  GL_MAX_PROGRAM_GENERIC_RESULTS_NV = $8DA6;
-
-  // GL_NV_parameter_buffer_object
-  GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV = $8DA0;
-  GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV = $8DA1;
-  GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV = $8DA2;
-  GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV = $8DA3;
-  GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV = $8DA4;
-
-  // GL_NV_transform_feedback
-  GL_TRANSFORM_FEEDBACK_BUFFER_NV = $8C8E;
-  GL_TRANSFORM_FEEDBACK_BUFFER_START_NV = $8C84;
-  GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV = $8C85;
-  GL_TRANSFORM_FEEDBACK_RECORD_NV = $8C86;
-  GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV = $8C8F;
-  GL_INTERLEAVED_ATTRIBS_NV = $8C8C;
-  GL_SEPARATE_ATTRIBS_NV = $8C8D;
-  GL_PRIMITIVES_GENERATED_NV = $8C87;
-  GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV = $8C88;
-  GL_RASTERIZER_DISCARD_NV = $8C89;
-  GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV = $8C8A;
-  GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV = $8C8B;
-  GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV = $8C80;
-  GL_TRANSFORM_FEEDBACK_ATTRIBS_NV = $8C7E;
-  GL_ACTIVE_VARYINGS_NV = $8C81;
-  GL_ACTIVE_VARYING_MAX_LENGTH_NV = $8C82;
-  GL_TRANSFORM_FEEDBACK_VARYINGS_NV = $8C83;
-  GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV = $8C7F;
-  GL_BACK_PRIMARY_COLOR_NV = $8C77;
-  GL_BACK_SECONDARY_COLOR_NV = $8C78;
-  GL_TEXTURE_COORD_NV = $8C79;
-  GL_CLIP_DISTANCE_NV = $8C7A;
-  GL_VERTEX_ID_NV = $8C7B;
-  GL_PRIMITIVE_ID_NV = $8C7C;
-  GL_GENERIC_ATTRIB_NV = $8C7D;
-
-  // GL_NV_conditional_render
-  GL_QUERY_WAIT_NV = $8E13;
-  GL_QUERY_NO_WAIT_NV = $8E14;
-  GL_QUERY_BY_REGION_WAIT_NV = $8E15;
-  GL_QUERY_BY_REGION_NO_WAIT_NV = $8E16;
-
-  // GL_NV_present_video
-  GL_FRAME_NV = $8E26;
-  GL_FIELDS_NV = $8E27;
-  GL_CURRENT_TIME_NV = $8E28;
-  GL_NUM_FILL_STREAMS_NV = $8E29;
-  GL_PRESENT_TIME_NV = $8E2A;
-  GL_PRESENT_DURATION_NV = $8E2B;
-
-  // GL_NV_explicit_multisample
-  GL_SAMPLE_POSITION_NV = $8E50;
-  GL_SAMPLE_MASK_NV = $8E51;
-  GL_SAMPLE_MASK_VALUE_NV = $8E52;
-  GL_TEXTURE_BINDING_RENDERBUFFER_NV = $8E53;
-  GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV = $8E54;
-  GL_TEXTURE_RENDERBUFFER_NV = $8E55;
-  GL_SAMPLER_RENDERBUFFER_NV = $8E56;
-  GL_INT_SAMPLER_RENDERBUFFER_NV = $8E57;
-  GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV = $8E58;
-  GL_MAX_SAMPLE_MASK_WORDS_NV = $8E59;
-
-  // GL_NV_transform_feedback2
-  GL_TRANSFORM_FEEDBACK_NV = $8E22;
-  GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV = $8E23;
-  GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV = $8E24;
-  GL_TRANSFORM_FEEDBACK_BINDING_NV = $8E25;
-
-  // GL_OML_interlace
-  GL_INTERLACE_OML = $8980;
-  GL_INTERLACE_READ_OML = $8981;
-
-  // GL_OML_resample
-  GL_PACK_RESAMPLE_OML = $8984;
-  GL_UNPACK_RESAMPLE_OML = $8985;
-  GL_RESAMPLE_REPLICATE_OML = $8986;
-  GL_RESAMPLE_ZERO_FILL_OML = $8987;
-  GL_RESAMPLE_AVERAGE_OML = $8988;
-  GL_RESAMPLE_DECIMATE_OML = $8989;
-
-  // GL_OML_subsample
-  GL_FORMAT_SUBSAMPLE_24_24_OML = $8982;
-  GL_FORMAT_SUBSAMPLE_244_244_OML = $8983;
-
-  // GL_PGI_misc_hints
-  GL_PREFER_DOUBLEBUFFER_HINT_PGI = $1A1F8;
-  GL_CONSERVE_MEMORY_HINT_PGI = $1A1FD;
-  GL_RECLAIM_MEMORY_HINT_PGI = $1A1FE;
-  GL_NATIVE_GRAPHICS_HANDLE_PGI = $1A202;
-  GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI = $1A203;
-  GL_NATIVE_GRAPHICS_END_HINT_PGI = $1A204;
-  GL_ALWAYS_FAST_HINT_PGI = $1A20C;
-  GL_ALWAYS_SOFT_HINT_PGI = $1A20D;
-  GL_ALLOW_DRAW_OBJ_HINT_PGI = $1A20E;
-  GL_ALLOW_DRAW_WIN_HINT_PGI = $1A20F;
-  GL_ALLOW_DRAW_FRG_HINT_PGI = $1A210;
-  GL_ALLOW_DRAW_MEM_HINT_PGI = $1A211;
-  GL_STRICT_DEPTHFUNC_HINT_PGI = $1A216;
-  GL_STRICT_LIGHTING_HINT_PGI = $1A217;
-  GL_STRICT_SCISSOR_HINT_PGI = $1A218;
-  GL_FULL_STIPPLE_HINT_PGI = $1A219;
-  GL_CLIP_NEAR_HINT_PGI = $1A220;
-  GL_CLIP_FAR_HINT_PGI = $1A221;
-  GL_WIDE_LINE_HINT_PGI = $1A222;
-  GL_BACK_NORMALS_HINT_PGI = $1A223;
-
-  // GL_PGI_vertex_hints
-  GL_VERTEX_DATA_HINT_PGI = $1A22A;
-  GL_VERTEX_CONSISTENT_HINT_PGI = $1A22B;
-  GL_MATERIAL_SIDE_HINT_PGI = $1A22C;
-  GL_MAX_VERTEX_HINT_PGI = $1A22D;
-  GL_COLOR3_BIT_PGI = $00010000;
-  GL_COLOR4_BIT_PGI = $00020000;
-  GL_EDGEFLAG_BIT_PGI = $00040000;
-  GL_INDEX_BIT_PGI = $00080000;
-  GL_MAT_AMBIENT_BIT_PGI = $00100000;
-  GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI = $00200000;
-  GL_MAT_DIFFUSE_BIT_PGI = $00400000;
-  GL_MAT_EMISSION_BIT_PGI = $00800000;
-  GL_MAT_COLOR_INDEXES_BIT_PGI = $01000000;
-  GL_MAT_SHININESS_BIT_PGI = $02000000;
-  GL_MAT_SPECULAR_BIT_PGI = $04000000;
-  GL_NORMAL_BIT_PGI = $08000000;
-  GL_TEXCOORD1_BIT_PGI = $10000000;
-  GL_TEXCOORD2_BIT_PGI = $20000000;
-  GL_TEXCOORD3_BIT_PGI = $40000000;
-  GL_TEXCOORD4_BIT_PGI = $80000000;
-  GL_VERTEX23_BIT_PGI = $00000004;
-  GL_VERTEX4_BIT_PGI = $00000008;
-
-  // GL_REND_screen_coordinates
-  GL_SCREEN_COORDINATES_REND = $8490;
-  GL_INVERTED_SCREEN_W_REND = $8491;
-
-  // GL_S3_s3tc
-  GL_RGB_S3TC = $83A0;
-  GL_RGB4_S3TC = $83A1;
-  GL_RGBA_S3TC = $83A2;
-  GL_RGBA4_S3TC = $83A3;
-
-  // GL_SGIS_detail_texture
-  GL_DETAIL_TEXTURE_2D_SGIS = $8095;
-  GL_DETAIL_TEXTURE_2D_BINDING_SGIS = $8096;
-  GL_LINEAR_DETAIL_SGIS = $8097;
-  GL_LINEAR_DETAIL_ALPHA_SGIS = $8098;
-  GL_LINEAR_DETAIL_COLOR_SGIS = $8099;
-  GL_DETAIL_TEXTURE_LEVEL_SGIS = $809A;
-  GL_DETAIL_TEXTURE_MODE_SGIS = $809B;
-  GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS = $809C;
-
-  // GL_SGIS_fog_function
-  GL_FOG_FUNC_SGIS = $812A;
-  GL_FOG_FUNC_POINTS_SGIS = $812B;
-  GL_MAX_FOG_FUNC_POINTS_SGIS = $812C;
-
-  // GL_SGIS_generate_mipmap
-  GL_GENERATE_MIPMAP_SGIS = $8191;
-  GL_GENERATE_MIPMAP_HINT_SGIS = $8192;
-
-  // GL_SGIS_multisample
-  GL_MULTISAMPLE_SGIS = $809D;
-  GL_SAMPLE_ALPHA_TO_MASK_SGIS = $809E;
-  GL_SAMPLE_ALPHA_TO_ONE_SGIS = $809F;
-  GL_SAMPLE_MASK_SGIS = $80A0;
-  GL_1PASS_SGIS = $80A1;
-  GL_2PASS_0_SGIS = $80A2;
-  GL_2PASS_1_SGIS = $80A3;
-  GL_4PASS_0_SGIS = $80A4;
-  GL_4PASS_1_SGIS = $80A5;
-  GL_4PASS_2_SGIS = $80A6;
-  GL_4PASS_3_SGIS = $80A7;
-  GL_SAMPLE_BUFFERS_SGIS = $80A8;
-  GL_SAMPLES_SGIS = $80A9;
-  GL_SAMPLE_MASK_VALUE_SGIS = $80AA;
-  GL_SAMPLE_MASK_INVERT_SGIS = $80AB;
-  GL_SAMPLE_PATTERN_SGIS = $80AC;
-
-  // GL_SGIS_pixel_texture
-  GL_PIXEL_TEXTURE_SGIS = $8353;
-  GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS = $8354;
-  GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS = $8355;
-  GL_PIXEL_GROUP_COLOR_SGIS = $8356;
-
-  // GL_SGIS_point_line_texgen
-  GL_EYE_DISTANCE_TO_POINT_SGIS = $81F0;
-  GL_OBJECT_DISTANCE_TO_POINT_SGIS = $81F1;
-  GL_EYE_DISTANCE_TO_LINE_SGIS = $81F2;
-  GL_OBJECT_DISTANCE_TO_LINE_SGIS = $81F3;
-  GL_EYE_POINT_SGIS = $81F4;
-  GL_OBJECT_POINT_SGIS = $81F5;
-  GL_EYE_LINE_SGIS = $81F6;
-  GL_OBJECT_LINE_SGIS = $81F7;
-
-  // GL_SGIS_point_parameters
-  GL_POINT_SIZE_MIN_SGIS = $8126;
-  GL_POINT_SIZE_MAX_SGIS = $8127;
-  GL_POINT_FADE_THRESHOLD_SIZE_SGIS = $8128;
-  GL_DISTANCE_ATTENUATION_SGIS = $8129;
-
-  // GL_SGIS_sharpen_texture
-  GL_LINEAR_SHARPEN_SGIS = $80AD;
-  GL_LINEAR_SHARPEN_ALPHA_SGIS = $80AE;
-  GL_LINEAR_SHARPEN_COLOR_SGIS = $80AF;
-  GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS = $80B0;
-
-  // GL_SGIS_texture4D
-  GL_PACK_SKIP_VOLUMES_SGIS = $8130;
-  GL_PACK_IMAGE_DEPTH_SGIS = $8131;
-  GL_UNPACK_SKIP_VOLUMES_SGIS = $8132;
-  GL_UNPACK_IMAGE_DEPTH_SGIS = $8133;
-  GL_TEXTURE_4D_SGIS = $8134;
-  GL_PROXY_TEXTURE_4D_SGIS = $8135;
-  GL_TEXTURE_4DSIZE_SGIS = $8136;
-  GL_TEXTURE_WRAP_Q_SGIS = $8137;
-  GL_MAX_4D_TEXTURE_SIZE_SGIS = $8138;
-  GL_TEXTURE_4D_BINDING_SGIS = $814F;
-
-  // GL_SGIS_texture_color_mask
-  GL_TEXTURE_COLOR_WRITEMASK_SGIS = $81EF;
-
-  // GL_SGIS_texture_edge_clamp
-  GL_CLAMP_TO_EDGE_SGIS = $812F;
-
-  // GL_SGIS_texture_filter4
-  GL_FILTER4_SGIS = $8146;
-  GL_TEXTURE_FILTER4_SIZE_SGIS = $8147;
-
-  // GL_SGIS_texture_lod
-  GL_TEXTURE_MIN_LOD_SGIS = $813A;
-  GL_TEXTURE_MAX_LOD_SGIS = $813B;
-  GL_TEXTURE_BASE_LEVEL_SGIS = $813C;
-  GL_TEXTURE_MAX_LEVEL_SGIS = $813D;
-
-  // GL_SGIS_texture_select
-  GL_DUAL_ALPHA4_SGIS = $8110;
-  GL_DUAL_ALPHA8_SGIS = $8111;
-  GL_DUAL_ALPHA12_SGIS = $8112;
-  GL_DUAL_ALPHA16_SGIS = $8113;
-  GL_DUAL_LUMINANCE4_SGIS = $8114;
-  GL_DUAL_LUMINANCE8_SGIS = $8115;
-  GL_DUAL_LUMINANCE12_SGIS = $8116;
-  GL_DUAL_LUMINANCE16_SGIS = $8117;
-  GL_DUAL_INTENSITY4_SGIS = $8118;
-  GL_DUAL_INTENSITY8_SGIS = $8119;
-  GL_DUAL_INTENSITY12_SGIS = $811A;
-  GL_DUAL_INTENSITY16_SGIS = $811B;
-  GL_DUAL_LUMINANCE_ALPHA4_SGIS = $811C;
-  GL_DUAL_LUMINANCE_ALPHA8_SGIS = $811D;
-  GL_QUAD_ALPHA4_SGIS = $811E;
-  GL_QUAD_ALPHA8_SGIS = $811F;
-  GL_QUAD_LUMINANCE4_SGIS = $8120;
-  GL_QUAD_LUMINANCE8_SGIS = $8121;
-  GL_QUAD_INTENSITY4_SGIS = $8122;
-  GL_QUAD_INTENSITY8_SGIS = $8123;
-  GL_DUAL_TEXTURE_SELECT_SGIS = $8124;
-  GL_QUAD_TEXTURE_SELECT_SGIS = $8125;
-
-  // GL_SGIX_async
-  GL_ASYNC_MARKER_SGIX = $8329;
-
-  // GL_SGIX_async_histogram
-  GL_ASYNC_HISTOGRAM_SGIX = $832C;
-  GL_MAX_ASYNC_HISTOGRAM_SGIX = $832D;
-
-  // GL_SGIX_async_pixel
-  GL_ASYNC_TEX_IMAGE_SGIX = $835C;
-  GL_ASYNC_DRAW_PIXELS_SGIX = $835D;
-  GL_ASYNC_READ_PIXELS_SGIX = $835E;
-  GL_MAX_ASYNC_TEX_IMAGE_SGIX = $835F;
-  GL_MAX_ASYNC_DRAW_PIXELS_SGIX = $8360;
-  GL_MAX_ASYNC_READ_PIXELS_SGIX = $8361;
-
-  // GL_SGIX_blend_alpha_minmax
-  GL_ALPHA_MIN_SGIX = $8320;
-  GL_ALPHA_MAX_SGIX = $8321;
-
-  // GL_SGIX_calligraphic_fragment
-  GL_CALLIGRAPHIC_FRAGMENT_SGIX = $8183;
-
-  // GL_SGIX_clipmap
-  GL_LINEAR_CLIPMAP_LINEAR_SGIX = $8170;
-  GL_TEXTURE_CLIPMAP_CENTER_SGIX = $8171;
-  GL_TEXTURE_CLIPMAP_FRAME_SGIX = $8172;
-  GL_TEXTURE_CLIPMAP_OFFSET_SGIX = $8173;
-  GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX = $8174;
-  GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX = $8175;
-  GL_TEXTURE_CLIPMAP_DEPTH_SGIX = $8176;
-  GL_MAX_CLIPMAP_DEPTH_SGIX = $8177;
-  GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX = $8178;
-  GL_NEAREST_CLIPMAP_NEAREST_SGIX = $844D;
-  GL_NEAREST_CLIPMAP_LINEAR_SGIX = $844E;
-  GL_LINEAR_CLIPMAP_NEAREST_SGIX = $844F;
-
-  // GL_SGIX_convolution_accuracy
-  GL_CONVOLUTION_HINT_SGIX = $8316;
-
-  // GL_SGIX_depth_texture
-  GL_DEPTH_COMPONENT16_SGIX = $81A5;
-  GL_DEPTH_COMPONENT24_SGIX = $81A6;
-  GL_DEPTH_COMPONENT32_SGIX = $81A7;
-
-  // GL_SGIX_fog_offset
-  GL_FOG_OFFSET_SGIX = $8198;
-  GL_FOG_OFFSET_VALUE_SGIX = $8199;
-
-  // GL_SGIX_fog_scale
-  GL_FOG_SCALE_SGIX = $81FC;
-  GL_FOG_SCALE_VALUE_SGIX = $81FD;
-
-  // GL_SGIX_fragment_lighting
-  GL_FRAGMENT_LIGHTING_SGIX = $8400;
-  GL_FRAGMENT_COLOR_MATERIAL_SGIX = $8401;
-  GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX = $8402;
-  GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX = $8403;
-  GL_MAX_FRAGMENT_LIGHTS_SGIX = $8404;
-  GL_MAX_ACTIVE_LIGHTS_SGIX = $8405;
-  GL_CURRENT_RASTER_NORMAL_SGIX = $8406;
-  GL_LIGHT_ENV_MODE_SGIX = $8407;
-  GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX = $8408;
-  GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX = $8409;
-  GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX = $840A;
-  GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX = $840B;
-  GL_FRAGMENT_LIGHT0_SGIX = $840C;
-  GL_FRAGMENT_LIGHT1_SGIX = $840D;
-  GL_FRAGMENT_LIGHT2_SGIX = $840E;
-  GL_FRAGMENT_LIGHT3_SGIX = $840F;
-  GL_FRAGMENT_LIGHT4_SGIX = $8410;
-  GL_FRAGMENT_LIGHT5_SGIX = $8411;
-  GL_FRAGMENT_LIGHT6_SGIX = $8412;
-  GL_FRAGMENT_LIGHT7_SGIX = $8413;
-
-  // GL_SGIX_framezoom
-  GL_FRAMEZOOM_SGIX = $818B;
-  GL_FRAMEZOOM_FACTOR_SGIX = $818C;
-  GL_MAX_FRAMEZOOM_FACTOR_SGIX = $818D;
-
-  // GL_SGIX_impact_pixel_texture
-  GL_PIXEL_TEX_GEN_Q_CEILING_SGIX = $8184;
-  GL_PIXEL_TEX_GEN_Q_ROUND_SGIX = $8185;
-  GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX = $8186;
-  GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX = $8187;
-  GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX = $8188;
-  GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX = $8189;
-  GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX = $818A;
-
-  // GL_SGIX_instruments
-  GL_INSTRUMENT_BUFFER_POINTER_SGIX = $8180;
-  GL_INSTRUMENT_MEASUREMENTS_SGIX = $8181;
-
-  // GL_SGIX_interlace
-  GL_INTERLACE_SGIX = $8094;
-
-  // GL_SGIX_ir_instrument1
-  GL_IR_INSTRUMENT1_SGIX = $817F;
-
-  // GL_SGIX_list_priority
-  GL_LIST_PRIORITY_SGIX = $8182;
-
-  // GL_SGIX_pixel_texture
-  GL_PIXEL_TEX_GEN_SGIX = $8139;
-  GL_PIXEL_TEX_GEN_MODE_SGIX = $832B;
-
-  // GL_SGIX_pixel_tiles
-  GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX = $813E;
-  GL_PIXEL_TILE_CACHE_INCREMENT_SGIX = $813F;
-  GL_PIXEL_TILE_WIDTH_SGIX = $8140;
-  GL_PIXEL_TILE_HEIGHT_SGIX = $8141;
-  GL_PIXEL_TILE_GRID_WIDTH_SGIX = $8142;
-  GL_PIXEL_TILE_GRID_HEIGHT_SGIX = $8143;
-  GL_PIXEL_TILE_GRID_DEPTH_SGIX = $8144;
-  GL_PIXEL_TILE_CACHE_SIZE_SGIX = $8145;
-
-  // GL_SGIX_polynomial_ffd
-  GL_GEOMETRY_DEFORMATION_SGIX = $8194;
-  GL_TEXTURE_DEFORMATION_SGIX = $8195;
-  GL_DEFORMATIONS_MASK_SGIX = $8196;
-  GL_MAX_DEFORMATION_ORDER_SGIX = $8197;
-
-  // GL_SGIX_reference_plane
-  GL_REFERENCE_PLANE_SGIX = $817D;
-  GL_REFERENCE_PLANE_EQUATION_SGIX = $817E;
-
-  // GL_SGIX_resample
-  GL_PACK_RESAMPLE_SGIX = $842C;
-  GL_UNPACK_RESAMPLE_SGIX = $842D;
-  GL_RESAMPLE_REPLICATE_SGIX = $842E;
-  GL_RESAMPLE_ZERO_FILL_SGIX = $842F;
-  GL_RESAMPLE_DECIMATE_SGIX = $8430;
-
-  // GL_SGIX_scalebias_hint
-  GL_SCALEBIAS_HINT_SGIX = $8322;
-
-  // GL_SGIX_shadow
-  GL_TEXTURE_COMPARE_SGIX = $819A;
-  GL_TEXTURE_COMPARE_OPERATOR_SGIX = $819B;
-  GL_TEXTURE_LEQUAL_R_SGIX = $819C;
-  GL_TEXTURE_GEQUAL_R_SGIX = $819D;
-
-  // GL_SGIX_shadow_ambient
-  GL_SHADOW_AMBIENT_SGIX = $80BF;
-
-  // GL_SGIX_sprite
-  GL_SPRITE_SGIX = $8148;
-  GL_SPRITE_MODE_SGIX = $8149;
-  GL_SPRITE_AXIS_SGIX = $814A;
-  GL_SPRITE_TRANSLATION_SGIX = $814B;
-  GL_SPRITE_AXIAL_SGIX = $814C;
-  GL_SPRITE_OBJECT_ALIGNED_SGIX = $814D;
-  GL_SPRITE_EYE_ALIGNED_SGIX = $814E;
-
-  // GL_SGIX_subsample
-  GL_PACK_SUBSAMPLE_RATE_SGIX = $85A0;
-  GL_UNPACK_SUBSAMPLE_RATE_SGIX = $85A1;
-  GL_PIXEL_SUBSAMPLE_4444_SGIX = $85A2;
-  GL_PIXEL_SUBSAMPLE_2424_SGIX = $85A3;
-  GL_PIXEL_SUBSAMPLE_4242_SGIX = $85A4;
-
-  // GL_SGIX_texture_add_env
-  GL_TEXTURE_ENV_BIAS_SGIX = $80BE;
-
-  // GL_SGIX_texture_coordinate_clamp
-  GL_TEXTURE_MAX_CLAMP_S_SGIX = $8369;
-  GL_TEXTURE_MAX_CLAMP_T_SGIX = $836A;
-  GL_TEXTURE_MAX_CLAMP_R_SGIX = $836B;
-
-  // GL_SGIX_texture_lod_bias
-  GL_TEXTURE_LOD_BIAS_S_SGIX = $818E;
-  GL_TEXTURE_LOD_BIAS_T_SGIX = $818F;
-  GL_TEXTURE_LOD_BIAS_R_SGIX = $8190;
-
-  // GL_SGIX_texture_multi_buffer
-  GL_TEXTURE_MULTI_BUFFER_HINT_SGIX = $812E;
-
-  // GL_SGIX_texture_scale_bias
-  GL_POST_TEXTURE_FILTER_BIAS_SGIX = $8179;
-  GL_POST_TEXTURE_FILTER_SCALE_SGIX = $817A;
-  GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX = $817B;
-  GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX = $817C;
-
-  // GL_SGIX_vertex_preclip
-  GL_VERTEX_PRECLIP_SGIX = $83EE;
-  GL_VERTEX_PRECLIP_HINT_SGIX = $83EF;
-
-  // GL_SGIX_ycrcb
-  GL_YCRCB_422_SGIX = $81BB;
-  GL_YCRCB_444_SGIX = $81BC;
-
-  // GL_SGIX_ycrcba
-  GL_YCRCB_SGIX = $8318;
-  GL_YCRCBA_SGIX = $8319;
-
-  // GL_SGI_color_matrix
-  GL_COLOR_MATRIX_SGI = $80B1;
-  GL_COLOR_MATRIX_STACK_DEPTH_SGI = $80B2;
-  GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI = $80B3;
-  GL_POST_COLOR_MATRIX_RED_SCALE_SGI = $80B4;
-  GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI = $80B5;
-  GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI = $80B6;
-  GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI = $80B7;
-  GL_POST_COLOR_MATRIX_RED_BIAS_SGI = $80B8;
-  GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI = $80B9;
-  GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI = $80BA;
-  GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI = $80BB;
-
-  // GL_SGI_color_table
-  GL_COLOR_TABLE_SGI = $80D0;
-  GL_POST_CONVOLUTION_COLOR_TABLE_SGI = $80D1;
-  GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI = $80D2;
-  GL_PROXY_COLOR_TABLE_SGI = $80D3;
-  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI = $80D4;
-  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI = $80D5;
-  GL_COLOR_TABLE_SCALE_SGI = $80D6;
-  GL_COLOR_TABLE_BIAS_SGI = $80D7;
-  GL_COLOR_TABLE_FORMAT_SGI = $80D8;
-  GL_COLOR_TABLE_WIDTH_SGI = $80D9;
-  GL_COLOR_TABLE_RED_SIZE_SGI = $80DA;
-  GL_COLOR_TABLE_GREEN_SIZE_SGI = $80DB;
-  GL_COLOR_TABLE_BLUE_SIZE_SGI = $80DC;
-  GL_COLOR_TABLE_ALPHA_SIZE_SGI = $80DD;
-  GL_COLOR_TABLE_LUMINANCE_SIZE_SGI = $80DE;
-  GL_COLOR_TABLE_INTENSITY_SIZE_SGI = $80DF;
-
-  // GL_SGI_depth_pass_instrument
-  GL_DEPTH_PASS_INSTRUMENT_SGIX = $8310;
-  GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX = $8311;
-  GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX = $8312;
-
-  // GL_SGI_texture_color_table
-  GL_TEXTURE_COLOR_TABLE_SGI = $80BC;
-  GL_PROXY_TEXTURE_COLOR_TABLE_SGI = $80BD;
-
-  // GL_SUNX_constant_data
-  GL_UNPACK_CONSTANT_DATA_SUNX = $81D5;
-  GL_TEXTURE_CONSTANT_DATA_SUNX = $81D6;
-
-  // GL_SUN_convolution_border_modes
-  GL_WRAP_BORDER_SUN = $81D4;
-
-  // GL_SUN_global_alpha
-  GL_GLOBAL_ALPHA_SUN = $81D9;
-  GL_GLOBAL_ALPHA_FACTOR_SUN = $81DA;
-
-  // GL_SUN_mesh_array
-  GL_QUAD_MESH_SUN = $8614;
-  GL_TRIANGLE_MESH_SUN = $8615;
-
-  // GL_SUN_slice_accum
-  GL_SLICE_ACCUM_SUN = $85CC;
-
-  // GL_SUN_triangle_list
-  GL_RESTART_SUN = $0001;
-  GL_REPLACE_MIDDLE_SUN = $0002;
-  GL_REPLACE_OLDEST_SUN = $0003;
-  GL_TRIANGLE_LIST_SUN = $81D7;
-  GL_REPLACEMENT_CODE_SUN = $81D8;
-  GL_REPLACEMENT_CODE_ARRAY_SUN = $85C0;
-  GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN = $85C1;
-  GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN = $85C2;
-  GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN = $85C3;
-  GL_R1UI_V3F_SUN = $85C4;
-  GL_R1UI_C4UB_V3F_SUN = $85C5;
-  GL_R1UI_C3F_V3F_SUN = $85C6;
-  GL_R1UI_N3F_V3F_SUN = $85C7;
-  GL_R1UI_C4F_N3F_V3F_SUN = $85C8;
-  GL_R1UI_T2F_V3F_SUN = $85C9;
-  GL_R1UI_T2F_N3F_V3F_SUN = $85CA;
-  GL_R1UI_T2F_C4F_N3F_V3F_SUN = $85CB;
-
-  // GL_WIN_phong_shading
-  GL_PHONG_WIN = $80EA;
-  GL_PHONG_HINT_WIN = $80EB;
-
-  // GL_WIN_specular_fog
-  GL_FOG_SPECULAR_TEXTURE_WIN = $80EC;
-
-   // GL_ARB_vertex_shader
-  GL_VERTEX_SHADER_ARB = $8B31;
-  GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB = $8B4A;
-  GL_MAX_VARYING_FLOATS_ARB = $8B4B;
-  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB = $8B4C;
-  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB = $8B4D;
-  GL_OBJECT_ACTIVE_ATTRIBUTES_ARB = $8B89;
-  GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB = $8B8A;
-
-  // GL_ARB_fragment_shader
-  GL_FRAGMENT_SHADER_ARB = $8B30;
-  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB = $8B49; // 1.4
-  GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB = $8B8B; // 1.4
-
-  // GL_ARB_occlusion_query
-  GL_SAMPLES_PASSED_ARB = $8914;
-  GL_QUERY_COUNTER_BITS_ARB = $8864;
-  GL_CURRENT_QUERY_ARB = $8865;
-  GL_QUERY_RESULT_ARB = $8866;
-  GL_QUERY_RESULT_AVAILABLE_ARB = $8867;
-
-  // GL_ARB_point_sprite
-  GL_POINT_SPRITE_ARB = $8861;
-  GL_COORD_REPLACE_ARB = $8862;
-
-  // GL_ARB_shading_language_100
-  GL_SHADING_LANGUAGE_VERSION_ARB = $8B8C; // 1.4
-
-  // GL_ARB_shader_objects
-  GL_PROGRAM_OBJECT_ARB = $8B40;
-
-  GL_OBJECT_TYPE_ARB = $8B4E;
-  GL_OBJECT_SUBTYPE_ARB = $8B4F;
-  GL_OBJECT_DELETE_STATUS_ARB = $8B80;
-  GL_OBJECT_COMPILE_STATUS_ARB = $8B81;
-  GL_OBJECT_LINK_STATUS_ARB = $8B82;
-  GL_OBJECT_VALIDATE_STATUS_ARB = $8B83;
-  GL_OBJECT_INFO_LOG_LENGTH_ARB = $8B84;
-  GL_OBJECT_ATTACHED_OBJECTS_ARB = $8B85;
-  GL_OBJECT_ACTIVE_UNIFORMS_ARB = $8B86;
-  GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB = $8B87;
-  GL_OBJECT_SHADER_SOURCE_LENGTH_ARB = $8B88;
-
-  GL_SHADER_OBJECT_ARB = $8B48;
-
-  GL_FLOAT_VEC2_ARB = $8B50;
-  GL_FLOAT_VEC3_ARB = $8B51;
-  GL_FLOAT_VEC4_ARB = $8B52;
-  GL_INT_VEC2_ARB = $8B53;
-  GL_INT_VEC3_ARB = $8B54;
-  GL_INT_VEC4_ARB = $8B55;
-  GL_BOOL_ARB = $8B56;
-  GL_BOOL_VEC2_ARB = $8B57;
-  GL_BOOL_VEC3_ARB = $8B58;
-  GL_BOOL_VEC4_ARB = $8B59;
-  GL_FLOAT_MAT2_ARB = $8B5A;
-  GL_FLOAT_MAT3_ARB = $8B5B;
-  GL_FLOAT_MAT4_ARB = $8B5C;
-  GL_SAMPLER_1D_ARB = $8B5D;
-  GL_SAMPLER_2D_ARB = $8B5E;
-  GL_SAMPLER_3D_ARB = $8B5F;
-  GL_SAMPLER_CUBE_ARB = $8B60;
-  GL_SAMPLER_1D_SHADOW_ARB = $8B61;
-  GL_SAMPLER_2D_SHADOW_ARB = $8B62;
-  GL_SAMPLER_2D_RECT_ARB = $8B63;
-  GL_SAMPLER_2D_RECT_SHADOW_ARB = $8B64;
-
-  // WGL_3DFX_multisample
-  WGL_SAMPLE_BUFFERS_3DFX = $2060;
-  WGL_SAMPLES_3DFX = $2061;
-
-  // WGL_ARB_buffer_region
-  WGL_FRONT_COLOR_BUFFER_BIT_ARB = $00000001;
-  WGL_BACK_COLOR_BUFFER_BIT_ARB = $00000002;
-  WGL_DEPTH_BUFFER_BIT_ARB = $00000004;
-  WGL_STENCIL_BUFFER_BIT_ARB = $00000008;
-
-  // WGL_ARB_make_current_read
-  ERROR_INVALID_PIXEL_TYPE_ARB = $2043;
-  ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB = $2054;
-
-  // WGL_ARB_multisample
-  WGL_SAMPLE_BUFFERS_ARB = $2041;
-  WGL_SAMPLES_ARB = $2042;
-
-  // WGL_ARB_pbuffer
-  WGL_DRAW_TO_PBUFFER_ARB = $202D;
-  WGL_MAX_PBUFFER_PIXELS_ARB = $202E;
-  WGL_MAX_PBUFFER_WIDTH_ARB = $202F;
-  WGL_MAX_PBUFFER_HEIGHT_ARB = $2030;
-  WGL_PBUFFER_LARGEST_ARB = $2033;
-  WGL_PBUFFER_WIDTH_ARB = $2034;
-  WGL_PBUFFER_HEIGHT_ARB = $2035;
-  WGL_PBUFFER_LOST_ARB = $2036;
-
-  // WGL_ARB_pixel_format
-  WGL_NUMBER_PIXEL_FORMATS_ARB = $2000;
-  WGL_DRAW_TO_WINDOW_ARB = $2001;
-  WGL_DRAW_TO_BITMAP_ARB = $2002;
-  WGL_ACCELERATION_ARB = $2003;
-  WGL_NEED_PALETTE_ARB = $2004;
-  WGL_NEED_SYSTEM_PALETTE_ARB = $2005;
-  WGL_SWAP_LAYER_BUFFERS_ARB = $2006;
-  WGL_SWAP_METHOD_ARB = $2007;
-  WGL_NUMBER_OVERLAYS_ARB = $2008;
-  WGL_NUMBER_UNDERLAYS_ARB = $2009;
-  WGL_TRANSPARENT_ARB = $200A;
-  WGL_TRANSPARENT_RED_VALUE_ARB = $2037;
-  WGL_TRANSPARENT_GREEN_VALUE_ARB = $2038;
-  WGL_TRANSPARENT_BLUE_VALUE_ARB = $2039;
-  WGL_TRANSPARENT_ALPHA_VALUE_ARB = $203A;
-  WGL_TRANSPARENT_INDEX_VALUE_ARB = $203B;
-  WGL_SHARE_DEPTH_ARB = $200C;
-  WGL_SHARE_STENCIL_ARB = $200D;
-  WGL_SHARE_ACCUM_ARB = $200E;
-  WGL_SUPPORT_GDI_ARB = $200F;
-  WGL_SUPPORT_OPENGL_ARB = $2010;
-  WGL_DOUBLE_BUFFER_ARB = $2011;
-  WGL_STEREO_ARB = $2012;
-  WGL_PIXEL_TYPE_ARB = $2013;
-  WGL_COLOR_BITS_ARB = $2014;
-  WGL_RED_BITS_ARB = $2015;
-  WGL_RED_SHIFT_ARB = $2016;
-  WGL_GREEN_BITS_ARB = $2017;
-  WGL_GREEN_SHIFT_ARB = $2018;
-  WGL_BLUE_BITS_ARB = $2019;
-  WGL_BLUE_SHIFT_ARB = $201A;
-  WGL_ALPHA_BITS_ARB = $201B;
-  WGL_ALPHA_SHIFT_ARB = $201C;
-  WGL_ACCUM_BITS_ARB = $201D;
-  WGL_ACCUM_RED_BITS_ARB = $201E;
-  WGL_ACCUM_GREEN_BITS_ARB = $201F;
-  WGL_ACCUM_BLUE_BITS_ARB = $2020;
-  WGL_ACCUM_ALPHA_BITS_ARB = $2021;
-  WGL_DEPTH_BITS_ARB = $2022;
-  WGL_STENCIL_BITS_ARB = $2023;
-  WGL_AUX_BUFFERS_ARB = $2024;
-  WGL_NO_ACCELERATION_ARB = $2025;
-  WGL_GENERIC_ACCELERATION_ARB = $2026;
-  WGL_FULL_ACCELERATION_ARB = $2027;
-  WGL_SWAP_EXCHANGE_ARB = $2028;
-  WGL_SWAP_COPY_ARB = $2029;
-  WGL_SWAP_UNDEFINED_ARB = $202A;
-  WGL_TYPE_RGBA_ARB = $202B;
-  WGL_TYPE_COLORINDEX_ARB = $202C;
-
-  // WGL_ARB_pixel_format_float
-  WGL_RGBA_FLOAT_MODE_ARB = $8820;
-  WGL_CLAMP_VERTEX_COLOR_ARB = $891A;
-  WGL_CLAMP_FRAGMENT_COLOR_ARB = $891B;
-  WGL_CLAMP_READ_COLOR_ARB = $891C;
-  WGL_FIXED_ONLY_ARB = $891D;
-
-  // WGL_ARB_render_texture
-  WGL_BIND_TO_TEXTURE_RGB_ARB = $2070;
-  WGL_BIND_TO_TEXTURE_RGBA_ARB = $2071;
-  WGL_TEXTURE_FORMAT_ARB = $2072;
-  WGL_TEXTURE_TARGET_ARB = $2073;
-  WGL_MIPMAP_TEXTURE_ARB = $2074;
-  WGL_TEXTURE_RGB_ARB = $2075;
-  WGL_TEXTURE_RGBA_ARB = $2076;
-  WGL_NO_TEXTURE_ARB = $2077;
-  WGL_TEXTURE_CUBE_MAP_ARB = $2078;
-  WGL_TEXTURE_1D_ARB = $2079;
-  WGL_TEXTURE_2D_ARB = $207A;
-  WGL_MIPMAP_LEVEL_ARB = $207B;
-  WGL_CUBE_MAP_FACE_ARB = $207C;
-  WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB = $207D;
-  WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB = $207E;
-  WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB = $207F;
-  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB = $2080;
-  WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB = $2081;
-  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB = $2082;
-  WGL_FRONT_LEFT_ARB = $2083;
-  WGL_FRONT_RIGHT_ARB = $2084;
-  WGL_BACK_LEFT_ARB = $2085;
-  WGL_BACK_RIGHT_ARB = $2086;
-  WGL_AUX0_ARB = $2087;
-  WGL_AUX1_ARB = $2088;
-  WGL_AUX2_ARB = $2089;
-  WGL_AUX3_ARB = $208A;
-  WGL_AUX4_ARB = $208B;
-  WGL_AUX5_ARB = $208C;
-  WGL_AUX6_ARB = $208D;
-  WGL_AUX7_ARB = $208E;
-  WGL_AUX8_ARB = $208F;
-  WGL_AUX9_ARB = $2090;
-
-  // WGL_ARB_create_context
-  WGL_CONTEXT_DEBUG_BIT_ARB = $00000001;
-  WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = $00000002;
-  WGL_CONTEXT_MAJOR_VERSION_ARB = $2091;
-  WGL_CONTEXT_MINOR_VERSION_ARB = $2092;
-  WGL_CONTEXT_LAYER_PLANE_ARB = $2093;
-  WGL_CONTEXT_FLAGS_ARB = $2094;
-  ERROR_INVALID_VERSION_ARB = $2095;
-
-  // WGL_ARB_create_context_profile
-  WGL_CONTEXT_PROFILE_MASK_ARB = $9126;
-  WGL_CONTEXT_CORE_PROFILE_BIT_ARB = $00000001;
-  WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = $00000002;
-  ERROR_INVALID_PROFILE_ARB = $2096;
-
-  // WGL_ATI_pixel_format_float
-  WGL_TYPE_RGBA_FLOAT_ATI = $21A0;
-  GL_TYPE_RGBA_FLOAT_ATI = $8820;
-  GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI = $8835;
-
-  // WGL_AMD_gpu_association
-  WGL_GPU_VENDOR_AMD = $1F00;
-  WGL_GPU_RENDERER_STRING_AMD = $1F01;
-  WGL_GPU_OPENGL_VERSION_STRING_AMD = $1F02;
-  WGL_GPU_FASTEST_TARGET_GPUS_AMD = $21A2;
-  WGL_GPU_RAM_AMD = $21A3;
-  WGL_GPU_CLOCK_AMD = $21A4;
-  WGL_GPU_NUM_PIPES_AMD = $21A5;
-  WGL_GPU_NUM_SIMD_AMD = $21A6;
-  WGL_GPU_NUM_RB_AMD = $21A7;
-  WGL_GPU_NUM_SPI_AMD = $21A8;
-
-  // WGL_EXT_depth_float
-  WGL_DEPTH_FLOAT_EXT = $2040;
-
-  // WGL_EXT_make_current_read
-  ERROR_INVALID_PIXEL_TYPE_EXT = $2043;
-
-  // WGL_EXT_multisample
-  WGL_SAMPLE_BUFFERS_EXT = $2041;
-  WGL_SAMPLES_EXT = $2042;
-
-  // WGL_EXT_pbuffer
-  WGL_DRAW_TO_PBUFFER_EXT = $202D;
-  WGL_MAX_PBUFFER_PIXELS_EXT = $202E;
-  WGL_MAX_PBUFFER_WIDTH_EXT = $202F;
-  WGL_MAX_PBUFFER_HEIGHT_EXT = $2030;
-  WGL_OPTIMAL_PBUFFER_WIDTH_EXT = $2031;
-  WGL_OPTIMAL_PBUFFER_HEIGHT_EXT = $2032;
-  WGL_PBUFFER_LARGEST_EXT = $2033;
-  WGL_PBUFFER_WIDTH_EXT = $2034;
-  WGL_PBUFFER_HEIGHT_EXT = $2035;
-
-  // WGL_EXT_pixel_format
-  WGL_NUMBER_PIXEL_FORMATS_EXT = $2000;
-  WGL_DRAW_TO_WINDOW_EXT = $2001;
-  WGL_DRAW_TO_BITMAP_EXT = $2002;
-  WGL_ACCELERATION_EXT = $2003;
-  WGL_NEED_PALETTE_EXT = $2004;
-  WGL_NEED_SYSTEM_PALETTE_EXT = $2005;
-  WGL_SWAP_LAYER_BUFFERS_EXT = $2006;
-  WGL_SWAP_METHOD_EXT = $2007;
-  WGL_NUMBER_OVERLAYS_EXT = $2008;
-  WGL_NUMBER_UNDERLAYS_EXT = $2009;
-  WGL_TRANSPARENT_EXT = $200A;
-  WGL_TRANSPARENT_VALUE_EXT = $200B;
-  WGL_SHARE_DEPTH_EXT = $200C;
-  WGL_SHARE_STENCIL_EXT = $200D;
-  WGL_SHARE_ACCUM_EXT = $200E;
-  WGL_SUPPORT_GDI_EXT = $200F;
-  WGL_SUPPORT_OPENGL_EXT = $2010;
-  WGL_DOUBLE_BUFFER_EXT = $2011;
-  WGL_STEREO_EXT = $2012;
-  WGL_PIXEL_TYPE_EXT = $2013;
-  WGL_COLOR_BITS_EXT = $2014;
-  WGL_RED_BITS_EXT = $2015;
-  WGL_RED_SHIFT_EXT = $2016;
-  WGL_GREEN_BITS_EXT = $2017;
-  WGL_GREEN_SHIFT_EXT = $2018;
-  WGL_BLUE_BITS_EXT = $2019;
-  WGL_BLUE_SHIFT_EXT = $201A;
-  WGL_ALPHA_BITS_EXT = $201B;
-  WGL_ALPHA_SHIFT_EXT = $201C;
-  WGL_ACCUM_BITS_EXT = $201D;
-  WGL_ACCUM_RED_BITS_EXT = $201E;
-  WGL_ACCUM_GREEN_BITS_EXT = $201F;
-  WGL_ACCUM_BLUE_BITS_EXT = $2020;
-  WGL_ACCUM_ALPHA_BITS_EXT = $2021;
-  WGL_DEPTH_BITS_EXT = $2022;
-  WGL_STENCIL_BITS_EXT = $2023;
-  WGL_AUX_BUFFERS_EXT = $2024;
-  WGL_NO_ACCELERATION_EXT = $2025;
-  WGL_GENERIC_ACCELERATION_EXT = $2026;
-  WGL_FULL_ACCELERATION_EXT = $2027;
-  WGL_SWAP_EXCHANGE_EXT = $2028;
-  WGL_SWAP_COPY_EXT = $2029;
-  WGL_SWAP_UNDEFINED_EXT = $202A;
-  WGL_TYPE_RGBA_EXT = $202B;
-  WGL_TYPE_COLORINDEX_EXT = $202C;
-
-  // WGL_I3D_digital_video_control
-  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D = $2050;
-  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D = $2051;
-  WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D = $2052;
-  WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D = $2053;
-
-  // WGL_I3D_gamma
-  WGL_GAMMA_TABLE_SIZE_I3D = $204E;
-  WGL_GAMMA_EXCLUDE_DESKTOP_I3D = $204F;
-
-  // WGL_I3D_genlock
-  WGL_GENLOCK_SOURCE_MULTIVIEW_I3D = $2044;
-  WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D = $2045;
-  WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D = $2046;
-  WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D = $2047;
-  WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D = $2048;
-  WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D = $2049;
-  WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D = $204A;
-  WGL_GENLOCK_SOURCE_EDGE_RISING_I3D = $204B;
-  WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D = $204C;
-
-  // WGL_I3D_image_buffer
-  WGL_IMAGE_BUFFER_MIN_ACCESS_I3D = $00000001;
-  WGL_IMAGE_BUFFER_LOCK_I3D = $00000002;
-
-  // WGL_NV_float_buffer
-  WGL_FLOAT_COMPONENTS_NV = $20B0;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV = $20B1;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV = $20B2;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV = $20B3;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV = $20B4;
-  WGL_TEXTURE_FLOAT_R_NV = $20B5;
-  WGL_TEXTURE_FLOAT_RG_NV = $20B6;
-  WGL_TEXTURE_FLOAT_RGB_NV = $20B7;
-  WGL_TEXTURE_FLOAT_RGBA_NV = $20B8;
-
-  // WGL_NV_render_depth_texture
-  WGL_BIND_TO_TEXTURE_DEPTH_NV = $20A3;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV = $20A4;
-  WGL_DEPTH_TEXTURE_FORMAT_NV = $20A5;
-  WGL_TEXTURE_DEPTH_COMPONENT_NV = $20A6;
-  WGL_DEPTH_COMPONENT_NV = $20A7;
-
-  // WGL_NV_render_texture_rectangle
-  WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV = $20A0;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV = $20A1;
-  WGL_TEXTURE_RECTANGLE_NV = $20A2;
-
-  // WGL_NV_present_video
-  WGL_NUM_VIDEO_SLOTS_NV = $20F0;
-  
-  // WGL_NV_video_out
-  WGL_BIND_TO_VIDEO_RGB_NV = $20C0;
-  WGL_BIND_TO_VIDEO_RGBA_NV = $20C1;
-  WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV = $20C2;
-  WGL_VIDEO_OUT_COLOR_NV = $20C3;
-  WGL_VIDEO_OUT_ALPHA_NV = $20C4;
-  WGL_VIDEO_OUT_DEPTH_NV = $20C5;
-  WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV = $20C6;
-  WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV = $20C7;
-  WGL_VIDEO_OUT_FRAME = $20C8;
-  WGL_VIDEO_OUT_FIELD_1 = $20C9;
-  WGL_VIDEO_OUT_FIELD_2 = $20CA;
-  WGL_VIDEO_OUT_STACKED_FIELDS_1_2 = $20CB;
-  WGL_VIDEO_OUT_STACKED_FIELDS_2_1 = $20CC;
-
-  // WGL_NV_gpu_affinity
-  WGL_ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV = $20D0;
-  WGL_ERROR_MISSING_AFFINITY_MASK_NV = $20D1;
-
-  // WIN_draw_range_elements
-  GL_MAX_ELEMENTS_VERTICES_WIN = $80E8;
-  GL_MAX_ELEMENTS_INDICES_WIN = $80E9;
-
-  // GLX 1.1 and later:
-  GLX_VENDOR = 1;
-  GLX_VERSION = 2;
-  GLX_EXTENSIONS = 3;
-
-  GLX_USE_GL = 1;
-  GLX_BUFFER_SIZE = 2;
-  GLX_LEVEL = 3;
-  GLX_RGBA = 4;
-  GLX_DOUBLEBUFFER = 5;
-  GLX_STEREO = 6;
-  GLX_AUX_BUFFERS = 7;
-  GLX_RED_SIZE = 8;
-  GLX_GREEN_SIZE = 9;
-  GLX_BLUE_SIZE = 10;
-  GLX_ALPHA_SIZE = 11;
-  GLX_DEPTH_SIZE = 12;
-  GLX_STENCIL_SIZE = 13;
-  GLX_ACCUM_RED_SIZE = 14;
-  GLX_ACCUM_GREEN_SIZE = 15;
-  GLX_ACCUM_BLUE_SIZE = 16;
-  GLX_ACCUM_ALPHA_SIZE = 17;
-
-  // GLX_VERSION_1_3
-  GLX_WINDOW_BIT = $00000001;
-  GLX_PIXMAP_BIT = $00000002;
-  GLX_PBUFFER_BIT = $00000004;
-  GLX_RGBA_BIT = $00000001;
-  GLX_COLOR_INDEX_BIT = $00000002;
-  GLX_PBUFFER_CLOBBER_MASK = $08000000;
-  GLX_FRONT_LEFT_BUFFER_BIT = $00000001;
-  GLX_FRONT_RIGHT_BUFFER_BIT = $00000002;
-  GLX_BACK_LEFT_BUFFER_BIT = $00000004;
-  GLX_BACK_RIGHT_BUFFER_BIT = $00000008;
-  GLX_AUX_BUFFERS_BIT = $00000010;
-  GLX_DEPTH_BUFFER_BIT = $00000020;
-  GLX_STENCIL_BUFFER_BIT = $00000040;
-  GLX_ACCUM_BUFFER_BIT = $00000080;
-  GLX_CONFIG_CAVEAT = $20;
-  GLX_X_VISUAL_TYPE = $22;
-  GLX_TRANSPARENT_TYPE = $23;
-  GLX_TRANSPARENT_INDEX_VALUE = $24;
-  GLX_TRANSPARENT_RED_VALUE = $25;
-  GLX_TRANSPARENT_GREEN_VALUE = $26;
-  GLX_TRANSPARENT_BLUE_VALUE = $27;
-  GLX_TRANSPARENT_ALPHA_VALUE = $28;
-  GLX_DONT_CARE = $FFFFFFFF;
-  GLX_NONE = $8000;
-  GLX_SLOW_CONFIG = $8001;
-  GLX_TRUE_COLOR = $8002;
-  GLX_DIRECT_COLOR = $8003;
-  GLX_PSEUDO_COLOR = $8004;
-  GLX_STATIC_COLOR = $8005;
-  GLX_GRAY_SCALE = $8006;
-  GLX_STATIC_GRAY = $8007;
-  GLX_TRANSPARENT_RGB = $8008;
-  GLX_TRANSPARENT_INDEX = $8009;
-  GLX_VISUAL_ID = $800B;
-  GLX_SCREEN = $800C;
-  GLX_NON_CONFORMANT_CONFIG = $800D;
-  GLX_DRAWABLE_TYPE = $8010;
-  GLX_RENDER_TYPE = $8011;
-  GLX_X_RENDERABLE = $8012;
-  GLX_FBCONFIG_ID = $8013;
-  GLX_RGBA_TYPE = $8014;
-  GLX_COLOR_INDEX_TYPE = $8015;
-  GLX_MAX_PBUFFER_WIDTH = $8016;
-  GLX_MAX_PBUFFER_HEIGHT = $8017;
-  GLX_MAX_PBUFFER_PIXELS = $8018;
-  GLX_PRESERVED_CONTENTS = $801B;
-  GLX_LARGEST_PBUFFER = $801C;
-  GLX_WIDTH = $801D;
-  GLX_HEIGHT = $801E;
-  GLX_EVENT_MASK = $801F;
-  GLX_DAMAGED = $8020;
-  GLX_SAVED = $8021;
-  GLX_WINDOW = $8022;
-  GLX_PBUFFER = $8023;
-  GLX_PBUFFER_HEIGHT = $8040;
-  GLX_PBUFFER_WIDTH = $8041;
-
-  // GLX_VERSION_1_4
-  GLX_SAMPLE_BUFFERS = 100000;
-  GLX_SAMPLES = 100001;
-
-  // GLX_ARB_multisample
-  GLX_SAMPLE_BUFFERS_ARB = 100000;
-  GLX_SAMPLES_ARB = 100001;
-
-  // GLX_ARB_fbconfig_float
-  GLX_RGBA_FLOAT_TYPE_ARB = $20B9;
-  GLX_RGBA_FLOAT_BIT_ARB = $00000004;
-
-  // GLX_ARB_create_context
-  GLX_CONTEXT_DEBUG_BIT_ARB = $00000001;
-  GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = $00000002;
-  GLX_CONTEXT_MAJOR_VERSION_ARB = $2091;
-  GLX_CONTEXT_MINOR_VERSION_ARB = $2092;
-  GLX_CONTEXT_FLAGS_ARB = $2094;
-
-  // GLX_ARB_create_context_profile
-  GLX_CONTEXT_CORE_PROFILE_BIT_ARB = $00000001;
-  GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = $00000002;
-  GLX_CONTEXT_PROFILE_MASK_ARB = $9126;
-
-  // GLX_EXT_visual_info
-  GLX_X_VISUAL_TYPE_EXT = $22;
-  GLX_TRANSPARENT_TYPE_EXT = $23;
-  GLX_TRANSPARENT_INDEX_VALUE_EXT = $24;
-  GLX_TRANSPARENT_RED_VALUE_EXT = $25;
-  GLX_TRANSPARENT_GREEN_VALUE_EXT = $26;
-  GLX_TRANSPARENT_BLUE_VALUE_EXT = $27;
-  GLX_TRANSPARENT_ALPHA_VALUE_EXT = $28;
-  GLX_NONE_EXT = $8000;
-  GLX_TRUE_COLOR_EXT = $8002;
-  GLX_DIRECT_COLOR_EXT = $8003;
-  GLX_PSEUDO_COLOR_EXT = $8004;
-  GLX_STATIC_COLOR_EXT = $8005;
-  GLX_GRAY_SCALE_EXT = $8006;
-  GLX_STATIC_GRAY_EXT = $8007;
-  GLX_TRANSPARENT_RGB_EXT = $8008;
-  GLX_TRANSPARENT_INDEX_EXT = $8009;
-  
-  // GLX_EXT_visual_rating
-  GLX_VISUAL_CAVEAT_EXT = $20;
-  GLX_SLOW_VISUAL_EXT = $8001;
-  GLX_NON_CONFORMANT_VISUAL_EXT = $800D;
-  (* reuse GLX_NONE_EXT *)
-  
-  // GLX_EXT_import_context
-  GLX_SHARE_CONTEXT_EXT = $800A;
-  GLX_VISUAL_ID_EXT = $800B;
-  GLX_SCREEN_EXT = $800C;
-
-  // GLX_EXT_fbconfig_packed_float
-//  GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT = $20B1;
-//  GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT = $00000008;
-
-  // GLX_EXT_framebuffer_sRGB
-//  GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT = $20B2;
-
-  // GLX_EXT_texture_from_pixmap
-  GLX_TEXTURE_1D_BIT_EXT = $00000001;
-  GLX_TEXTURE_2D_BIT_EXT = $00000002;
-  GLX_TEXTURE_RECTANGLE_BIT_EXT = $00000004;
-  GLX_BIND_TO_TEXTURE_RGB_EXT = $20D0;
-  GLX_BIND_TO_TEXTURE_RGBA_EXT = $20D1;
-  GLX_BIND_TO_MIPMAP_TEXTURE_EXT = $20D2;
-  GLX_BIND_TO_TEXTURE_TARGETS_EXT = $20D3;
-  GLX_Y_INVERTED_EXT = $20D4;
-  GLX_TEXTURE_FORMAT_EXT = $20D5;
-  GLX_TEXTURE_TARGET_EXT = $20D6;
-  GLX_MIPMAP_TEXTURE_EXT = $20D7;
-  GLX_TEXTURE_FORMAT_NONE_EXT = $20D8;
-  GLX_TEXTURE_FORMAT_RGB_EXT = $20D9;
-  GLX_TEXTURE_FORMAT_RGBA_EXT = $20DA;
-  GLX_TEXTURE_1D_EXT = $20DB;
-  GLX_TEXTURE_2D_EXT = $20DC;
-  GLX_TEXTURE_RECTANGLE_EXT = $20DD;
-  GLX_FRONT_LEFT_EXT = $20DE;
-  GLX_FRONT_RIGHT_EXT = $20DF;
-  GLX_BACK_LEFT_EXT = $20E0;
-  GLX_BACK_RIGHT_EXT = $20E1;
-  GLX_FRONT_EXT = GLX_FRONT_LEFT_EXT;
-  GLX_BACK_EXT = GLX_BACK_LEFT_EXT;
-  GLX_AUX0_EXT = $20E2;
-  GLX_AUX1_EXT = $20E3;
-  GLX_AUX2_EXT = $20E4;
-  GLX_AUX3_EXT = $20E5;
-  GLX_AUX4_EXT = $20E6;
-  GLX_AUX5_EXT = $20E7;
-  GLX_AUX6_EXT = $20E8;
-  GLX_AUX7_EXT = $20E9;
-  GLX_AUX8_EXT = $20EA;
-  GLX_AUX9_EXT = $20EB;
-
-
-  // GLU
-  GLU_INVALID_ENUM = 100900;
-  GLU_INVALID_VALUE = 100901;
-  GLU_OUT_OF_MEMORY = 100902;
-  GLU_INCOMPATIBLE_GL_VERSION = 100903;
-  GLU_VERSION = 100800;
-  GLU_EXTENSIONS = 100801;
-  GLU_TRUE = GL_TRUE;
-  GLU_FALSE = GL_FALSE;
-  GLU_SMOOTH = 100000;
-  GLU_FLAT = 100001;
-  GLU_NONE = 100002;
-  GLU_POINT = 100010;
-  GLU_LINE = 100011;
-  GLU_FILL = 100012;
-  GLU_SILHOUETTE = 100013;
-  GLU_OUTSIDE = 100020;
-  GLU_INSIDE = 100021;
-  GLU_TESS_MAX_COORD = 1.0E150;
-  GLU_TESS_WINDING_RULE = 100140;
-  GLU_TESS_BOUNDARY_ONLY = 100141;
-  GLU_TESS_TOLERANCE = 100142;
-  GLU_TESS_WINDING_ODD = 100130;
-  GLU_TESS_WINDING_NONZERO = 100131;
-  GLU_TESS_WINDING_POSITIVE = 100132;
-  GLU_TESS_WINDING_NEGATIVE = 100133;
-  GLU_TESS_WINDING_ABS_GEQ_TWO = 100134;
-  GLU_TESS_BEGIN = 100100; // TGLUTessBeginProc
-  GLU_TESS_VERTEX = 100101; // TGLUTessVertexProc
-  GLU_TESS_END = 100102; // TGLUTessEndProc
-  GLU_TESS_ERROR = 100103; // TGLUTessErrorProc
-  GLU_TESS_EDGE_FLAG = 100104; // TGLUTessEdgeFlagProc
-  GLU_TESS_COMBINE = 100105; // TGLUTessCombineProc
-  GLU_TESS_BEGIN_DATA = 100106; // TGLUTessBeginDataProc
-  GLU_TESS_VERTEX_DATA = 100107; // TGLUTessVertexDataProc
-  GLU_TESS_END_DATA = 100108; // TGLUTessEndDataProc
-  GLU_TESS_ERROR_DATA = 100109; // TGLUTessErrorDataProc
-  GLU_TESS_EDGE_FLAG_DATA = 100110; // TGLUTessEdgeFlagDataProc
-  GLU_TESS_COMBINE_DATA = 100111; // TGLUTessCombineDataProc
-  GLU_TESS_ERROR1 = 100151;
-  GLU_TESS_ERROR2 = 100152;
-  GLU_TESS_ERROR3 = 100153;
-  GLU_TESS_ERROR4 = 100154;
-  GLU_TESS_ERROR5 = 100155;
-  GLU_TESS_ERROR6 = 100156;
-  GLU_TESS_ERROR7 = 100157;
-  GLU_TESS_ERROR8 = 100158;
-  GLU_TESS_MISSING_BEGIN_POLYGON = GLU_TESS_ERROR1;
-  GLU_TESS_MISSING_BEGIN_CONTOUR = GLU_TESS_ERROR2;
-  GLU_TESS_MISSING_END_POLYGON = GLU_TESS_ERROR3;
-  GLU_TESS_MISSING_END_CONTOUR = GLU_TESS_ERROR4;
-  GLU_TESS_COORD_TOO_LARGE = GLU_TESS_ERROR5;
-  GLU_TESS_NEED_COMBINE_CALLBACK = GLU_TESS_ERROR6;
-  GLU_AUTO_LOAD_MATRIX = 100200;
-  GLU_CULLING = 100201;
-  GLU_SAMPLING_TOLERANCE = 100203;
-  GLU_DISPLAY_MODE = 100204;
-  GLU_PARAMETRIC_TOLERANCE = 100202;
-  GLU_SAMPLING_METHOD = 100205;
-  GLU_U_STEP = 100206;
-  GLU_V_STEP = 100207;
-  GLU_PATH_LENGTH = 100215;
-  GLU_PARAMETRIC_ERROR = 100216;
-  GLU_DOMAIN_DISTANCE = 100217;
-  GLU_MAP1_TRIM_2 = 100210;
-  GLU_MAP1_TRIM_3 = 100211;
-  GLU_OUTLINE_POLYGON = 100240;
-  GLU_OUTLINE_PATCH = 100241;
-  GLU_NURBS_ERROR1 = 100251;
-  GLU_NURBS_ERROR2 = 100252;
-  GLU_NURBS_ERROR3 = 100253;
-  GLU_NURBS_ERROR4 = 100254;
-  GLU_NURBS_ERROR5 = 100255;
-  GLU_NURBS_ERROR6 = 100256;
-  GLU_NURBS_ERROR7 = 100257;
-  GLU_NURBS_ERROR8 = 100258;
-  GLU_NURBS_ERROR9 = 100259;
-  GLU_NURBS_ERROR10 = 100260;
-  GLU_NURBS_ERROR11 = 100261;
-  GLU_NURBS_ERROR12 = 100262;
-  GLU_NURBS_ERROR13 = 100263;
-  GLU_NURBS_ERROR14 = 100264;
-  GLU_NURBS_ERROR15 = 100265;
-  GLU_NURBS_ERROR16 = 100266;
-  GLU_NURBS_ERROR17 = 100267;
-  GLU_NURBS_ERROR18 = 100268;
-  GLU_NURBS_ERROR19 = 100269;
-  GLU_NURBS_ERROR20 = 100270;
-  GLU_NURBS_ERROR21 = 100271;
-  GLU_NURBS_ERROR22 = 100272;
-  GLU_NURBS_ERROR23 = 100273;
-  GLU_NURBS_ERROR24 = 100274;
-  GLU_NURBS_ERROR25 = 100275;
-  GLU_NURBS_ERROR26 = 100276;
-  GLU_NURBS_ERROR27 = 100277;
-  GLU_NURBS_ERROR28 = 100278;
-  GLU_NURBS_ERROR29 = 100279;
-  GLU_NURBS_ERROR30 = 100280;
-  GLU_NURBS_ERROR31 = 100281;
-  GLU_NURBS_ERROR32 = 100282;
-  GLU_NURBS_ERROR33 = 100283;
-  GLU_NURBS_ERROR34 = 100284;
-  GLU_NURBS_ERROR35 = 100285;
-  GLU_NURBS_ERROR36 = 100286;
-  GLU_NURBS_ERROR37 = 100287;
-  GLU_CW = 100120;
-  GLU_CCW = 100121;
-  GLU_INTERIOR = 100122;
-  GLU_EXTERIOR = 100123;
-  GLU_UNKNOWN = 100124;
-  GLU_BEGIN = GLU_TESS_BEGIN;
-  GLU_VERTEX = GLU_TESS_VERTEX;
-  GLU_END = GLU_TESS_END;
-  GLU_ERROR = GLU_TESS_ERROR;
-  GLU_EDGE_FLAG = GLU_TESS_EDGE_FLAG;
-
-type
-  // GL_VERSION_1_0
-  TglCullFace = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFrontFace = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglHint = procedure(target: TGLenum; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLineWidth = procedure(width: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointSize = procedure(size: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPolygonMode = procedure(face: TGLenum; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglScissor = procedure(x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameterf = procedure(target: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameterfv = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameteri = procedure(target: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameteriv = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexImage1D = procedure(target: TGLenum; level: TGLint; internalformat: TGLint; width: TGLsizei; border: TGLint; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexImage2D = procedure(target: TGLenum; level: TGLint; internalformat: TGLint; width: TGLsizei; height: TGLsizei; border: TGLint; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawBuffer = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClear = procedure(mask: TGLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearColor = procedure(red: TGLclampf; green: TGLclampf; blue: TGLclampf; alpha: TGLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearStencil = procedure(s: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearDepth = procedure(depth: TGLclampd); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStencilMask = procedure(mask: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorMask = procedure(red: TGLboolean; green: TGLboolean; blue: TGLboolean; alpha: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDepthMask = procedure(flag: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisable = procedure(cap: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnable = procedure(cap: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFinish = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFlush = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBlendFunc = procedure(sfactor: TGLenum; dfactor: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLogicOp = procedure(opcode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStencilFunc = procedure(func: TGLenum; ref: TGLint; mask: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStencilOp = procedure(fail: TGLenum; zfail: TGLenum; zpass: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDepthFunc = procedure(func: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelStoref = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelStorei = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReadBuffer = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReadPixels = procedure(x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBooleanv = procedure(pname: TGLenum; params: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetDoublev = procedure(pname: TGLenum; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetError = function(): TGLenum; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFloatv = procedure(pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetIntegerv = procedure(pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetString = function(name: TGLenum): PAnsiChar; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexImage = procedure(target: TGLenum; level: TGLint; format: TGLenum; _type: TGLenum; pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexParameteriv = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexParameterfv = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexLevelParameterfv = procedure(target: TGLenum; level: TGLint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexLevelParameteriv = procedure(target: TGLenum; level: TGLint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsEnabled = function(cap: TGLenum): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDepthRange = procedure(zNear: TGLclampd; zFar: TGLclampd); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglViewport = procedure(x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_VERSION_1_1
-  TglDrawArrays = procedure(mode: TGLenum; first: TGLint; count: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawElements = procedure(mode: TGLenum; count: TGLsizei; _type: TGLenum; const indices: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPointerv = procedure(pname: TGLenum; params: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPolygonOffset = procedure(factor: TGLfloat; units: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexImage1D = procedure(target: TGLenum; level: TGLint; internalFormat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei; border: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexImage2D = procedure(target: TGLenum; level: TGLint; internalFormat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei; border: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexSubImage1D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexSubImage2D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexSubImage1D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; width: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexSubImage2D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindTexture = procedure(target: TGLenum; texture: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteTextures = procedure(n: TGLsizei; const textures: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenTextures = procedure(n: TGLsizei; textures: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  
-{$ifdef DGL_DEPRECATED}
-  TglAccum = procedure(op: TGLenum; value: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglAlphaFunc = procedure(func: TGLenum; ref: TGLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglAreTexturesResident = function(n: TGLsizei; const textures: PGLuint; residences: PGLboolean): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglArrayElement = procedure(i: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBegin = procedure(mode: TGLenum); {$IFNDEF CLR}{$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}{$ENDIF}
-  TglBitmap = procedure(width: TGLsizei; height: TGLsizei; xorig: TGLfloat; yorig: TGLfloat; xmove: TGLfloat; ymove: TGLfloat; const bitmap: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCallList = procedure(list: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCallLists = procedure(n: TGLsizei; _type: TGLenum; const lists: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearAccum = procedure(red: TGLfloat; green: TGLfloat; blue: TGLfloat; alpha: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearIndex = procedure(c: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClipPlane = procedure(plane: TGLenum; const equation: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3b = procedure(red: TGLbyte; green: TGLbyte; blue: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3bv = procedure(const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3d = procedure(red: TGLdouble; green: TGLdouble; blue: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3f = procedure(red: TGLfloat; green: TGLfloat; blue: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3i = procedure(red: TGLint; green: TGLint; blue: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3s = procedure(red: TGLshort; green: TGLshort; blue: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3ub = procedure(red: TGLubyte; green: TGLubyte; blue: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3ubv = procedure(const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3ui = procedure(red: TGLuint; green: TGLuint; blue: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3uiv = procedure(const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3us = procedure(red: TGLushort; green: TGLushort; blue: TGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3usv = procedure(const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4b = procedure(red: TGLbyte; green: TGLbyte; blue: TGLbyte; alpha: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4bv = procedure(const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4d = procedure(red: TGLdouble; green: TGLdouble; blue: TGLdouble; alpha: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4f = procedure(red: TGLfloat; green: TGLfloat; blue: TGLfloat; alpha: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4i = procedure(red: TGLint; green: TGLint; blue: TGLint; alpha: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4s = procedure(red: TGLshort; green: TGLshort; blue: TGLshort; alpha: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4ub = procedure(red: TGLubyte; green: TGLubyte; blue: TGLubyte; alpha: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4ubv = procedure(const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4ui = procedure(red: TGLuint; green: TGLuint; blue: TGLuint; alpha: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4uiv = procedure(const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4us = procedure(red: TGLushort; green: TGLushort; blue: TGLushort; alpha: TGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4usv = procedure(const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorMaterial = procedure(face: TGLenum; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorPointer = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyPixels = procedure(x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei; _type: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteLists = procedure(list: TGLuint; range: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisableClientState = procedure(_array: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawPixels = procedure(width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEdgeFlag = procedure(flag: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEdgeFlagPointer = procedure(stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEdgeFlagv = procedure(const flag: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnableClientState = procedure(_array: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnd = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndList = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord1d = procedure(u: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord1dv = procedure(const u: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord1f = procedure(u: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord1fv = procedure(const u: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord2d = procedure(u: TGLdouble; v: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord2dv = procedure(const u: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord2f = procedure(u: TGLfloat; v: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalCoord2fv = procedure(const u: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalMesh1 = procedure(mode: TGLenum; i1: TGLint; i2: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalMesh2 = procedure(mode: TGLenum; i1: TGLint; i2: TGLint; j1: TGLint; j2: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalPoint1 = procedure(i: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalPoint2 = procedure(i: TGLint; j: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFeedbackBuffer = procedure(size: TGLsizei; _type: TGLenum; buffer: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogf = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogfv = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogi = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogiv = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFrustum = procedure(left: TGLdouble; right: TGLdouble; bottom: TGLdouble; top: TGLdouble; zNear: TGLdouble; zFar: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenLists = function(range: TGLsizei): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetClipPlane = procedure(plane: TGLenum; equation: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetLightfv = procedure(light: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetLightiv = procedure(light: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapdv = procedure(target: TGLenum; query: TGLenum; v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapfv = procedure(target: TGLenum; query: TGLenum; v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapiv = procedure(target: TGLenum; query: TGLenum; v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMaterialfv = procedure(face: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMaterialiv = procedure(face: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPixelMapfv = procedure(map: TGLenum; values: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPixelMapuiv = procedure(map: TGLenum; values: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPixelMapusv = procedure(map: TGLenum; values: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPolygonStipple = procedure(mask: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexEnvfv = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexEnviv = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexGendv = procedure(coord: TGLenum; pname: TGLenum; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexGenfv = procedure(coord: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexGeniv = procedure(coord: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexMask = procedure(mask: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexPointer = procedure(_type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexd = procedure(c: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexdv = procedure(const c: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexf = procedure(c: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexfv = procedure(const c: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexi = procedure(c: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexiv = procedure(const c: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexs = procedure(c: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexsv = procedure(const c: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexub = procedure(c: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexubv = procedure(const c: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglInitNames = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglInterleavedArrays = procedure(format: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsList = function(list: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsTexture = function(texture: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightModelf = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightModelfv = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightModeli = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightModeliv = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightf = procedure(light: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightfv = procedure(light: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLighti = procedure(light: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightiv = procedure(light: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLineStipple = procedure(factor: TGLint; pattern: TGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglListBase = procedure(base: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadIdentity = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadMatrixd = procedure(const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadMatrixf = procedure(const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadName = procedure(name: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMap1d = procedure(target: TGLenum; u1: TGLdouble; u2: TGLdouble; stride: TGLint; order: TGLint; const points: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMap1f = procedure(target: TGLenum; u1: TGLfloat; u2: TGLfloat; stride: TGLint; order: TGLint; const points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMap2d = procedure(target: TGLenum; u1: TGLdouble; u2: TGLdouble; ustride: TGLint; uorder: TGLint; v1: TGLdouble; v2: TGLdouble; vstride: TGLint; vorder: TGLint; const points: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMap2f = procedure(target: TGLenum; u1: TGLfloat; u2: TGLfloat; ustride: TGLint; uorder: TGLint; v1: TGLfloat; v2: TGLfloat; vstride: TGLint; vorder: TGLint; const points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapGrid1d = procedure(un: TGLint; u1: TGLdouble; u2: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapGrid1f = procedure(un: TGLint; u1: TGLfloat; u2: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapGrid2d = procedure(un: TGLint; u1: TGLdouble; u2: TGLdouble; vn: TGLint; v1: TGLdouble; v2: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapGrid2f = procedure(un: TGLint; u1: TGLfloat; u2: TGLfloat; vn: TGLint; v1: TGLfloat; v2: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMaterialf = procedure(face: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMaterialfv = procedure(face: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMateriali = procedure(face: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMaterialiv = procedure(face: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixMode = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultMatrixd = procedure(const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultMatrixf = procedure(const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNewList = procedure(list: TGLuint; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3b = procedure(nx: TGLbyte; ny: TGLbyte; nz: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3bv = procedure(const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3d = procedure(nx: TGLdouble; ny: TGLdouble; nz: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3f = procedure(nx: TGLfloat; ny: TGLfloat; nz: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3i = procedure(nx: TGLint; ny: TGLint; nz: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3s = procedure(nx: TGLshort; ny: TGLshort; nz: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalPointer = procedure(_type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglOrtho = procedure(left: TGLdouble; right: TGLdouble; bottom: TGLdouble; top: TGLdouble; zNear: TGLdouble; zFar: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPassThrough = procedure(token: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelMapfv = procedure(map: TGLenum; mapsize: TGLsizei; const values: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelMapuiv = procedure(map: TGLenum; mapsize: TGLsizei; const values: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelMapusv = procedure(map: TGLenum; mapsize: TGLsizei; const values: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTransferf = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTransferi = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelZoom = procedure(xfactor: TGLfloat; yfactor: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPolygonStipple = procedure(const mask: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPopAttrib = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPopClientAttrib = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPopMatrix = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPopName = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPrioritizeTextures = procedure(n: TGLsizei; const textures: PGLuint; const priorities: PGLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPushAttrib = procedure(mask: TGLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPushClientAttrib = procedure(mask: TGLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPushMatrix = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPushName = procedure(name: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2d = procedure(x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2f = procedure(x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2i = procedure(x: TGLint; y: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2s = procedure(x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos2sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3d = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3f = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3i = procedure(x: TGLint; y: TGLint; z: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3s = procedure(x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos3sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4d = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4f = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4i = procedure(x: TGLint; y: TGLint; z: TGLint; w: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4s = procedure(x: TGLshort; y: TGLshort; z: TGLshort; w: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRasterPos4sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRectd = procedure(x1: TGLdouble; y1: TGLdouble; x2: TGLdouble; y2: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRectdv = procedure(const v1: PGLdouble; const v2: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRectf = procedure(x1: TGLfloat; y1: TGLfloat; x2: TGLfloat; y2: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRectfv = procedure(const v1: PGLfloat; const v2: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRecti = procedure(x1: TGLint; y1: TGLint; x2: TGLint; y2: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRectiv = procedure(const v1: PGLint; const v2: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRects = procedure(x1: TGLshort; y1: TGLshort; x2: TGLshort; y2: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRectsv = procedure(const v1: PGLshort; const v2: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRenderMode = function(mode: TGLenum): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRotated = procedure(angle: TGLdouble; x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRotatef = procedure(angle: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglScaled = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglScalef = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSelectBuffer = procedure(size: TGLsizei; buffer: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglShadeModel = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1d = procedure(s: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1f = procedure(s: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1i = procedure(s: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1s = procedure(s: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2d = procedure(s: TGLdouble; t: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2f = procedure(s: TGLfloat; t: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2i = procedure(s: TGLint; t: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2s = procedure(s: TGLshort; t: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3d = procedure(s: TGLdouble; t: TGLdouble; r: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3f = procedure(s: TGLfloat; t: TGLfloat; r: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3i = procedure(s: TGLint; t: TGLint; r: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3s = procedure(s: TGLshort; t: TGLshort; r: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4d = procedure(s: TGLdouble; t: TGLdouble; r: TGLdouble; q: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4f = procedure(s: TGLfloat; t: TGLfloat; r: TGLfloat; q: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4i = procedure(s: TGLint; t: TGLint; r: TGLint; q: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4s = procedure(s: TGLshort; t: TGLshort; r: TGLshort; q: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoordPointer = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexEnvf = procedure(target: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexEnvfv = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexEnvi = procedure(target: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexEnviv = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexGend = procedure(coord: TGLenum; pname: TGLenum; param: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexGendv = procedure(coord: TGLenum; pname: TGLenum; const params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexGenf = procedure(coord: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexGenfv = procedure(coord: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexGeni = procedure(coord: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexGeniv = procedure(coord: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-
-  TglTranslated = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTranslatef = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2d = procedure(x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2f = procedure(x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2i = procedure(x: TGLint; y: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2s = procedure(x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3d = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3f = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3i = procedure(x: TGLint; y: TGLint; z: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3s = procedure(x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4d = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4f = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4i = procedure(x: TGLint; y: TGLint; z: TGLint; w: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4s = procedure(x: TGLshort; y: TGLshort; z: TGLshort; w: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexPointer = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-{$endif}
-
-  // GL_VERSION_1_2
-  TglBlendColor = procedure(red: TGLclampf; green: TGLclampf; blue: TGLclampf; alpha: TGLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBlendEquation = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawRangeElements = procedure(mode: TGLenum; start: TGLuint; _end: TGLuint; count: TGLsizei; _type: TGLenum; const indices: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexImage3D = procedure(target: TGLenum; level: TGLint; internalformat: TGLint; width: TGLsizei; height: TGLsizei; depth: TGLsizei; border: TGLint; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexSubImage3D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; zoffset: TGLint; width: TGLsizei; height: TGLsizei; depth: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexSubImage3D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; zoffset: TGLint; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-{$ifdef DGL_DEPRECATED}
-  TglColorTable = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; format: TGLenum; _type: TGLenum; const table: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorTableParameterfv = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorTableParameteriv = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyColorTable = procedure(target: TGLenum; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTable = procedure(target: TGLenum; format: TGLenum; _type: TGLenum; table: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableParameterfv = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableParameteriv = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorSubTable = procedure(target: TGLenum; start: TGLsizei; count: TGLsizei; format: TGLenum; _type: TGLenum; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyColorSubTable = procedure(target: TGLenum; start: TGLsizei; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionFilter1D = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; format: TGLenum; _type: TGLenum; const image: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionFilter2D = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; const image: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameterf = procedure(target: TGLenum; pname: TGLenum; params: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameterfv = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameteri = procedure(target: TGLenum; pname: TGLenum; params: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameteriv = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyConvolutionFilter1D = procedure(target: TGLenum; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyConvolutionFilter2D = procedure(target: TGLenum; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetConvolutionFilter = procedure(target: TGLenum; format: TGLenum; _type: TGLenum; image: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetConvolutionParameterfv = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetConvolutionParameteriv = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetSeparableFilter = procedure(target: TGLenum; format: TGLenum; _type: TGLenum; row: PGLvoid; column: PGLvoid; span: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSeparableFilter2D = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; const row: PGLvoid; const column: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetHistogram = procedure(target: TGLenum; reset: TGLboolean; format: TGLenum; _type: TGLenum; values: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetHistogramParameterfv = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetHistogramParameteriv = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMinmax = procedure(target: TGLenum; reset: TGLboolean; format: TGLenum; _type: TGLenum; values: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMinmaxParameterfv = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMinmaxParameteriv = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglHistogram = procedure(target: TGLenum; width: TGLsizei; internalformat: TGLenum; sink: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMinmax = procedure(target: TGLenum; internalformat: TGLenum; sink: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglResetHistogram = procedure(target: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglResetMinmax = procedure(target: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-{$endif}
-
-  // GL_VERSION_1_3
-  TglActiveTexture = procedure(texture: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSampleCoverage = procedure(value: TGLclampf; invert: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexImage3D = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; depth: TGLsizei; border: TGLint; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexImage2D = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; border: TGLint; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexImage1D = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; border: TGLint; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexSubImage3D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; zoffset: TGLint; width: TGLsizei; height: TGLsizei; depth: TGLsizei; format: TGLenum; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexSubImage2D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; width: TGLsizei; height: TGLsizei; format: TGLenum; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexSubImage1D = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; width: TGLsizei; format: TGLenum; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCompressedTexImage = procedure(target: TGLenum; level: TGLint; img: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-{$ifdef DGL_DEPRECATED}
-  TglClientActiveTexture = procedure(texture: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1d = procedure(target: TGLenum; s: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1dv = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1f = procedure(target: TGLenum; s: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1fv = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1i = procedure(target: TGLenum; s: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1iv = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1s = procedure(target: TGLenum; s: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1sv = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2d = procedure(target: TGLenum; s: TGLdouble; t: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2dv = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2f = procedure(target: TGLenum; s: TGLfloat; t: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2fv = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2i = procedure(target: TGLenum; s: TGLint; t: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2iv = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2s = procedure(target: TGLenum; s: TGLshort; t: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2sv = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3d = procedure(target: TGLenum; s: TGLdouble; t: TGLdouble; r: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3dv = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3f = procedure(target: TGLenum; s: TGLfloat; t: TGLfloat; r: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3fv = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3i = procedure(target: TGLenum; s: TGLint; t: TGLint; r: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3iv = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3s = procedure(target: TGLenum; s: TGLshort; t: TGLshort; r: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3sv = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4d = procedure(target: TGLenum; s: TGLdouble; t: TGLdouble; r: TGLdouble; q: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4dv = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4f = procedure(target: TGLenum; s: TGLfloat; t: TGLfloat; r: TGLfloat; q: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4fv = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4i = procedure(target: TGLenum; s: TGLint; t: TGLint; r: TGLint; q: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4iv = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4s = procedure(target: TGLenum; s: TGLshort; t: TGLshort; r: TGLshort; q: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4sv = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadTransposeMatrixf = procedure(const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadTransposeMatrixd = procedure(const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultTransposeMatrixf = procedure(const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultTransposeMatrixd = procedure(const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-{$endif}
-
-  // GL_VERSION_1_4
-  TglBlendFuncSeparate = procedure(sfactorRGB: TGLenum; dfactorRGB: TGLenum; sfactorAlpha: TGLenum; dfactorAlpha: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiDrawArrays = procedure(mode: TGLenum; first: PGLint; count: PGLsizei; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiDrawElements = procedure(mode: TGLenum; const count: PGLsizei; _type: TGLenum; const indices: PGLvoid; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameterf = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameterfv = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameteri = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameteriv = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-{$ifdef DGL_DEPRECATED}
-  TglFogCoordf = procedure(coord: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordfv = procedure(const coord: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordd = procedure(coord: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoorddv = procedure(const coord: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordPointer = procedure(_type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3b = procedure(red: TGLbyte; green: TGLbyte; blue: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3bv = procedure(const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3d = procedure(red: TGLdouble; green: TGLdouble; blue: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3f = procedure(red: TGLfloat; green: TGLfloat; blue: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3i = procedure(red: TGLint; green: TGLint; blue: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3s = procedure(red: TGLshort; green: TGLshort; blue: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3ub = procedure(red: TGLubyte; green: TGLubyte; blue: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3ubv = procedure(const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3ui = procedure(red: TGLuint; green: TGLuint; blue: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3uiv = procedure(const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3us = procedure(red: TGLushort; green: TGLushort; blue: TGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3usv = procedure(const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColorPointer = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2d = procedure(x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2f = procedure(x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2i = procedure(x: TGLint; y: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2s = procedure(x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3d = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3dv = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3f = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3fv = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3i = procedure(x: TGLint; y: TGLint; z: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3iv = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3s = procedure(x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3sv = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-{$endif}
-
-  // GL_VERSION_1_5
-  TglGenQueries = procedure(n: GLsizei; ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteQueries = procedure(n: GLsizei; const ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsQuery = function(id: GLuint): boolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBeginQuery = procedure(target: GLenum; id: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndQuery = procedure(target: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetQueryiv = procedure(target, pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetQueryObjectiv = procedure(id: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetQueryObjectuiv = procedure(id: GLuint; pname: GLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBuffer = procedure(target: TGLenum; buffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteBuffers = procedure(n: TGLsizei; const buffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenBuffers = procedure(n: TGLsizei; buffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsBuffer = function(buffer: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBufferData = procedure(target: TGLenum; size: TGLsizei; const data: PGLvoid; usage: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBufferSubData = procedure(target: TGLenum; offset: TGLsizei; size: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBufferSubData = procedure(target: TGLenum; offset: TGLsizei; size: TGLsizei; data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapBuffer = function(target: TGLenum; access: TGLenum): PGLvoid; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUnmapBuffer = function(target: TGLenum): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBufferParameteriv = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBufferPointerv = procedure(target: TGLenum; pname: TGLenum; params: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_VERSION_2_0
-  TglBlendEquationSeparate = procedure(modeRGB: GLenum; modeAlpha: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawBuffers = procedure(n: GLsizei; const bufs: PGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStencilOpSeparate = procedure(face: GLenum; sfail: GLenum; dpfail: GLenum; dppass: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStencilFuncSeparate = procedure(frontfunc: GLenum; backfunc: GLenum; ref: GLint; mask: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStencilMaskSeparate = procedure(face: GLenum; mask: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglAttachShader = procedure(programObj, shaderObj: GLhandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindAttribLocation = procedure(programObj: GLhandle; index: GLuint; name: PGLChar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompileShader = procedure(shaderObj: GLhandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCreateProgram = function: GLhandle; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCreateShader = function(shaderType: GLenum): GLhandle; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteProgram = procedure(programObj: GLhandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteShader = procedure(shaderObj: GLhandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDetachShader = procedure(programObj, shaderObj: GLhandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisableVertexAttribArray = procedure(index: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnableVertexAttribArray = procedure(index: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveAttrib = procedure(programObj: GLhandle; index: GLuint; maxlength: GLsizei; var length: GLint; var size: GLint; var _type: GLenum; name: PGLChar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveUniform = procedure(programObj: GLhandle; index: GLuint; maxLength: GLsizei; var length: GLsizei; var size: GLint; var _type: GLenum; name: PGLChar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetAttachedShaders = procedure(programObj: GLhandle; MaxCount: GLsizei; var Count: GLint; shaders: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetAttribLocation = function(programObj: GLhandle; char: string): glint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramiv = procedure(programObj: GLhandle; pname: TGLenum; params: PGLInt); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramInfoLog = procedure(programObj: GLHandle; maxLength: glsizei; var length: GLint; infoLog: PGLChar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetShaderiv = procedure(shaderObj: GLhandle; pname: TGLenum; params: PGLInt); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetShaderInfoLog = procedure(shaderObj: GLHandle; maxLength: glsizei; var length: glint; infoLog: PGLChar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetShaderSource = procedure(shaderObj: GLhandle; maxlength: GLsizei; var length: GLsizei; source: PGLChar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformLocation = function(programObj: GLhandle; const char: PGLChar): glint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformfv = procedure(programObj: GLhandle; location: GLint; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformiv = procedure(programObj: GLhandle; location: GLint; params: PGLInt); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribfv = procedure(index: GLuint; pname: GLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribiv = procedure(index: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribPointerv = procedure(index: GLuint; pname: GLenum; _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsProgram = function(programObj: GLhandle) : TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsShader = function(shaderObj: GLhandle) : TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLinkProgram = procedure(programObj: GLHandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglShaderSource = procedure(shaderObj: GLHandle; count: glsizei; _string: PPGLChar; lengths: pglint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUseProgram = procedure(programObj: GLhandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1f = procedure(location: GLint; v0: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2f = procedure(location: GLint; v0, v1: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3f = procedure(location: GLint; v0, v1, v2: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4f = procedure(location: GLint; v0, v1, v2, v3: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1i = procedure(location: GLint; v0: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2i = procedure(location: GLint; v0, v1: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3i = procedure(location: GLint; v0, v1, v2: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4i = procedure(location: GLint; v0, v1, v2, v3: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1fv = procedure(location: GLint; count: GLsizei; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2fv = procedure(location: GLint; count: GLsizei; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3fv = procedure(location: GLint; count: GLsizei; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4fv = procedure(location: GLint; count: GLsizei; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1iv = procedure(location: GLint; count: GLsizei; value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2iv = procedure(location: GLint; count: GLsizei; value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3iv = procedure(location: GLint; count: GLsizei; value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4iv = procedure(location: GLint; count: GLsizei; value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix2fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix3fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix4fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglValidateProgram = procedure(programObj: GLhandle); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1d = procedure(index: GLuint; x: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1dv = procedure(index: GLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1f = procedure(index: GLuint; x: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1fv = procedure(index: GLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1s = procedure(index: GLuint; x: GLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1sv = procedure(index: GLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2d = procedure(index: GLuint; x: GLdouble; y: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2dv = procedure(index: GLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2f = procedure(index: GLuint; x: GLfloat; y: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2fv = procedure(index: GLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2s = procedure(index: GLuint; x: GLshort; y: GLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2sv = procedure(index: GLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3d = procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3dv = procedure(index: GLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3f = procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3fv = procedure(index: GLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3s = procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3sv = procedure(index: GLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4Nbv = procedure(index: GLuint; const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4Niv = procedure(index: GLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4Nsv = procedure(index: GLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4Nub = procedure(index: GLuint; x: GLubyte; y: GLubyte; z: GLubyte; w: GLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4Nubv = procedure(index: GLuint; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4Nuiv = procedure(index: GLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4Nusv = procedure(index: GLuint; const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4bv = procedure(index: GLuint; const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4d = procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4dv = procedure(index: GLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4f = procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4fv = procedure(index: GLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4iv = procedure(index: GLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4s = procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort; w: GLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4sv = procedure(index: GLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4ubv = procedure(index: GLuint; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4uiv = procedure(index: GLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4usv = procedure(index: GLuint; const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribPointer = procedure(index: GLuint; size: GLint; _type: GLenum; normalized: GLboolean; stride: GLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_VERSION_2_1
-  TglUniformMatrix2x3fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix3x2fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix2x4fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix4x2fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix3x4fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix4x3fv = procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_VERSION_3_0
-  { OpenGL 3.0 also reuses entry points from these extensions: }
-  { ARB_framebuffer_object }
-  { ARB_map_buffer_range }
-  { ARB_vertex_array_object }
-  TglColorMaski = procedure(index_: GLuint; r: GLboolean; g: GLboolean; b: GLboolean; a: GLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBooleani_v = procedure(target: GLenum; index_: GLuint; data: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetIntegeri_v = procedure(target: GLenum; index_: GLuint; data: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnablei = procedure(target: GLenum; index_: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisablei = procedure(target: GLenum; index_: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsEnabledi = function(target: GLenum; index_: GLuint): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBeginTransformFeedback = procedure(primitiveMode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndTransformFeedback = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferRange = procedure(target: GLenum; index_: GLuint; buffer: GLuint; offset: GLsizei; size: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferBase = procedure(target: GLenum; index_: GLuint; buffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTransformFeedbackVaryings = procedure(program_: GLuint; count: GLsizei; const varyings: PPGLchar; bufferMode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTransformFeedbackVarying = procedure(program_: GLuint; index_: GLuint; bufSize: GLsizei; length: PGLsizei; size: PGLsizei; type_: PGLsizei; name: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClampColor = procedure(targe: GLenum; clamp: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBeginConditionalRender = procedure(id: GLuint; mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndConditionalRender = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribIPointer = procedure(index_: GLuint; size: GLint; type_: GLenum; stride: GLsizei; const pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribIiv = procedure(index_: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribIuiv = procedure(index_: GLuint; pname: GLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI1i = procedure(index_: GLuint; x: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2i = procedure(index_: GLuint; x: GLint; y: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3i = procedure(index_: GLuint; x: GLint; y: GLint; z: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4i = procedure(index_: GLuint; x: GLint; y: GLint; z: GLint; w: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI1ui = procedure(index_: GLuint; x: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2ui = procedure(index_: GLuint; x: GLuint; y: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3ui = procedure(index_: GLuint; x: GLuint; y: GLuint; z: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4ui = procedure(index_: GLuint; x: GLuint; y: GLuint; z: GLuint; w: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI1iv = procedure(index_: GLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2iv = procedure(index_: GLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3iv = procedure(index_: GLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4iv = procedure(index_: GLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI1uiv = procedure(index_: GLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2uiv = procedure(index_: GLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3uiv = procedure(index_: GLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4uiv = procedure(index_: GLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4bv = procedure(index_: GLuint; const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4sv = procedure(index_: GLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4ubv = procedure(index_: GLuint; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4usv = procedure(index_: GLuint; const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformuiv = procedure(program_: GLuint; location: GLint; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindFragDataLocation = procedure(program_: GLuint; color: GLuint; const name: PGLChar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFragDataLocation = function(program_: GLuint; const name: PGLChar): GLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1ui = procedure(location: GLint; v0: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2ui = procedure(location: GLint; v0: GLuint; v1: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3ui = procedure(location: GLint; v0: GLuint; v1: GLuint; v2: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4ui = procedure(location: GLint; v0: GLuint; v1: GLuint; v2: GLuint; v3: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1uiv = procedure(location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2uiv = procedure(location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3uiv = procedure(location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4uiv = procedure(location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameterIiv = procedure(target: GLenum; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameterIuiv = procedure(target: GLenum; pname: GLenum; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexParameterIiv = procedure(target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexParameterIuiv = procedure(target: GLenum; pname: GLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearBufferiv = procedure(buffer: GLenum; drawbuffer: GLint; const value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearBufferuiv = procedure(buffer: GLenum; drawbuffer: GLint; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearBufferfv = procedure(buffer: GLenum; drawbuffer: GLint; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearBufferfi = procedure(buffer: GLenum; drawbuffer: GLint; depth: GLfloat; stencil: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetStringi = function(name: GLenum; index: GLuint): PGLubyte; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_VERSION_3_1
-  { OpenGL 3.1 also reuses entry points from these extensions: }
-  { ARB_copy_buffer }
-  { ARB_uniform_buffer_object }
-  TglDrawArraysInstanced = procedure(mode: GLenum; first: GLint; count: GLsizei; primcount: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawElementsInstanced = procedure(mode: GLenum; count: GLsizei; type_: GLenum; const indices: PGLvoid; primcount: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexBuffer = procedure(target: GLenum; internalformat: GLenum; buffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPrimitiveRestartIndex = procedure(index_: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_VERSION_3_2
-  { OpenGL 3.2 also reuses entry points from these extensions: }
-  { ARB_draw_elements_base_vertex }
-  { ARB_provoking_vertex }
-  { ARB_sync }
-  { ARB_texture_multisample }
-  TglGetInteger64i_v = procedure(target: GLenum; index_: GLuint; data: PGLint64); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBufferParameteri64v = procedure(target: GLenum; pname: GLenum; params: PGLint64); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramParameteri = procedure(program_: GLuint; pname: GLenum; value: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTexture = procedure(target: GLenum; attachment: GLenum; texture: GLuint; level: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTextureFace = procedure(target: GLenum; attachment: GLenum; texture: GLuint; level: GLint; face: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  
-  // GL_3DFX_tbuffer
-  TglTbufferMask3DFX = procedure(mask: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_APPLE_element_array
-  TglElementPointerAPPLE = procedure(_type: TGLenum; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawElementArrayAPPLE = procedure(mode: TGLenum; first: TGLint; count: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawRangeElementArrayAPPLE = procedure(mode: TGLenum; start: TGLuint; _end: TGLuint; first: TGLint; count: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiDrawElementArrayAPPLE = procedure(mode: TGLenum; const first: PGLint; const count: PGLsizei; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiDrawRangeElementArrayAPPLE = procedure(mode: TGLenum; start: TGLuint; _end: TGLuint; const first: PGLint; const count: PGLsizei; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_APPLE_fence
-  TglGenFencesAPPLE = procedure(n: TGLsizei; fences: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteFencesAPPLE = procedure(n: TGLsizei; const fences: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSetFenceAPPLE = procedure(fence: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsFenceAPPLE = function(fence: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTestFenceAPPLE = function(fence: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFinishFenceAPPLE = procedure(fence: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTestObjectAPPLE = function(_object: TGLenum; name: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFinishObjectAPPLE = procedure(_object: TGLenum; name: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_APPLE_vertex_array_object
-  TglBindVertexArrayAPPLE = procedure(_array: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteVertexArraysAPPLE = procedure(n: TGLsizei; const arrays: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenVertexArraysAPPLE = procedure(n: TGLsizei; const arrays: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsVertexArrayAPPLE = function(_array: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_APPLE_vertex_array_range
-  TglVertexArrayRangeAPPLE = procedure(length: TGLsizei; _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFlushVertexArrayRangeAPPLE = procedure(length: TGLsizei; _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexArrayParameteriAPPLE = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_APPLE_texture_range
-  TglTextureRangeAPPLE = procedure(target: GLenum; length: GLsizei; const Pointer_: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexParameterPointervAPPLE = procedure(target: GLenum; pname: GLenum; params: PPGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_APPLE_vertex_program_evaluators
-  TglEnableVertexAttribAPPLE = procedure(index_: GLuint; pname: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisableVertexAttribAPPLE = procedure(index_: GLuint; pname: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsVertexAttribEnabledAPPLE = function(index_: GLuint; pname: GLenum): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapVertexAttrib1dAPPLE = procedure(index_: GLuint; size: GLuint; u1: GLdouble; u2: GLdouble; stride: GLint; order: GLint; const points: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapVertexAttrib1fAPPLE = procedure(index_: GLuint; size: GLuint; u1: GLfloat; u2: GLfloat; stride: GLint; order: GLint; const points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapVertexAttrib2dAPPLE = procedure(index_: GLuint; size: GLuint; u1: GLdouble; u2: GLdouble; ustride: GLint; uorder: GLint; v1: GLdouble; v2: GLdouble; vstride: GLint; vorder: GLint; const points: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapVertexAttrib2fAPPLE = procedure(index_: GLuint; size: GLuint; u1: GLfloat; u2: GLfloat; ustride: GLint; order: GLint; v1: GLfloat; v2: GLfloat; vstride: GLint; vorder: GLint; const points: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_APPLE_object_purgeable
-  TglObjectPurgeableAPPLE = function(objectType: GLenum; name: GLuint; option: GLenum): GLenum; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglObjectUnpurgeableAPPLE = function(objectType: GLenum; name: GLuint; option: GLenum): GLenum; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetObjectParameterivAPPLE = procedure(objectType: GLenum; name: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_matrix_palette
-  TglCurrentPaletteMatrixARB = procedure(index: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixIndexubvARB = procedure(size: TGLint; const indices: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixIndexusvARB = procedure(size: TGLint; const indices: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixIndexuivARB = procedure(size: TGLint; const indices: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixIndexPointerARB = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_multisample
-  TglSampleCoverageARB = procedure(value: TGLclampf; invert: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_multitexture
-  TglActiveTextureARB = procedure(texture: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClientActiveTextureARB = procedure(texture: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1dARB = procedure(target: TGLenum; s: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1dvARB = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1fARB = procedure(target: TGLenum; s: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1fvARB = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1iARB = procedure(target: TGLenum; s: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1ivARB = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1sARB = procedure(target: TGLenum; s: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1svARB = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2dARB = procedure(target: TGLenum; s: TGLdouble; t: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2dvARB = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2fARB = procedure(target: TGLenum; s: TGLfloat; t: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2fvARB = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2iARB = procedure(target: TGLenum; s: TGLint; t: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2ivARB = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2sARB = procedure(target: TGLenum; s: TGLshort; t: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2svARB = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3dARB = procedure(target: TGLenum; s: TGLdouble; t: TGLdouble; r: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3dvARB = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3fARB = procedure(target: TGLenum; s: TGLfloat; t: TGLfloat; r: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3fvARB = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3iARB = procedure(target: TGLenum; s: TGLint; t: TGLint; r: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3ivARB = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3sARB = procedure(target: TGLenum; s: TGLshort; t: TGLshort; r: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3svARB = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4dARB = procedure(target: TGLenum; s: TGLdouble; t: TGLdouble; r: TGLdouble; q: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4dvARB = procedure(target: TGLenum; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4fARB = procedure(target: TGLenum; s: TGLfloat; t: TGLfloat; r: TGLfloat; q: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4fvARB = procedure(target: TGLenum; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4iARB = procedure(target: TGLenum; s: TGLint; t: TGLint; r: TGLint; q: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4ivARB = procedure(target: TGLenum; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4sARB = procedure(target: TGLenum; s: TGLshort; t: TGLshort; r: TGLshort; q: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4svARB = procedure(target: TGLenum; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_point_parameters
-  TglPointParameterfARB = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameterfvARB = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_texture_compression
-  TglCompressedTexImage3DARB = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; depth: TGLsizei; border: TGLint; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexImage2DARB = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; border: TGLint; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexImage1DARB = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; border: TGLint; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexSubImage3DARB = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; zoffset: TGLint; width: TGLsizei; height: TGLsizei; depth: TGLsizei; format: TGLenum; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexSubImage2DARB = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; width: TGLsizei; height: TGLsizei; format: TGLenum; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTexSubImage1DARB = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; width: TGLsizei; format: TGLenum; imageSize: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCompressedTexImageARB = procedure(target: TGLenum; level: TGLint; img: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_transpose_matrix
-  TglLoadTransposeMatrixfARB = procedure(const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadTransposeMatrixdARB = procedure(const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultTransposeMatrixfARB = procedure(const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultTransposeMatrixdARB = procedure(const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_vertex_blend
-  TglWeightbvARB = procedure(size: TGLint; const weights: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightsvARB = procedure(size: TGLint; const weights: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightivARB = procedure(size: TGLint; const weights: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightfvARB = procedure(size: TGLint; const weights: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightdvARB = procedure(size: TGLint; const weights: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightubvARB = procedure(size: TGLint; const weights: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightusvARB = procedure(size: TGLint; const weights: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightuivARB = procedure(size: TGLint; const weights: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWeightPointerARB = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexBlendARB = procedure(count: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_vertex_buffer_object
-  TglBindBufferARB = procedure(target: TGLenum; buffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteBuffersARB = procedure(n: TGLsizei; const buffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenBuffersARB = procedure(n: TGLsizei; buffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsBufferARB = function(buffer: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBufferDataARB = procedure(target: TGLenum; size: TGLsizei; const data: PGLvoid; usage: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBufferSubDataARB = procedure(target: TGLenum; offset: TGLsizei; size: TGLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBufferSubDataARB = procedure(target: TGLenum; offset: TGLsizei; size: TGLsizei; data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapBufferARB = function(target: TGLenum; access: TGLenum): PGLvoid; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUnmapBufferARB = function(target: TGLenum): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBufferParameterivARB = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBufferPointervARB = procedure(target: TGLenum; pname: TGLenum; params: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_vertex_program
-  TglVertexAttrib1dARB = procedure(index: TGLuint; x: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1dvARB = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1fARB = procedure(index: TGLuint; x: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1fvARB = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1sARB = procedure(index: TGLuint; x: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1svARB = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2dARB = procedure(index: TGLuint; x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2dvARB = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2fARB = procedure(index: TGLuint; x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2fvARB = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2sARB = procedure(index: TGLuint; x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2svARB = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3dARB = procedure(index: TGLuint; x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3dvARB = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3fARB = procedure(index: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3fvARB = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3sARB = procedure(index: TGLuint; x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3svARB = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4NbvARB = procedure(index: TGLuint; const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4NivARB = procedure(index: TGLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4NsvARB = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4NubARB = procedure(index: TGLuint; x: TGLubyte; y: TGLubyte; z: TGLubyte; w: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4NubvARB = procedure(index: TGLuint; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4NuivARB = procedure(index: TGLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4NusvARB = procedure(index: TGLuint; const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4bvARB = procedure(index: TGLuint; const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4dARB = procedure(index: TGLuint; x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4dvARB = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4fARB = procedure(index: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4fvARB = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4ivARB = procedure(index: TGLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4sARB = procedure(index: TGLuint; x: TGLshort; y: TGLshort; z: TGLshort; w: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4svARB = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4ubvARB = procedure(index: TGLuint; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4uivARB = procedure(index: TGLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4usvARB = procedure(index: TGLuint; const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribPointerARB = procedure(index: TGLuint; size: TGLint; _type: TGLenum; normalized: TGLboolean; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnableVertexAttribArrayARB = procedure(index: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisableVertexAttribArrayARB = procedure(index: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramStringARB = procedure(target: TGLenum; format: TGLenum; len: TGLsizei; const _string: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindProgramARB = procedure(target: TGLenum; _program: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteProgramsARB = procedure(n: TGLsizei; const programs: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenProgramsARB = procedure(n: TGLsizei; programs: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameter4dARB = procedure(target: TGLenum; index: TGLuint; x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameter4dvARB = procedure(target: TGLenum; index: TGLuint; const params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameter4fARB = procedure(target: TGLenum; index: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameter4fvARB = procedure(target: TGLenum; index: TGLuint; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameter4dARB = procedure(target: TGLenum; index: TGLuint; x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameter4dvARB = procedure(target: TGLenum; index: TGLuint; const params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameter4fARB = procedure(target: TGLenum; index: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameter4fvARB = procedure(target: TGLenum; index: TGLuint; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramEnvParameterdvARB = procedure(target: TGLenum; index: TGLuint; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramEnvParameterfvARB = procedure(target: TGLenum; index: TGLuint; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramLocalParameterdvARB = procedure(target: TGLenum; index: TGLuint; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramLocalParameterfvARB = procedure(target: TGLenum; index: TGLuint; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramivARB = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramStringARB = procedure(target: TGLenum; pname: TGLenum; _string: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribdvARB = procedure(index: TGLuint; pname: TGLenum; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribfvARB = procedure(index: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribivARB = procedure(index: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribPointervARB = procedure(index: TGLuint; pname: TGLenum; _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsProgramARB = function(_program: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_window_pos
-  TglWindowPos2dARB = procedure(x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2dvARB = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2fARB = procedure(x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2fvARB = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2iARB = procedure(x: TGLint; y: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2ivARB = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2sARB = procedure(x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2svARB = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3dARB = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3dvARB = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3fARB = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3fvARB = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3iARB = procedure(x: TGLint; y: TGLint; z: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3ivARB = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3sARB = procedure(x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3svARB = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_draw_buffers
-  TglDrawBuffersARB = procedure(n: TGLsizei; bufs: PGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_color_buffer_float
-  TglClampColorARB = procedure(target: TGLenum; clamp: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_vertex_shader
-  TglGetActiveAttribARB = procedure(programobj: GLhandleARB; index: GLuint; maxLength: GLsizei; var length: GLsizei; var size: GLint; var _type: GLenum; name: PGLcharARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetAttribLocationARB = function(programObj: GLhandleARB; const char: PGLcharARB): glint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindAttribLocationARB = procedure(programObj: GLhandleARB; index: GLuint; const name: PGLcharARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_shader_objects
-  TglDeleteObjectARB = procedure(Obj: GLHandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetHandleARB = function(pname: GlEnum): GLHandleARB; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDetachObjectARB = procedure(container, attached: GLHandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCreateShaderObjectARB = function(shaderType: glenum): GLHandleARB; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglShaderSourceARB = procedure(shaderObj: GLHandleARB; count: glsizei; _string: PPGLCharARB; lengths: pglint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompileShaderARB = procedure(shaderObj: GLHandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCreateProgramObjectARB = function: GLHandleARB; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglAttachObjectARB = procedure(programObj, shaderObj: GLhandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLinkProgramARB = procedure(programObj: GLHandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUseProgramObjectARB = procedure(programObj: GLHandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglValidateProgramARB = procedure(programObj: GLhandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1fARB = procedure(location: glint; v0: glfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2fARB = procedure(location: glint; v0, v1: glfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3fARB = procedure(location: glint; v0, v1, v2: glfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4fARB = procedure(location: glint; v0, v1, v2, v3: glfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1iARB = procedure(location: glint; v0: glint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2iARB = procedure(location: glint; v0, v1: glint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3iARB = procedure(location: glint; v0, v1, v2: glint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4iARB = procedure(location: glint; v0, v1, v2, v3: glint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1fvARB = procedure(location: glint; count: GLsizei; value: pglfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2fvARB = procedure(location: glint; count: GLsizei; value: pglfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3fvARB = procedure(location: glint; count: GLsizei; value: pglfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4fvARB = procedure(location: glint; count: GLsizei; value: pglfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1ivARB = procedure(location: glint; count: GLsizei; value: pglint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2ivARB = procedure(location: glint; count: GLsizei; value: pglint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3ivARB = procedure(location: glint; count: GLsizei; value: pglint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4ivARB = procedure(location: glint; count: GLsizei; value: pglint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix2fvARB = procedure(location: glint; count: glsizei; transpose: glboolean; value: pglfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix3fvARB = procedure(location: glint; count: glsizei; transpose: glboolean; value: pglfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformMatrix4fvARB = procedure(location: glint; count: glsizei; transpose: glboolean; value: pglfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetObjectParameterfvARB = procedure(Obj: GLHandleARB; pname: GLEnum; params: PGLFloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetObjectParameterivARB = procedure(Obj: GLHandleARB; pname: GLEnum; params: PGLInt); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetInfoLogARB = procedure(shaderObj: GLHandleARB; maxLength: glsizei; var length: glint; infoLog: PGLcharARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetAttachedObjectsARB = procedure(programobj: GLhandleARB; maxCount: GLsizei; var count: GLsizei; objects: PGLhandleARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformLocationARB = function(programObj: GLhandleARB; const char: PGLcharARB): glint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveUniformARB = procedure(programobj: GLhandleARB; index: GLuint; maxLength: GLsizei; var length: GLsizei; var size: GLint; var _type: GLenum; name: PGLcharARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformfvARB = procedure(programObj: GLhandleARB; location: GLint; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformivARB = procedure(programObj: GLhandleARB; location: GLint; params: PGLInt); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetShaderSourceARB = procedure(shader: GLhandleARB; maxLength: GLsizei; var length: GLsizei; source: PGLcharARB); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_Occlusion_Query
-  TglGenQueriesARB = procedure(n: GLsizei; ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteQueriesARB = procedure(n: GLsizei; const ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsQueryARB = function(id: GLuint): boolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBeginQueryARB = procedure(target: GLenum; id: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndQueryARB = procedure(target: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetQueryivARB = procedure(target, pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetQueryObjectivARB = procedure(id: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetQueryObjectuivARB = procedure(id: GLuint; pname: GLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_draw_instanced
-  TglDrawArraysInstancedARB = procedure(mode: GLenum; first: GLint; count: GLsizei; primcount: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawElementsInstancedARB = procedure(mode: GLenum; count: GLsizei; type_: GLenum; const indices: PGLvoid; primcount: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_framebuffer_object
-  TglIsRenderbuffer = function(renderbuffer: GLuint): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindRenderbuffer = procedure(target: GLenum; renderbuffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteRenderbuffers = procedure(n: GLsizei; const renderbuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenRenderbuffers = procedure(n: GLsizei; renderbuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRenderbufferStorage = procedure(target: GLenum; internalformat: GLenum; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetRenderbufferParameteriv = procedure(target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsFramebuffer = function(framebuffer: GLuint): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindFramebuffer = procedure(target: GLenum; framebuffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteFramebuffers = procedure(n: GLsizei; const framebuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenFramebuffers = procedure(n: GLsizei; framebuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCheckFramebufferStatus = function(target: GLenum): GLenum; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTexture1D = procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTexture2D = procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTexture3D = procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint; zoffset: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferRenderbuffer = procedure(target: GLenum; attachment: GLenum; renderbuffertarget: GLenum; renderbuffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFramebufferAttachmentParameteriv = procedure(target: GLenum; attachment: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenerateMipmap = procedure(target: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBlitFramebuffer = procedure(srcX0: GLint; srcY0: GLint; srcX1: GLint; srcY1: GLint; dstX0: GLint; dstY0: GLint; dstX1: GLint; dstY1: GLint; mask: GLbitfield; filter: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRenderbufferStorageMultisample = procedure(target: GLenum; samples: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTextureLayer = procedure(target: GLenum; attachment: GLenum; texture: GLuint; level: GLint; layer: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_geometry_shader4
-  TglProgramParameteriARB = procedure(program_: GLuint; pname: GLenum; value: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTextureARB = procedure(target: GLenum; attachment: GLenum; texture: GLuint; level: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTextureLayerARB = procedure(target: GLenum; attachment: GLenum; texture: GLuint; level: GLint; layer: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTextureFaceARB = procedure(target: GLenum; attachment: GLenum; texture: GLuint; level: GLint; face: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_instanced_arrays
-  TglVertexAttribDivisorARB = procedure(index_: GLuint; divisor: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_map_buffer_range
-  TglMapBufferRange = function(target: GLenum; offset: GLsizei; length: GLsizei; access: GLbitfield): PGLvoid; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFlushMappedBufferRange = procedure(target: GLenum; offset: GLsizei; length: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_texture_buffer_object
-  TglTexBufferARB = procedure(target: GLenum; internalformat: GLenum; buffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_vertex_array_object
-  TglBindVertexArray = procedure(array_: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteVertexArrays = procedure(n: GLsizei; const arrays: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenVertexArrays = procedure(n: GLsizei; arrays: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsVertexArray = function(array_: GLuint): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_uniform_buffer_object
-  TglGetUniformIndices = procedure(program_: GLuint; uniformCount: GLsizei; const uniformNames: PPGLchar; uniformIndices: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveUniformsiv = procedure(program_: GLuint; uniformCount: GLsizei; const uniformIndices: PGLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveUniformName = procedure(program_: GLuint; uniformIndex: GLuint; bufSize: GLsizei; length: PGLsizei; uniformName: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformBlockIndex = function(program_: GLuint; const uniformBlockName: PGLchar): GLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveUniformBlockiv = procedure(program_: GLuint; uniformBlockIndex: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveUniformBlockName = procedure(program_: GLuint; uniformBlockIndex: GLuint; bufSize: GLsizei; length: PGLsizei; uniformBlockName: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniformBlockBinding = procedure(program_: GLuint; uniformBlockIndex: GLuint; uniformBlockBinding: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_copy_buffer
-  TglCopyBufferSubData = procedure(readTarget: GLenum; writeTarget: GLenum; readOffset: GLint; writeOffset: GLint; size: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_draw_elements_base_vertex
-  TglDrawElementsBaseVertex = procedure(mode: GLenum; count: GLsizei; type_: GLenum; const indices: PGLvoid; basevertex: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawRangeElementsBaseVertex = procedure(mode: GLenum; start: GLuint; end_: GLuint; count: GLsizei; type_: GLenum; const indices: PGLvoid; basevertex: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawElementsInstancedBaseVertex = procedure(mode: GLenum; count: GLsizei; type_: GLenum; const indices: PGLvoid; primcount: GLsizei; basevertex: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiDrawElementsBaseVertex = procedure(mode: GLenum; const count: PGLsizei; type_: GLenum; const indices: PPGLvoid; primcount: GLsizei; const basevertex: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_provoking_vertex
-  TglProvokingVertex = procedure(mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_sync
-  TglFenceSync = function(condition: GLenum; flags: GLbitfield): GLsync; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsSync = function(sync: GLsync): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteSync = procedure(sync: GLsync); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClientWaitSync = function(sync: GLsync; flags: GLbitfield; timeout: GLuint64): GLenum; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWaitSync = procedure(sync: GLsync; flags: GLbitfield; timeout: GLuint64); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetInteger64v = procedure(pname: GLenum; params: PGLint64); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetSynciv = procedure(sync: GLsync; pname: GLenum; butSize: GLsizei; length: PGLsizei; values: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_texture_multisample
-  TglTexImage2DMultisample = procedure(target: GLenum; samples: GLsizei; internalformat: GLint; width: GLsizei; height: GLsizei; fixedsamplelocations: GLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexImage3DMultisample = procedure(target: GLenum; samples: GLsizei; internalformat: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; fixedsamplelocations: GLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultisamplefv = procedure(pname: GLenum; index_: GLuint; val: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSampleMaski = procedure(index_: GLuint; mask: GLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_draw_buffers_blend
-  TglBlendEquationi = procedure(buf: GLuint; mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBlendEquationSeparatei = procedure(buf: GLuint; modeRGB: GLenum; modeAlpha: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBlendFunci = procedure(buf: GLuint; src: GLenum; dst: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBlendFuncSeparatei = procedure(buf: GLuint; srcRGB: GLenum; dstRGB: GLenum; srcAlpha: GLenum; dstAlpha: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ARB_sample_shading
-  TglMinSampleShading = procedure(value: GLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_draw_buffers
-  TglDrawBuffersATI = procedure(n: TGLsizei; const bufs: PGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_element_array
-  TglElementPointerATI = procedure(_type: TGLenum; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawElementArrayATI = procedure(mode: TGLenum; count: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawRangeElementArrayATI = procedure(mode: TGLenum; start: TGLuint; _end: TGLuint; count: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_envmap_bumpmap
-  TglTexBumpParameterivATI = procedure(pname: TGLenum; const param: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexBumpParameterfvATI = procedure(pname: TGLenum; const param: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexBumpParameterivATI = procedure(pname: TGLenum; param: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexBumpParameterfvATI = procedure(pname: TGLenum; param: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_fragment_shader
-  TglGenFragmentShadersATI = function(range: TGLuint): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindFragmentShaderATI = procedure(id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteFragmentShaderATI = procedure(id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBeginFragmentShaderATI = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndFragmentShaderATI = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPassTexCoordATI = procedure(dst: TGLuint; coord: TGLuint; swizzle: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSampleMapATI = procedure(dst: TGLuint; interp: TGLuint; swizzle: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorFragmentOp1ATI = procedure(op: TGLenum; dst: TGLuint; dstMask: TGLuint; dstMod: TGLuint; arg1: TGLuint; arg1Rep: TGLuint; arg1Mod: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorFragmentOp2ATI = procedure(op: TGLenum; dst: TGLuint; dstMask: TGLuint; dstMod: TGLuint; arg1: TGLuint; arg1Rep: TGLuint; arg1Mod: TGLuint; arg2: TGLuint; arg2Rep: TGLuint; arg2Mod: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorFragmentOp3ATI = procedure(op: TGLenum; dst: TGLuint; dstMask: TGLuint; dstMod: TGLuint; arg1: TGLuint; arg1Rep: TGLuint; arg1Mod: TGLuint; arg2: TGLuint; arg2Rep: TGLuint; arg2Mod: TGLuint; arg3: TGLuint; arg3Rep: TGLuint; arg3Mod: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglAlphaFragmentOp1ATI = procedure(op: TGLenum; dst: TGLuint; dstMod: TGLuint; arg1: TGLuint; arg1Rep: TGLuint; arg1Mod: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglAlphaFragmentOp2ATI = procedure(op: TGLenum; dst: TGLuint; dstMod: TGLuint; arg1: TGLuint; arg1Rep: TGLuint; arg1Mod: TGLuint; arg2: TGLuint; arg2Rep: TGLuint; arg2Mod: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglAlphaFragmentOp3ATI = procedure(op: TGLenum; dst: TGLuint; dstMod: TGLuint; arg1: TGLuint; arg1Rep: TGLuint; arg1Mod: TGLuint; arg2: TGLuint; arg2Rep: TGLuint; arg2Mod: TGLuint; arg3: TGLuint; arg3Rep: TGLuint; arg3Mod: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSetFragmentShaderConstantATI = procedure(dst: TGLuint; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_map_object_buffer
-  TglMapObjectBufferATI = function(buffer: TGLuint): PGLvoid; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUnmapObjectBufferATI = procedure(buffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_pn_triangles
-  TglPNTrianglesiATI = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPNTrianglesfATI = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_separate_stencil
-  TglStencilOpSeparateATI = procedure(face: TGLenum; sfail: TGLenum; dpfail: TGLenum; dppass: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStencilFuncSeparateATI = procedure(frontfunc: TGLenum; backfunc: TGLenum; ref: TGLint; mask: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_vertex_array_object
-  TglNewObjectBufferATI = function(size: TGLsizei; const _pointer: PGLvoid; usage: TGLenum): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsObjectBufferATI = function(buffer: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUpdateObjectBufferATI = procedure(buffer: TGLuint; offset: TGLuint; size: TGLsizei; const _pointer: PGLvoid; preserve: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetObjectBufferfvATI = procedure(buffer: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetObjectBufferivATI = procedure(buffer: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFreeObjectBufferATI = procedure(buffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglArrayObjectATI = procedure(_array: TGLenum; size: TGLint; _type: TGLenum; stride: TGLsizei; buffer: TGLuint; offset: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetArrayObjectfvATI = procedure(_array: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetArrayObjectivATI = procedure(_array: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantArrayObjectATI = procedure(id: TGLuint; _type: TGLenum; stride: TGLsizei; buffer: TGLuint; offset: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVariantArrayObjectfvATI = procedure(id: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVariantArrayObjectivATI = procedure(id: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_vertex_attrib_array_object
-  TglVertexAttribArrayObjectATI = procedure(index: TGLuint; size: TGLint; _type: TGLenum; normalized: TGLboolean; stride: TGLsizei; buffer: TGLuint; offset: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribArrayObjectfvATI = procedure(index: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribArrayObjectivATI = procedure(index: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_ATI_vertex_streams
-  TglVertexStream1sATI = procedure(stream: TGLenum; x: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream1svATI = procedure(stream: TGLenum; const coords: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream1iATI = procedure(stream: TGLenum; x: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream1ivATI = procedure(stream: TGLenum; const coords: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream1fATI = procedure(stream: TGLenum; x: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream1fvATI = procedure(stream: TGLenum; const coords: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream1dATI = procedure(stream: TGLenum; x: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream1dvATI = procedure(stream: TGLenum; const coords: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2sATI = procedure(stream: TGLenum; x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2svATI = procedure(stream: TGLenum; const coords: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2iATI = procedure(stream: TGLenum; x: TGLint; y: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2ivATI = procedure(stream: TGLenum; const coords: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2fATI = procedure(stream: TGLenum; x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2fvATI = procedure(stream: TGLenum; const coords: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2dATI = procedure(stream: TGLenum; x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream2dvATI = procedure(stream: TGLenum; const coords: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3sATI = procedure(stream: TGLenum; x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3svATI = procedure(stream: TGLenum; const coords: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3iATI = procedure(stream: TGLenum; x: TGLint; y: TGLint; z: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3ivATI = procedure(stream: TGLenum; const coords: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3fATI = procedure(stream: TGLenum; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3fvATI = procedure(stream: TGLenum; const coords: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3dATI = procedure(stream: TGLenum; x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream3dvATI = procedure(stream: TGLenum; const coords: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4sATI = procedure(stream: TGLenum; x: TGLshort; y: TGLshort; z: TGLshort; w: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4svATI = procedure(stream: TGLenum; const coords: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4iATI = procedure(stream: TGLenum; x: TGLint; y: TGLint; z: TGLint; w: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4ivATI = procedure(stream: TGLenum; const coords: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4fATI = procedure(stream: TGLenum; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4fvATI = procedure(stream: TGLenum; const coords: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4dATI = procedure(stream: TGLenum; x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexStream4dvATI = procedure(stream: TGLenum; const coords: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3bATI = procedure(stream: TGLenum; nx: TGLbyte; ny: TGLbyte; nz: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3bvATI = procedure(stream: TGLenum; const coords: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3sATI = procedure(stream: TGLenum; nx: TGLshort; ny: TGLshort; nz: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3svATI = procedure(stream: TGLenum; const coords: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3iATI = procedure(stream: TGLenum; nx: TGLint; ny: TGLint; nz: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3ivATI = procedure(stream: TGLenum; const coords: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3fATI = procedure(stream: TGLenum; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3fvATI = procedure(stream: TGLenum; const coords: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3dATI = procedure(stream: TGLenum; nx: TGLdouble; ny: TGLdouble; nz: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalStream3dvATI = procedure(stream: TGLenum; const coords: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClientActiveVertexStreamATI = procedure(stream: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexBlendEnviATI = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexBlendEnvfATI = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_AMD_performance_monitor
-  TglGetPerfMonitorGroupsAMD = procedure(numGroups: PGLint; groupsSize: GLsizei; groups: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPerfMonitorCountersAMD = procedure(group: GLuint; numCounters: PGLint; maxActiveCouters: PGLint; counterSize: GLsizei; counters: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPerfMonitorGroupStringAMD = procedure(group: GLuint; bufSize: GLsizei; length: PGLsizei; groupString: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPerfMonitorCounterStringAMD = procedure(group: GLuint; counter: GLuint; bufSize: GLsizei; length: PGLsizei; counterString: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPerfMonitorCounterInfoAMD = procedure(group: GLuint; counter: GLuint; pname: GLenum; data: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenPerfMonitorsAMD = procedure(n: GLsizei; monitors: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeletePerfMonitorsAMD = procedure(n: GLsizei; monitors: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSelectPerfMonitorCountersAMD = procedure(monitor: GLuint; enable: GLboolean; group: GLuint; numCounters: GLint; counterList: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBeginPerfMonitorAMD = procedure(monitor: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndPerfMonitorAMD = procedure(monitor: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPerfMonitorCounterDataAMD = procedure(monitor: GLuint; pname: GLenum; dataSize: GLsizei; data: PGLuint; bytesWritten: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_AMD_vertex_shader_tesselator
-  TglTessellationFactorAMD = procedure(factor: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTessellationModeAMD = procedure(mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  
-  // GL_EXT_blend_color
-  TglBlendColorEXT = procedure(red: TGLclampf; green: TGLclampf; blue: TGLclampf; alpha: TGLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_blend_func_separate
-  TglBlendFuncSeparateEXT = procedure(sfactorRGB: TGLenum; dfactorRGB: TGLenum; sfactorAlpha: TGLenum; dfactorAlpha: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_blend_minmax
-  TglBlendEquationEXT = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_color_subtable
-  TglColorSubTableEXT = procedure(target: TGLenum; start: TGLsizei; count: TGLsizei; format: TGLenum; _type: TGLenum; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyColorSubTableEXT = procedure(target: TGLenum; start: TGLsizei; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_compiled_vertex_array
-  TglLockArraysEXT = procedure(first: TGLint; count: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUnlockArraysEXT = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_convolution
-  TglConvolutionFilter1DEXT = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; format: TGLenum; _type: TGLenum; const image: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionFilter2DEXT = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; const image: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameterfEXT = procedure(target: TGLenum; pname: TGLenum; params: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameterfvEXT = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameteriEXT = procedure(target: TGLenum; pname: TGLenum; params: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglConvolutionParameterivEXT = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyConvolutionFilter1DEXT = procedure(target: TGLenum; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyConvolutionFilter2DEXT = procedure(target: TGLenum; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetConvolutionFilterEXT = procedure(target: TGLenum; format: TGLenum; _type: TGLenum; image: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetConvolutionParameterfvEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetConvolutionParameterivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetSeparableFilterEXT = procedure(target: TGLenum; format: TGLenum; _type: TGLenum; row: PGLvoid; column: PGLvoid; span: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSeparableFilter2DEXT = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; const row: PGLvoid; const column: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_coordinate_frame
-  TglTangent3bEXT = procedure(tx: TGLbyte; ty: TGLbyte; tz: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3bvEXT = procedure(const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3dEXT = procedure(tx: TGLdouble; ty: TGLdouble; tz: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3dvEXT = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3fEXT = procedure(tx: TGLfloat; ty: TGLfloat; tz: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3fvEXT = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3iEXT = procedure(tx: TGLint; ty: TGLint; tz: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3ivEXT = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3sEXT = procedure(tx: TGLshort; ty: TGLshort; tz: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangent3svEXT = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3bEXT = procedure(bx: TGLbyte; by: TGLbyte; bz: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3bvEXT = procedure(const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3dEXT = procedure(bx: TGLdouble; by: TGLdouble; bz: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3dvEXT = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3fEXT = procedure(bx: TGLfloat; by: TGLfloat; bz: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3fvEXT = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3iEXT = procedure(bx: TGLint; by: TGLint; bz: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3ivEXT = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3sEXT = procedure(bx: TGLshort; by: TGLshort; bz: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormal3svEXT = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTangentPointerEXT = procedure(_type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBinormalPointerEXT = procedure(_type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_copy_texture
-  TglCopyTexImage1DEXT = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei; border: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexImage2DEXT = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei; border: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexSubImage1DEXT = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexSubImage2DEXT = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTexSubImage3DEXT = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; zoffset: TGLint; x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_cull_vertex
-  TglCullParameterdvEXT = procedure(pname: TGLenum; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCullParameterfvEXT = procedure(pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_draw_range_elements
-  TglDrawRangeElementsEXT = procedure(mode: TGLenum; start: TGLuint; _end: TGLuint; count: TGLsizei; _type: TGLenum; const indices: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_fog_coord
-  TglFogCoordfEXT = procedure(coord: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordfvEXT = procedure(const coord: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoorddEXT = procedure(coord: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoorddvEXT = procedure(const coord: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordPointerEXT = procedure(_type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_framebuffer_object
-  TglIsRenderbufferEXT = function(renderbuffer: TGLuint): Boolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindRenderbufferEXT = procedure(target: TGLenum; renderbuffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteRenderbuffersEXT = procedure(n: TGLsizei; const renderbuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenRenderbuffersEXT = procedure(n: TGLsizei; renderbuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRenderbufferStorageEXT = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetRenderbufferParameterivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsFramebufferEXT = function(framebuffer: TGLuint): Boolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindFramebufferEXT = procedure(target: TGLenum; framebuffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteFramebuffersEXT = procedure(n: TGLsizei; const framebuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenFramebuffersEXT = procedure(n: TGLsizei; framebuffers: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCheckFramebufferStatusEXT = function(target: TGLenum): TGLenum; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTexture1DEXT = procedure(target: TGLenum; attachment: TGLenum; textarget: TGLenum; texture: TGLuint; level: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTexture2DEXT = procedure(target: TGLenum; attachment: TGLenum; textarget: TGLenum; texture: TGLuint; level: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTexture3DEXT = procedure(target: TGLenum; attachment: TGLenum; textarget: TGLenum; texture: TGLuint; level: TGLint; zoffset: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferRenderbufferEXT = procedure(target: TGLenum; attachment: TGLenum; renderbuffertarget: TGLenum; renderbuffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFramebufferAttachmentParameterivEXT = procedure(target: TGLenum; attachment: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenerateMipmapEXT = procedure(target: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_histogram
-  TglGetHistogramEXT = procedure(target: TGLenum; reset: TGLboolean; format: TGLenum; _type: TGLenum; values: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetHistogramParameterfvEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetHistogramParameterivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMinmaxEXT = procedure(target: TGLenum; reset: TGLboolean; format: TGLenum; _type: TGLenum; values: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMinmaxParameterfvEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMinmaxParameterivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglHistogramEXT = procedure(target: TGLenum; width: TGLsizei; internalformat: TGLenum; sink: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMinmaxEXT = procedure(target: TGLenum; internalformat: TGLenum; sink: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglResetHistogramEXT = procedure(target: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglResetMinmaxEXT = procedure(target: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_index_func
-  TglIndexFuncEXT = procedure(func: TGLenum; ref: TGLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_index_material
-  TglIndexMaterialEXT = procedure(face: TGLenum; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_light_texture
-  TglApplyTextureEXT = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureLightEXT = procedure(pname: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureMaterialEXT = procedure(face: TGLenum; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_multi_draw_arrays
-  TglMultiDrawArraysEXT = procedure(mode: TGLenum; first: PGLint; count: PGLsizei; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiDrawElementsEXT = procedure(mode: TGLenum; const count: PGLsizei; _type: TGLenum; const indices: PGLvoid; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_multisample
-  TglSampleMaskEXT = procedure(value: TGLclampf; invert: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSamplePatternEXT = procedure(pattern: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_paletted_texture
-  TglColorTableEXT = procedure(target: TGLenum; internalFormat: TGLenum; width: TGLsizei; format: TGLenum; _type: TGLenum; const table: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableEXT = procedure(target: TGLenum; format: TGLenum; _type: TGLenum; data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableParameterivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableParameterfvEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_pixel_transform
-  TglPixelTransformParameteriEXT = procedure(target: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTransformParameterfEXT = procedure(target: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTransformParameterivEXT = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTransformParameterfvEXT = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_point_parameters
-  TglPointParameterfEXT = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameterfvEXT = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_polygon_offset
-  TglPolygonOffsetEXT = procedure(factor: TGLfloat; bias: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_secondary_color
-  TglSecondaryColor3bEXT = procedure(red: TGLbyte; green: TGLbyte; blue: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3bvEXT = procedure(const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3dEXT = procedure(red: TGLdouble; green: TGLdouble; blue: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3dvEXT = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3fEXT = procedure(red: TGLfloat; green: TGLfloat; blue: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3fvEXT = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3iEXT = procedure(red: TGLint; green: TGLint; blue: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3ivEXT = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3sEXT = procedure(red: TGLshort; green: TGLshort; blue: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3svEXT = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3ubEXT = procedure(red: TGLubyte; green: TGLubyte; blue: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3ubvEXT = procedure(const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3uiEXT = procedure(red: TGLuint; green: TGLuint; blue: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3uivEXT = procedure(const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3usEXT = procedure(red: TGLushort; green: TGLushort; blue: TGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3usvEXT = procedure(const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColorPointerEXT = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_stencil_two_side
-  TglActiveStencilFaceEXT = procedure(face: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_subtexture
-  TglTexSubImage1DEXT = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; width: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexSubImage2DEXT = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; width: TGLsizei; height: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_texture3D
-  TglTexImage3DEXT = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; depth: TGLsizei; border: TGLint; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexSubImage3DEXT = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; zoffset: TGLint; width: TGLsizei; height: TGLsizei; depth: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_texture_object
-  TglAreTexturesResidentEXT = function(n: TGLsizei; const textures: PGLuint; residences: PGLboolean): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindTextureEXT = procedure(target: TGLenum; texture: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteTexturesEXT = procedure(n: TGLsizei; const textures: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenTexturesEXT = procedure(n: TGLsizei; textures: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsTextureEXT = function(texture: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPrioritizeTexturesEXT = procedure(n: TGLsizei; const textures: PGLuint; const priorities: PGLclampf); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_texture_perturb_normal
-  TglTextureNormalEXT = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_vertex_array
-  TglArrayElementEXT = procedure(i: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorPointerEXT = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; count: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawArraysEXT = procedure(mode: TGLenum; first: TGLint; count: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEdgeFlagPointerEXT = procedure(stride: TGLsizei; count: TGLsizei; const _pointer: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPointervEXT = procedure(pname: TGLenum; params: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexPointerEXT = procedure(_type: TGLenum; stride: TGLsizei; count: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalPointerEXT = procedure(_type: TGLenum; stride: TGLsizei; count: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoordPointerEXT = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; count: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexPointerEXT = procedure(size: TGLint; _type: TGLenum; stride: TGLsizei; count: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_vertex_shader
-  TglBeginVertexShaderEXT = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndVertexShaderEXT = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindVertexShaderEXT = procedure(id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenVertexShadersEXT = function(range: TGLuint): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteVertexShaderEXT = procedure(id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglShaderOp1EXT = procedure(op: TGLenum; res: TGLuint; arg1: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglShaderOp2EXT = procedure(op: TGLenum; res: TGLuint; arg1: TGLuint; arg2: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglShaderOp3EXT = procedure(op: TGLenum; res: TGLuint; arg1: TGLuint; arg2: TGLuint; arg3: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSwizzleEXT = procedure(res: TGLuint; _in: TGLuint; outX: TGLenum; outY: TGLenum; outZ: TGLenum; outW: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWriteMaskEXT = procedure(res: TGLuint; _in: TGLuint; outX: TGLenum; outY: TGLenum; outZ: TGLenum; outW: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglInsertComponentEXT = procedure(res: TGLuint; src: TGLuint; num: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglExtractComponentEXT = procedure(res: TGLuint; src: TGLuint; num: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenSymbolsEXT = function(datatype: TGLenum; storagetype: TGLenum; range: TGLenum; components: TGLuint): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSetInvariantEXT = procedure(id: TGLuint; _type: TGLenum; const addr: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSetLocalConstantEXT = procedure(id: TGLuint; _type: TGLenum; const addr: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantbvEXT = procedure(id: TGLuint; const addr: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantsvEXT = procedure(id: TGLuint; const addr: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantivEXT = procedure(id: TGLuint; const addr: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantfvEXT = procedure(id: TGLuint; const addr: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantdvEXT = procedure(id: TGLuint; const addr: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantubvEXT = procedure(id: TGLuint; const addr: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantusvEXT = procedure(id: TGLuint; const addr: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantuivEXT = procedure(id: TGLuint; const addr: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVariantPointerEXT = procedure(id: TGLuint; _type: TGLenum; stride: TGLuint; const addr: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnableVariantClientStateEXT = procedure(id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisableVariantClientStateEXT = procedure(id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindLightParameterEXT = function(light: TGLenum; value: TGLenum): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindMaterialParameterEXT = function(face: TGLenum; value: TGLenum): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindTexGenParameterEXT = function(_unit: TGLenum; coord: TGLenum; value: TGLenum): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindTextureUnitParameterEXT = function(_unit: TGLenum; value: TGLenum): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindParameterEXT = function(value: TGLenum): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsVariantEnabledEXT = function(id: TGLuint; cap: TGLenum): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVariantBooleanvEXT = procedure(id: TGLuint; value: TGLenum; data: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVariantIntegervEXT = procedure(id: TGLuint; value: TGLenum; data: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVariantFloatvEXT = procedure(id: TGLuint; value: TGLenum; data: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVariantPointervEXT = procedure(id: TGLuint; value: TGLenum; data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetInvariantBooleanvEXT = procedure(id: TGLuint; value: TGLenum; data: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetInvariantIntegervEXT = procedure(id: TGLuint; value: TGLenum; data: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetInvariantFloatvEXT = procedure(id: TGLuint; value: TGLenum; data: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetLocalConstantBooleanvEXT = procedure(id: TGLuint; value: TGLenum; data: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetLocalConstantIntegervEXT = procedure(id: TGLuint; value: TGLenum; data: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetLocalConstantFloatvEXT = procedure(id: TGLuint; value: TGLenum; data: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_vertex_weighting
-  TglVertexWeightfEXT = procedure(weight: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexWeightfvEXT = procedure(const weight: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexWeightPointerEXT = procedure(size: TGLsizei; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_stencil_clear_tag
-  TglStencilClearTagEXT = procedure(stencilTagBits: TGLsizei; stencilClearTag: Tgluint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_framebuffer_blit
-  TglBlitFramebufferEXT = procedure(srcX0: TGLint; srcY0: TGLint; srcX1: TGLint; srcY1: TGLint; dstX0: TGLint; dstY0: TGLint; dstX1: TGLint; dstY1: TGLint; mask: TGLbitfield; filter: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_framebuffer_multisample
-  TglRenderbufferStorageMultisampleEXT = procedure(target: TGLenum; samples: TGLsizei; internalformat: TGLenum; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_timer_query
-  TglGetQueryObjecti64vEXT = procedure(id: TGLuint; pname: TGLenum; params: PGLint64EXT); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetQueryObjectui64vEXT = procedure(id: TGLuint; pname: TGLenum; params: PGLuint64EXT); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_gpu_program_parameters
-  TglProgramEnvParameters4fvEXT = procedure(target: TGLenum; index: TGLuint; count: TGLsizei; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameters4fvEXT = procedure(target: TGLenum; index: TGLuint; count: TGLsizei; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_bindable_uniform
-  TglUniformBufferEXT = procedure(_program: TGLuint; location: TGLint; buffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformBufferSizeEXT = function(_program: TGLuint; location: TGLint): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformOffsetEXT = function(_program: TGLuint; location: TGLint): PGLInt; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_draw_buffers2
-  TglColorMaskIndexedEXT = procedure(buf: TGLuint; r: TGLboolean; g: TGLboolean; b: TGLboolean; a: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetBooleanIndexedvEXT = procedure(value: TGLenum; index: TGLuint; data: PGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetIntegerIndexedvEXT = procedure(value: TGLenum; index: TGLuint; data: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnableIndexedEXT = procedure(target: TGLenum; index: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisableIndexedEXT = procedure(target: TGLenum; index: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsEnabledIndexedEXT = function(target: TGLenum; index: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_draw_instanced
-  TglDrawArraysInstancedEXT = procedure(mode: TGLenum; first: TGLint; count: TGLsizei; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawElementsInstancedEXT = procedure(mode: TGLenum; count: TGLsizei; _type: TGLenum; const indices: Pointer; primcount: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_geometry_shader4
-  TglProgramParameteriEXT = procedure (_program: TGLuint; pname: TGLenum; value: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTextureEXT = procedure(target: TGLenum; attachment: TGLenum; texture: TGLuint; level: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-//  TglFramebufferTextureLayerEXT = procedure(target: TGLenum; attachment: TGLenum; texture: TGLuint; level: TGLint; layer: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferTextureFaceEXT = procedure(target: TGLenum; attachment: TGLenum; texture: TGLuint; level: TGLint; face: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_gpu_shader4
-  TglVertexAttribI1iEXT = procedure(index: TGLuint; x: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2iEXT = procedure(index: TGLuint; x: TGLint; y: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3iEXT = procedure(index: TGLuint; x: TGLint; y: TGLint; z: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4iEXT = procedure(index: TGLuint; x: TGLint; y: TGLint; z: TGLint; w: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI1uiEXT = procedure(index: TGLuint; x: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2uiEXT = procedure(index: TGLuint; x: TGLuint; y: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3uiEXT = procedure(index: TGLuint; x: TGLuint; y: TGLuint; z: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4uiEXT = procedure(index: TGLuint; x: TGLuint; y: TGLuint; z: TGLuint; w: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI1ivEXT = procedure(index: TGLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2ivEXT = procedure(index: TGLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3ivEXT = procedure(index: TGLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4ivEXT = procedure(index: TGLuint; const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI1uivEXT = procedure(index: TGLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI2uivEXT = procedure(index: TGLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI3uivEXT = procedure(index: TGLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4uivEXT = procedure(index: TGLuint; const v: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4bvEXT = procedure(index: TGLuint; const v: PGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4svEXT = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4ubvEXT = procedure(index: TGLuint; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribI4usvEXT = procedure(index: TGLuint; const v: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribIPointerEXT = procedure(index: TGLuint; size: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribIivEXT = procedure(index: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribIuivEXT = procedure(index: TGLuint; pname: TGLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1uiEXT = procedure(location: TGLint; v0: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2uiEXT = procedure(location: TGLint; v0: TGLuint; v1: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3uiEXT = procedure(location: TGLint; v0: TGLuint; v1: TGLuint; v2: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4uiEXT = procedure(location: TGLint; v0: TGLuint; v1: TGLuint; v2: TGLuint; v3: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform1uivEXT = procedure(location: TGLint; count: TGLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform2uivEXT = procedure(location: TGLint; count: TGLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform3uivEXT = procedure(location: TGLint; count: TGLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUniform4uivEXT = procedure(location: TGLint; count: TGLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetUniformuivEXT = procedure(_program: TGLuint; location: TGLint; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindFragDataLocationEXT = procedure(_program: TGLuint; colorNumber: TGLuint; const name: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFragDataLocationEXT = function(_program: TGLuint; const name: PGLchar): TGLint;
-
-  // GL_EXT_texture_array
-  TglFramebufferTextureLayerEXT = procedure(target: TGLenum; attachment: TGLenum; texture: TGLuint; level: TGLint; layer: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_texture_buffer_object
-  TglTexBufferEXT = procedure(target: TGLenum; internalformat: TGLenum; buffer: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_texture_integer
-  TglClearColorIiEXT = procedure(r: TGLint; g: TGLint; b: TGLint; a: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearColorIuiEXT = procedure(r: TGLuint; g: TGLuint; b: TGLuint; a: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameterIivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexParameterIuivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexParameterIivEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTexParameterIiuvEXT = procedure(target: TGLenum; pname: TGLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_HP_image_transform
-  TglImageTransformParameteriHP = procedure(target: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglImageTransformParameterfHP = procedure(target: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglImageTransformParameterivHP = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglImageTransformParameterfvHP = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetImageTransformParameterivHP = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetImageTransformParameterfvHP = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_depth_bounds_test
-  TglDepthBoundsEXT = procedure(zmin: TGLclampd; zmax: TGLclampd); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_blend_equation_separate
-  TglBlendEquationSeparateEXT = procedure(modeRGB: TGLenum; modeAlpha: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_transform_feedback
-  TglBeginTransformFeedbackEXT = procedure(primitiveMode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndTransformFeedbackEXT = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferRangeEXT = procedure(target: GLenum; index_: GLuint; buffer: GLuint; offset: GLsizei; size: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferOffsetEXT = procedure(target: GLenum; index_: GLuint; buffer: GLuint; offset: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferBaseEXT = procedure(target: GLenum; index_: GLuint; buffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTransformFeedbackVaryingsEXT = procedure(program_: GLuint; count: GLsizei; const locations: PGLint; bufferMode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTransformFeedbackVaryingEXT = procedure(program_: GLuint; index_: GLuint; location: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_EXT_direct_state_access
-  TglClientAttribDefaultEXT = procedure(mask: GLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPushClientAttribDefaultEXT = procedure(mask: GLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixLoadfEXT = procedure(mode: GLenum; const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixLoaddEXT = procedure(mode: GLenum; const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixMultfEXT = procedure(mode: GLenum; const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixMultdEXT = procedure(mode: GLenum; const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixLoadIdentityEXT = procedure(mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixRotatefEXT = procedure(mode: GLenum; angle: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixRotatedEXT = procedure(mode: GLenum; angle: GLdouble; x: GLdouble; y: GLdouble; z: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixScalefEXT = procedure(mode: GLenum; x: GLfloat; y: GLfloat; z: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixScaledEXT = procedure(mode: GLenum; x: GLdouble; y: GLdouble; z: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixTranslatefEXT = procedure(mode: GLenum; x: GLfloat; y: GLfloat; z: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixTranslatedEXT = procedure(mode: GLenum; x: GLdouble; y: GLdouble; z: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixFrustumEXT = procedure(mode: GLenum; left: GLdouble; right: GLdouble; bottom: GLdouble; top: GLdouble; zNear: GLdouble; zFar: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixOrthoEXT = procedure(mode: GLenum; left: GLdouble; right: GLdouble; bottom: GLdouble; top: GLdouble; zNear: GLdouble; zFar: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixPopEXT = procedure(mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixPushEXT = procedure(mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixLoadTransposefEXT = procedure(mode: GLenum; const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixLoadTransposedEXT = procedure(mode: GLenum; const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixMultTransposefEXT = procedure(mode: GLenum; const m: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMatrixMultTransposedEXT = procedure(mode: GLenum; const m: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureParameterfEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; param: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureParameterfvEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureParameteriEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; param: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureParameterivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureImage1DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; border: GLint; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureImage2DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; border: GLint; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureSubImage1DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureSubImage2DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTextureImage1DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei; border: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTextureImage2DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei; height: GLsizei; border: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTextureSubImage1DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; x: GLint; y: GLint; width: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTextureSubImage2DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; x: GLint; y: GLint; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTextureImageEXT = procedure(texture: GLuint; target: GLenum; level: GLint; format: GLenum; type_: GLenum; pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTextureParameterfvEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTextureParameterivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTextureLevelParameterfvEXT = procedure(texture: GLuint; target: GLenum; level: GLint; pname: GLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTextureLevelParameterivEXT = procedure(texture: GLuint; target: GLenum; level: GLint; pname: GLenum; params: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureImage3DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureSubImage3DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyTextureSubImage3DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; x: GLint; y: GLint; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexParameterfEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; param: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexParameterfvEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexParameteriEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; param: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexParameterivEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexImage1DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; border: GLint; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexImage2DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; border: GLint; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexSubImage1DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexSubImage2DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyMultiTexImage1DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei; border: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyMultiTexImage2DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei; height: GLsizei; border: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyMultiTexSubImage1DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; x: GLint; y: GLint; width: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyMultiTexSubImage2DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; x: GLint; y: GLint; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexImageEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; format: GLenum; type_: GLenum; pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexParameterfvEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexParameterivEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexLevelParameterfvEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; pname: GLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexLevelParameterivEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexImage3DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; format: GLenum; type_: GLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexSubImage3DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; type_: GLenum; const pixels:PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyMultiTexSubImage3DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; x: GLint; y: GLint; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindMultiTextureEXT = procedure(texunit: GLenum; target: GLenum; texture: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEnableClientStateIndexedEXT = procedure(array_: GLenum; index_: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDisableClientStateIndexedEXT = procedure(array_: GLenum; index_: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoordPointerEXT = procedure(texunit: GLenum; size: GLint; type_: GLenum; stride: GLsizei; const pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexEnvfEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; param: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexEnvfvEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexEnviEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; param: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexEnvivEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexGendEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; param: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexGendvEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; const params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexGenfEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; param: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexGenfvEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexGeniEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; param: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexGenivEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexEnvfvEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexEnvivEXT = procedure(texunit: GLenum; target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexGendvEXT = procedure(texunit: GLenum; coord: GLenum; pname: GLenum; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexGenfvEXT = procedure(texunit: GLenum; coord: GLenum; pname: GLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexGenivEXT = procedure(texunit: GLenum; coord: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFloatIndexedvEXT = procedure(target: GLenum; index_: GLuint; data: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetDoubleIndexedvEXT = procedure(target: GLenum; index_: GLuint; data: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPointerIndexedvEXT = procedure(target: GLenum; index_: GLuint; data: PPGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTextureImage3DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTextureImage2DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; border: GLint; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTextureImage1DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; border: GLint; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTextureSubImage3DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTextureSubImage2DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedTextureSubImage1DEXT = procedure(texture: GLuint; target: GLenum; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCompressedTextureImageEXT = procedure(texture: GLuint; target: GLenum; lod: GLint; img: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedMultiTexImage3DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedMultiTexImage2DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; border: GLint; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedMultiTexImage1DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; border: GLint; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedMultiTexSubImage3DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedMultiTexSubImage2DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCompressedMultiTexSubImage1DEXT = procedure(texunit: GLenum; target: GLenum; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; imageSize: GLsizei; const bits: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCompressedMultiTexImageEXT = procedure(texunit: GLenum; target: GLenum; lod: GLint; img: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramStringEXT = procedure(program_: GLuint; target: GLenum; format: GLenum; len: GLsizei; const string_: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameter4dEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameter4dvEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; const params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameter4fEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameter4fvEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedProgramLocalParameterdvEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedProgramLocalParameterfvEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedProgramivEXT = procedure(program_: GLuint; target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedProgramStringEXT = procedure(program_: GLuint; target: GLenum; pname: GLenum; string_: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameters4fvEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; count: GLsizei; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameterI4iEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; x: GLint; y: GLint; z: GLint; w: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameterI4ivEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParametersI4ivEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; count: GLsizei; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameterI4uiEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; x: GLuint; y: GLuint; z: GLuint; w: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParameterI4uivEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedProgramLocalParametersI4uivEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; count: GLsizei; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedProgramLocalParameterIivEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedProgramLocalParameterIuivEXT = procedure(program_: GLuint; target: GLenum; index_: GLuint; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureParameterIivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureParameterIuivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTextureParameterIivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTextureParameterIuivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexParameterIivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexParameterIuivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexParameterIivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMultiTexParameterIuivEXT = procedure(texture: GLuint; target: GLenum; pname: GLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform1fEXT = procedure(program_: GLuint; location: GLint; v0: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform2fEXT = procedure(program_: GLuint; location: GLint; v0: GLfloat; v1: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform3fEXT = procedure(program_: GLuint; location: GLint; v0: GLfloat; v1: GLfloat; v2: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform4fEXT = procedure(program_: GLuint; location: GLint; v0: GLfloat; v1: GLfloat; v2: GLfloat; v3: GLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform1iEXT = procedure(program_: GLuint; location: GLint; v0: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform2iEXT = procedure(program_: GLuint; location: GLint; v0: GLint; v1: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform3iEXT = procedure(program_: GLuint; location: GLint; v0: GLint; v1: GLint; v2: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform4iEXT = procedure(program_: GLuint; location: GLint; v0: GLint; v1: GLint; v2: GLint; v3: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform1fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform2fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform3fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform4fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform1ivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform2ivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform3ivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform4ivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix2fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix3fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix4fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix2x3fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix3x2fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix2x4fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix4x2fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix3x4fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniformMatrix4x3fvEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform1uiEXT = procedure(program_: GLuint; location: GLint; v0: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform2uiEXT = procedure(program_: GLuint; location: GLint; v0: GLuint; v1: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform3uiEXT = procedure(program_: GLuint; location: GLint; v0: GLuint; v1: GLuint; v2: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform4uiEXT = procedure(program_: GLuint; location: GLint; v0: GLuint; v1: GLuint; v2: GLuint; v3: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform1uivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform2uivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform3uivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramUniform4uivEXT = procedure(program_: GLuint; location: GLint; count: GLsizei; const value: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedBufferDataEXT = procedure(buffer: GLuint; size: GLsizei; const data: PGLvoid; usage: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedBufferSubDataEXT = procedure(buffer: GLuint; offset: GLsizei; size: GLsizei; const data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapNamedBufferEXT = function(buffer: GLuint; access: GLenum): PGLvoid; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglUnmapNamedBufferEXT = function(buffer: GLuint): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedBufferParameterivEXT = procedure(buffer: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedBufferPointervEXT = procedure(buffer: GLuint; pname: GLenum; params: PPGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedBufferSubDataEXT = procedure(buffer: GLuint; offset: GLsizei; size: GLsizei; data: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureBufferEXT = procedure(texture: GLuint; target: GLenum; internalformat: GLenum; buffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexBufferEXT = procedure(texunit: GLenum; target: GLenum; interformat: GLenum; buffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedRenderbufferStorageEXT = procedure(renderbuffer: GLuint; interformat: GLenum; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedRenderbufferParameterivEXT = procedure(renderbuffer: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCheckNamedFramebufferStatusEXT = function(framebuffer: GLuint; target: GLenum): GLenum; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedFramebufferTexture1DEXT = procedure(framebuffer: GLuint; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedFramebufferTexture2DEXT = procedure(framebuffer: GLuint; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedFramebufferTexture3DEXT = procedure(framebuffer: GLuint; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint; zoffset: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedFramebufferRenderbufferEXT = procedure(framebuffer: GLuint; attachment: GLenum; renderbuffertarget: GLenum; renderbuffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetNamedFramebufferAttachmentParameterivEXT = procedure(framebuffer: GLuint; attachment: GLenum; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenerateTextureMipmapEXT = procedure(texture: GLuint; target: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenerateMultiTexMipmapEXT = procedure(texunit: GLenum; target: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferDrawBufferEXT = procedure(framebuffer: GLuint; mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferDrawBuffersEXT = procedure(framebuffer: GLuint; n: GLsizei; const bufs: PGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFramebufferReadBufferEXT = procedure(framebuffer: GLuint; mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFramebufferParameterivEXT = procedure(framebuffer: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedRenderbufferStorageMultisampleEXT = procedure(renderbuffer: GLuint; samples: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedRenderbufferStorageMultisampleCoverageEXT = procedure(renderbuffer: GLuint; coverageSamples: GLsizei; colorSamples: GLsizei; internalformat: GLenum; width: GLsizei; height: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedFramebufferTextureEXT = procedure(framebuffer: GLuint; attachment: GLenum; texture: GLuint; level: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedFramebufferTextureLayerEXT = procedure(framebuffer: GLuint; attachment: GLenum; texture: GLuint; level: GLint; layer: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNamedFramebufferTextureFaceEXT = procedure(framebuffer: GLuint; attachment: GLenum; texture: GLuint; level: GLint; face: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTextureRenderbufferEXT = procedure(texture: GLuint; target: GLenum; renderbuffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexRenderbufferEXT = procedure(texunit: GLenum; target: GLenum; renderbuffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_IBM_multimode_draw_arrays
-  TglMultiModeDrawArraysIBM = procedure(mode: TGLenum; const first: PGLint; const count: PGLsizei; primcount: TGLsizei; modestride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiModeDrawElementsIBM = procedure(const mode: PGLenum; const count: PGLsizei; _type: TGLenum; const indices: PGLvoid; primcount: TGLsizei; modestride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_IBM_vertex_array_lists
-  TglColorPointerListIBM = procedure(size: TGLint; _type: TGLenum; stride: TGLint; const _pointer: PGLvoid; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColorPointerListIBM = procedure(size: TGLint; _type: TGLenum; stride: TGLint; const _pointer: PGLvoid; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEdgeFlagPointerListIBM = procedure(stride: TGLint; const _pointer: PGLboolean; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordPointerListIBM = procedure(_type: TGLenum; stride: TGLint; const _pointer: PGLvoid; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIndexPointerListIBM = procedure(_type: TGLenum; stride: TGLint; const _pointer: PGLvoid; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalPointerListIBM = procedure(_type: TGLenum; stride: TGLint; const _pointer: PGLvoid; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoordPointerListIBM = procedure(size: TGLint; _type: TGLenum; stride: TGLint; const _pointer: PGLvoid; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexPointerListIBM = procedure(size: TGLint; _type: TGLenum; stride: TGLint; const _pointer: PGLvoid; ptrstride: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_INGR_blend_func_separate
-  TglBlendFuncSeparateINGR = procedure(sfactorRGB: TGLenum; dfactorRGB: TGLenum; sfactorAlpha: TGLenum; dfactorAlpha: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_INTEL_parallel_arrays
-  TglVertexPointervINTEL = procedure(size: TGLint; _type: TGLenum; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormalPointervINTEL = procedure(_type: TGLenum; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorPointervINTEL = procedure(size: TGLint; _type: TGLenum; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoordPointervINTEL = procedure(size: TGLint; _type: TGLenum; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_MESA_resize_buffers
-  TglResizeBuffersMESA = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_MESA_window_pos
-  TglWindowPos2dMESA = procedure(x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2dvMESA = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2fMESA = procedure(x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2fvMESA = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2iMESA = procedure(x: TGLint; y: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2ivMESA = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2sMESA = procedure(x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos2svMESA = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3dMESA = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3dvMESA = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3fMESA = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3fvMESA = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3iMESA = procedure(x: TGLint; y: TGLint; z: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3ivMESA = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3sMESA = procedure(x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos3svMESA = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4dMESA = procedure(x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4dvMESA = procedure(const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4fMESA = procedure(x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4fvMESA = procedure(const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4iMESA = procedure(x: TGLint; y: TGLint; z: TGLint; w: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4ivMESA = procedure(const v: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4sMESA = procedure(x: TGLshort; y: TGLshort; z: TGLshort; w: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglWindowPos4svMESA = procedure(const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_evaluators
-  TglMapControlPointsNV = procedure(target: TGLenum; index: TGLuint; _type: TGLenum; ustride: TGLsizei; vstride: TGLsizei; uorder: TGLint; vorder: TGLint; _packed: TGLboolean; const points: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapParameterivNV = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMapParameterfvNV = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapControlPointsNV = procedure(target: TGLenum; index: TGLuint; _type: TGLenum; ustride: TGLsizei; vstride: TGLsizei; _packed: TGLboolean; points: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapParameterivNV = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapParameterfvNV = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapAttribParameterivNV = procedure(target: TGLenum; index: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetMapAttribParameterfvNV = procedure(target: TGLenum; index: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEvalMapsNV = procedure(target: TGLenum; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_fence
-  TglDeleteFencesNV = procedure(n: TGLsizei; const fences: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenFencesNV = procedure(n: TGLsizei; fences: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsFenceNV = function(fence: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTestFenceNV = function(fence: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFenceivNV = procedure(fence: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFinishFenceNV = procedure(fence: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSetFenceNV = procedure(fence: TGLuint; condition: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_fragment_program
-  TglProgramNamedParameter4fNV = procedure(id: TGLuint; len: TGLsizei; const name: PGLubyte; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramNamedParameter4dNV = procedure(id: TGLuint; len: TGLsizei; const name: PGLubyte; x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramNamedParameter4fvNV = procedure(id: TGLuint; len: TGLsizei; const name: PGLubyte; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramNamedParameter4dvNV = procedure(id: TGLuint; len: TGLsizei; const name: PGLubyte; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramNamedParameterfvNV = procedure(id: TGLuint; len: TGLsizei; const name: PGLubyte; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramNamedParameterdvNV = procedure(id: TGLuint; len: TGLsizei; const name: PGLubyte; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_half_float
-  TglVertex2hNV = procedure(x: TGLhalfNV; y: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex2hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3hNV = procedure(x: TGLhalfNV; y: TGLhalfNV; z: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex3hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4hNV = procedure(x: TGLhalfNV; y: TGLhalfNV; z: TGLhalfNV; w: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertex4hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3hNV = procedure(nx: TGLhalfNV; ny: TGLhalfNV; nz: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3hNV = procedure(red: TGLhalfNV; green: TGLhalfNV; blue: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4hNV = procedure(red: TGLhalfNV; green: TGLhalfNV; blue: TGLhalfNV; alpha: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1hNV = procedure(s: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord1hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2hNV = procedure(s: TGLhalfNV; t: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3hNV = procedure(s: TGLhalfNV; t: TGLhalfNV; r: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord3hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4hNV = procedure(s: TGLhalfNV; t: TGLhalfNV; r: TGLhalfNV; q: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1hNV = procedure(target: TGLenum; s: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord1hvNV = procedure(target: TGLenum; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2hNV = procedure(target: TGLenum; s: TGLhalfNV; t: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord2hvNV = procedure(target: TGLenum; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3hNV = procedure(target: TGLenum; s: TGLhalfNV; t: TGLhalfNV; r: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord3hvNV = procedure(target: TGLenum; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4hNV = procedure(target: TGLenum; s: TGLhalfNV; t: TGLhalfNV; r: TGLhalfNV; q: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglMultiTexCoord4hvNV = procedure(target: TGLenum; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordhNV = procedure(fog: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFogCoordhvNV = procedure(const fog: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3hNV = procedure(red: TGLhalfNV; green: TGLhalfNV; blue: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSecondaryColor3hvNV = procedure(const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexWeighthNV = procedure(weight: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexWeighthvNV = procedure(const weight: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1hNV = procedure(index: TGLuint; x: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1hvNV = procedure(index: TGLuint; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2hNV = procedure(index: TGLuint; x: TGLhalfNV; y: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2hvNV = procedure(index: TGLuint; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3hNV = procedure(index: TGLuint; x: TGLhalfNV; y: TGLhalfNV; z: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3hvNV = procedure(index: TGLuint; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4hNV = procedure(index: TGLuint; x: TGLhalfNV; y: TGLhalfNV; z: TGLhalfNV; w: TGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4hvNV = procedure(index: TGLuint; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs1hvNV = procedure(index: TGLuint; n: TGLsizei; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs2hvNV = procedure(index: TGLuint; n: TGLsizei; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs3hvNV = procedure(index: TGLuint; n: TGLsizei; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs4hvNV = procedure(index: TGLuint; n: TGLsizei; const v: PGLhalfNV); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_occlusion_query
-  TglGenOcclusionQueriesNV = procedure(n: TGLsizei; ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteOcclusionQueriesNV = procedure(n: TGLsizei; const ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsOcclusionQueryNV = function(id: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBeginOcclusionQueryNV = procedure(id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndOcclusionQueryNV = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetOcclusionQueryivNV = procedure(id: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetOcclusionQueryuivNV = procedure(id: TGLuint; pname: TGLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_pixel_data_range
-  TglPixelDataRangeNV = procedure(target: TGLenum; length: TGLsizei; _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFlushPixelDataRangeNV = procedure(target: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_point_sprite
-  TglPointParameteriNV = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameterivNV = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_primitive_restart
-  TglPrimitiveRestartNV = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPrimitiveRestartIndexNV = procedure(index: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_register_combiners
-  TglCombinerParameterfvNV = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCombinerParameterfNV = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCombinerParameterivNV = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCombinerParameteriNV = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCombinerInputNV = procedure(stage: TGLenum; portion: TGLenum; variable: TGLenum; input: TGLenum; mapping: TGLenum; componentUsage: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCombinerOutputNV = procedure(stage: TGLenum; portion: TGLenum; abOutput: TGLenum; cdOutput: TGLenum; sumOutput: TGLenum; scale: TGLenum; bias: TGLenum; abDotProduct: TGLboolean; cdDotProduct: TGLboolean; muxSum: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFinalCombinerInputNV = procedure(variable: TGLenum; input: TGLenum; mapping: TGLenum; componentUsage: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCombinerInputParameterfvNV = procedure(stage: TGLenum; portion: TGLenum; variable: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCombinerInputParameterivNV = procedure(stage: TGLenum; portion: TGLenum; variable: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCombinerOutputParameterfvNV = procedure(stage: TGLenum; portion: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCombinerOutputParameterivNV = procedure(stage: TGLenum; portion: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFinalCombinerInputParameterfvNV = procedure(variable: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFinalCombinerInputParameterivNV = procedure(variable: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_register_combiners2
-  TglCombinerStageParameterfvNV = procedure(stage: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetCombinerStageParameterfvNV = procedure(stage: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_vertex_array_range
-  TglFlushVertexArrayRangeNV = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexArrayRangeNV = procedure(length: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_vertex_program
-  TglAreProgramsResidentNV = function(n: TGLsizei; const programs: PGLuint; residences: PGLboolean): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindProgramNV = procedure(target: TGLenum; id: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteProgramsNV = procedure(n: TGLsizei; const programs: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglExecuteProgramNV = procedure(target: TGLenum; id: TGLuint; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenProgramsNV = procedure(n: TGLsizei; programs: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramParameterdvNV = procedure(target: TGLenum; index: TGLuint; pname: TGLenum; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramParameterfvNV = procedure(target: TGLenum; index: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramivNV = procedure(id: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramStringNV = procedure(id: TGLuint; pname: TGLenum; _program: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTrackMatrixivNV = procedure(target: TGLenum; address: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribdvNV = procedure(index: TGLuint; pname: TGLenum; params: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribfvNV = procedure(index: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribivNV = procedure(index: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVertexAttribPointervNV = procedure(index: TGLuint; pname: TGLenum; _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsProgramNV = function(id: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadProgramNV = procedure(target: TGLenum; id: TGLuint; len: TGLsizei; const _program: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramParameter4dNV = procedure(target: TGLenum; index: TGLuint; x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramParameter4dvNV = procedure(target: TGLenum; index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramParameter4fNV = procedure(target: TGLenum; index: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramParameter4fvNV = procedure(target: TGLenum; index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramParameters4dvNV = procedure(target: TGLenum; index: TGLuint; count: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramParameters4fvNV = procedure(target: TGLenum; index: TGLuint; count: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglRequestResidentProgramsNV = procedure(n: TGLsizei; const programs: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTrackMatrixNV = procedure(target: TGLenum; address: TGLuint; matrix: TGLenum; transform: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribPointerNV = procedure(index: TGLuint; fsize: TGLint; _type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1dNV = procedure(index: TGLuint; x: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1dvNV = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1fNV = procedure(index: TGLuint; x: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1fvNV = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1sNV = procedure(index: TGLuint; x: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib1svNV = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2dNV = procedure(index: TGLuint; x: TGLdouble; y: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2dvNV = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2fNV = procedure(index: TGLuint; x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2fvNV = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2sNV = procedure(index: TGLuint; x: TGLshort; y: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib2svNV = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3dNV = procedure(index: TGLuint; x: TGLdouble; y: TGLdouble; z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3dvNV = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3fNV = procedure(index: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3fvNV = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3sNV = procedure(index: TGLuint; x: TGLshort; y: TGLshort; z: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib3svNV = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4dNV = procedure(index: TGLuint; x: TGLdouble; y: TGLdouble; z: TGLdouble; w: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4dvNV = procedure(index: TGLuint; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4fNV = procedure(index: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4fvNV = procedure(index: TGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4sNV = procedure(index: TGLuint; x: TGLshort; y: TGLshort; z: TGLshort; w: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4svNV = procedure(index: TGLuint; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4ubNV = procedure(index: TGLuint; x: TGLubyte; y: TGLubyte; z: TGLubyte; w: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttrib4ubvNV = procedure(index: TGLuint; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs1dvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs1fvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs1svNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs2dvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs2fvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs2svNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs3dvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs3fvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs3svNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs4dvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs4fvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs4svNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglVertexAttribs4ubvNV = procedure(index: TGLuint; count: TGLsizei; const v: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_depth_buffer_float
-  TglDepthRangedNV = procedure(n: TGLdouble; f: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglClearDepthdNV = procedure(d: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDepthBoundsdNV = procedure(zmin: TGLdouble; zmax: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_framebuffer_multisample_coverage
-  TglRenderbufferStorageMultsampleCoverageNV = procedure(target: TGLenum; coverageSamples: TGLsizei; colorSamples: TGLsizei; internalformat: TGLenum; width: TGLsizei; height: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_geometry_program4
-  TglProgramVertexLimitNV = procedure(target: TGLenum; limit: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_gpu_program4
-  TglProgramLocalParameterI4iNV = procedure(target: TGLenum; index: TGLuint; x: TGLint; y: TGLint; z: TGLint; w: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameterI4ivNV = procedure(target: TGLenum; index: TGLuint; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParametersI4ivNV = procedure(target: TGLenum; index: TGLuint; count: TGLsizei; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameterI4uiNV = procedure(target: TGLenum; index: TGLuint; x: TGLuint; y: TGLuint; z: TGLuint; w: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParameterI4uivNV = procedure(target: TGLenum; index: TGLuint; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramLocalParametersI4uivNV = procedure(target: TGLenum; index: TGLuint; count: TGLsizei; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameterI4iNV = procedure(target: TGLenum; index: TGLuint; x: TGLint; y: TGLint; z: TGLint; w: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameterI4ivNV = procedure(target: TGLenum; index: TGLuint; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParametersI4ivNV = procedure(target: TGLenum; index: TGLuint; count: TGLsizei; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameterI4uiNV = procedure(target: TGLenum; index: TGLuint; x: TGLuint; y: TGLuint; z: TGLuint; w: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParameterI4uivNV = procedure(target: TGLenum; index: TGLuint; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramEnvParametersI4uivNV = procedure(target: TGLenum; index: TGLuint; count: TGLsizei; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramLocalParameterIivNV = procedure(target: TGLenum; index: TGLuint; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramLocalParameterIuivNV = procedure(target: TGLenum; index: TGLuint; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramEnvParameterIivNV = procedure(target: TGLenum; index: TGLuint; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetProgramEnvParameterIuivNV = procedure(target: TGLenum; index: TGLuint; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_parameter_buffer_object
-  TglProgramBufferParametersfvNV = procedure(target: TGLenum; buffer: TGLuint; index: TGLuint; count: TGLsizei; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramBufferParametersIivNV = procedure(target: TGLenum; buffer: TGLuint; index: TGLuint; count: TGLsizei; const params: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglProgramBufferParametersIuivNV = procedure(target: TGLenum; buffer: TGLuint; index: TGLuint; count: TGLuint; const params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_transform_feedback
-  TglBeginTransformFeedbackNV = procedure(primitiveMode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndTransformFeedbackNV = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTransformFeedbackAttribsNV = procedure(count: TGLsizei; const attribs: TGLint; bufferMode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferRangeNV = procedure(target: GLenum; index: GLuint; buffer: GLuint; offset: GLint; size: GLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferOffsetNV = procedure(target: GLenum; index: GLuint; buffer: GLuint; offset: GLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglBindBufferBaseNV = procedure(target: GLenum; index: GLuint; buffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTransformFeedbackVaryingsNV = procedure(program_: TGLuint; count: TGLsizei; const varyings: PPGLchar; bufferMode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglActiveVaryingNV = procedure(program_: TGLuint; const name: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVaryingLocationNV = function(program_: TGLuint; const name: PGLchar): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetActiveVaryingNV = procedure(program_: TGLuint; index: TGLuint; bufSize: TGLsizei; length: PGLsizei; size: PGLsizei; _type: PGLenum; name: PGLchar); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetTransformFeedbackVaryingNV = procedure(program_: TGLuint; index: TGLuint; location: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_conditional_render
-  TglBeginConditionalRenderNV = procedure(id: GLuint; mode: GLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglEndConditionalRenderNV = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_present_video
-  TglPresentFrameKeyedNV = procedure(video_slot: GLuint; minPresentTime: GLuint64EXT; beginPresentTimeId: GLuint; presentDuratioId: GLuint; type_: GLenum; target0: GLenum; fill0: GLuint; key0: GLuint; target1: GLenum; fill1: GLuint; key1: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPresentFrameDualFillNV = procedure(video_slot: GLuint; minPresentTime: GLuint64EXT; beginPresentTimeId: GLuint; presentDurationId: GLuint; type_: GLenum; target0: GLenum; fill0: GLuint; target1: GLenum; fill1: GLuint; target2: GLenum; fill2: GLuint; target3: GLenum; fill3: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVideoivNV = procedure(video_slot: GLuint; pname: GLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVideouivNV = procedure(video_slot: GLuint; pname: GLenum; params: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVideoi64vNV = procedure(video_slot: GLuint; pname: GLenum; params: PGLint64EXT); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetVideoui64vNV = procedure(video_slot: GLuint; pname: GLenum; params: PGLuint64EXT); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-//  TglVideoParameterivNV = procedure(video_slot: GLuint; pname: GLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  
-  // GL_NV_explicit_multisample
-  TglGetMultisamplefvNV = procedure (pname: GLenum; index: GLuint; val: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSampleMaskIndexedNV = procedure (index: GLuint; mask: GLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexRenderbufferNV = procedure (target: GLenum; renderbuffer: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_NV_transform_feedback2
-  TglBindTransformFeedbackNV = procedure(target: GLenum; id: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteTransformFeedbacksNV = procedure(n: GLsizei; ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenTransformFeedbacksNV = procedure(n: GLsizei; ids: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsTransformFeedbackNV = function (id: GLuint): GLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPauseTransformFeedbackNV = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglResumeTransformFeedbackNV = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDrawTransformFeedbackNV = procedure(mode: GLenum; id: GLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_PGI_misc_hints
-  TglHintPGI = procedure(target: TGLenum; mode: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_detail_texture
-  TglDetailTexFuncSGIS = procedure(target: TGLenum; n: TGLsizei; const points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetDetailTexFuncSGIS = procedure(target: TGLenum; points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_fog_function
-  TglFogFuncSGIS = procedure(n: TGLsizei; const points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFogFuncSGIS = procedure(points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_multisample
-  TglSampleMaskSGIS = procedure(value: TGLclampf; invert: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSamplePatternSGIS = procedure(pattern: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_pixel_texture
-  TglPixelTexGenParameteriSGIS = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTexGenParameterivSGIS = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTexGenParameterfSGIS = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPixelTexGenParameterfvSGIS = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPixelTexGenParameterivSGIS = procedure(pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetPixelTexGenParameterfvSGIS = procedure(pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_point_parameters
-  TglPointParameterfSGIS = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPointParameterfvSGIS = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_sharpen_texture
-  TglSharpenTexFuncSGIS = procedure(target: TGLenum; n: TGLsizei; const points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetSharpenTexFuncSGIS = procedure(target: TGLenum; points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_texture4D
-  TglTexImage4DSGIS = procedure(target: TGLenum; level: TGLint; internalformat: TGLenum; width: TGLsizei; height: TGLsizei; depth: TGLsizei; size4d: TGLsizei; border: TGLint; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexSubImage4DSGIS = procedure(target: TGLenum; level: TGLint; xoffset: TGLint; yoffset: TGLint; zoffset: TGLint; woffset: TGLint; width: TGLsizei; height: TGLsizei; depth: TGLsizei; size4d: TGLsizei; format: TGLenum; _type: TGLenum; const pixels: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_texture_color_mask
-  TglTextureColorMaskSGIS = procedure(red: TGLboolean; green: TGLboolean; blue: TGLboolean; alpha: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIS_texture_filter4
-  TglGetTexFilterFuncSGIS = procedure(target: TGLenum; filter: TGLenum; weights: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexFilterFuncSGIS = procedure(target: TGLenum; filter: TGLenum; n: TGLsizei; const weights: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_async
-  TglAsyncMarkerSGIX = procedure(marker: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFinishAsyncSGIX = function(markerp: PGLuint): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPollAsyncSGIX = function(markerp: PGLuint): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGenAsyncMarkersSGIX = function(range: TGLsizei): TGLuint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeleteAsyncMarkersSGIX = procedure(marker: TGLuint; range: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglIsAsyncMarkerSGIX = function(marker: TGLuint): TGLboolean; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_flush_raster
-  TglFlushRasterSGIX = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_fragment_lighting
-  TglFragmentColorMaterialSGIX = procedure(face: TGLenum; mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightfSGIX = procedure(light: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightfvSGIX = procedure(light: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightiSGIX = procedure(light: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightivSGIX = procedure(light: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightModelfSGIX = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightModelfvSGIX = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightModeliSGIX = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentLightModelivSGIX = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentMaterialfSGIX = procedure(face: TGLenum; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentMaterialfvSGIX = procedure(face: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentMaterialiSGIX = procedure(face: TGLenum; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglFragmentMaterialivSGIX = procedure(face: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFragmentLightfvSGIX = procedure(light: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFragmentLightivSGIX = procedure(light: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFragmentMaterialfvSGIX = procedure(face: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetFragmentMaterialivSGIX = procedure(face: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLightEnviSGIX = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_framezoom
-  TglFrameZoomSGIX = procedure(factor: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_igloo_interface
-  TglIglooInterfaceSGIX = procedure(pname: TGLenum; const params: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_instruments
-  TglGetInstrumentsSGIX = function(): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglInstrumentsBufferSGIX = procedure(size: TGLsizei; buffer: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglPollInstrumentsSGIX = function(marker_p: PGLint): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReadInstrumentsSGIX = procedure(marker: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStartInstrumentsSGIX = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglStopInstrumentsSGIX = procedure(marker: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_list_priority
-  TglGetListParameterfvSGIX = procedure(list: TGLuint; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetListParameterivSGIX = procedure(list: TGLuint; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglListParameterfSGIX = procedure(list: TGLuint; pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglListParameterfvSGIX = procedure(list: TGLuint; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglListParameteriSGIX = procedure(list: TGLuint; pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglListParameterivSGIX = procedure(list: TGLuint; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_pixel_texture
-  TglPixelTexGenSGIX = procedure(mode: TGLenum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_polynomial_ffd
-  TglDeformationMap3dSGIX = procedure(target: TGLenum; u1: TGLdouble; u2: TGLdouble; ustride: TGLint; uorder: TGLint; v1: TGLdouble; v2: TGLdouble; vstride: TGLint; vorder: TGLint; w1: TGLdouble; w2: TGLdouble; wstride: TGLint; worder: TGLint; const points: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeformationMap3fSGIX = procedure(target: TGLenum; u1: TGLfloat; u2: TGLfloat; ustride: TGLint; uorder: TGLint; v1: TGLfloat; v2: TGLfloat; vstride: TGLint; vorder: TGLint; w1: TGLfloat; w2: TGLfloat; wstride: TGLint; worder: TGLint; const points: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglDeformSGIX = procedure(mask: TGLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglLoadIdentityDeformationMapSGIX = procedure(mask: TGLbitfield); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_reference_plane
-  TglReferencePlaneSGIX = procedure(const equation: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_sprite
-  TglSpriteParameterfSGIX = procedure(pname: TGLenum; param: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSpriteParameterfvSGIX = procedure(pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSpriteParameteriSGIX = procedure(pname: TGLenum; param: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglSpriteParameterivSGIX = procedure(pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGIX_tag_sample_buffer
-  TglTagSampleBufferSGIX = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SGI_color_table
-  TglColorTableSGI = procedure(target: TGLenum; internalformat: TGLenum; width: TGLsizei; format: TGLenum; _type: TGLenum; const table: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorTableParameterfvSGI = procedure(target: TGLenum; pname: TGLenum; const params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColorTableParameterivSGI = procedure(target: TGLenum; pname: TGLenum; const params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglCopyColorTableSGI = procedure(target: TGLenum; internalformat: TGLenum; x: TGLint; y: TGLint; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableSGI = procedure(target: TGLenum; format: TGLenum; _type: TGLenum; table: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableParameterfvSGI = procedure(target: TGLenum; pname: TGLenum; params: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGetColorTableParameterivSGI = procedure(target: TGLenum; pname: TGLenum; params: PGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SUNX_constant_data
-  TglFinishTextureSUNX = procedure(); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SUN_global_alpha
-  TglGlobalAlphaFactorbSUN = procedure(factor: TGLbyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGlobalAlphaFactorsSUN = procedure(factor: TGLshort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGlobalAlphaFactoriSUN = procedure(factor: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGlobalAlphaFactorfSUN = procedure(factor: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGlobalAlphaFactordSUN = procedure(factor: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGlobalAlphaFactorubSUN = procedure(factor: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGlobalAlphaFactorusSUN = procedure(factor: TGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglGlobalAlphaFactoruiSUN = procedure(factor: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SUN_mesh_array
-  TglDrawMeshArraysSUN = procedure(mode: TGLenum; first: TGLint; count: TGLsizei; width: TGLsizei); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SUN_triangle_list
-  TglReplacementCodeuiSUN = procedure(code: TGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeusSUN = procedure(code: TGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeubSUN = procedure(code: TGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuivSUN = procedure(const code: PGLuint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeusvSUN = procedure(const code: PGLushort); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeubvSUN = procedure(const code: PGLubyte); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodePointerSUN = procedure(_type: TGLenum; stride: TGLsizei; const _pointer: PGLvoid); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // GL_SUN_vertex
-  TglColor4ubVertex2fSUN = procedure(r: TGLubyte; g: TGLubyte; b: TGLubyte; a: TGLubyte; x: TGLfloat; y: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4ubVertex2fvSUN = procedure(const c: PGLubyte; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4ubVertex3fSUN = procedure(r: TGLubyte; g: TGLubyte; b: TGLubyte; a: TGLubyte; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4ubVertex3fvSUN = procedure(const c: PGLubyte; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3fVertex3fSUN = procedure(r: TGLfloat; g: TGLfloat; b: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor3fVertex3fvSUN = procedure(const c: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3fVertex3fSUN = procedure(nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglNormal3fVertex3fvSUN = procedure(const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4fNormal3fVertex3fSUN = procedure(r: TGLfloat; g: TGLfloat; b: TGLfloat; a: TGLfloat; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglColor4fNormal3fVertex3fvSUN = procedure(const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fVertex3fSUN = procedure(s: TGLfloat; t: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fVertex3fvSUN = procedure(const tc: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4fVertex4fSUN = procedure(s: TGLfloat; t: TGLfloat; p: TGLfloat; q: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4fVertex4fvSUN = procedure(const tc: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fColor4ubVertex3fSUN = procedure(s: TGLfloat; t: TGLfloat; r: TGLubyte; g: TGLubyte; b: TGLubyte; a: TGLubyte; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fColor4ubVertex3fvSUN = procedure(const tc: PGLfloat; const c: PGLubyte; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fColor3fVertex3fSUN = procedure(s: TGLfloat; t: TGLfloat; r: TGLfloat; g: TGLfloat; b: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fColor3fVertex3fvSUN = procedure(const tc: PGLfloat; const c: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fNormal3fVertex3fSUN = procedure(s: TGLfloat; t: TGLfloat; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fNormal3fVertex3fvSUN = procedure(const tc: PGLfloat; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fColor4fNormal3fVertex3fSUN = procedure(s: TGLfloat; t: TGLfloat; r: TGLfloat; g: TGLfloat; b: TGLfloat; a: TGLfloat; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord2fColor4fNormal3fVertex3fvSUN = procedure(const tc: PGLfloat; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4fColor4fNormal3fVertex4fSUN = procedure(s: TGLfloat; t: TGLfloat; p: TGLfloat; q: TGLfloat; r: TGLfloat; g: TGLfloat; b: TGLfloat; a: TGLfloat; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat; w: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglTexCoord4fColor4fNormal3fVertex4fvSUN = procedure(const tc: PGLfloat; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiVertex3fSUN = procedure(rc: TGLuint; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiVertex3fvSUN = procedure(const rc: PGLuint; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiColor4ubVertex3fSUN = procedure(rc: TGLuint; r: TGLubyte; g: TGLubyte; b: TGLubyte; a: TGLubyte; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiColor4ubVertex3fvSUN = procedure(const rc: PGLuint; const c: PGLubyte; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiColor3fVertex3fSUN = procedure(rc: TGLuint; r: TGLfloat; g: TGLfloat; b: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiColor3fVertex3fvSUN = procedure(const rc: PGLuint; const c: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiNormal3fVertex3fSUN = procedure(rc: TGLuint; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiNormal3fVertex3fvSUN = procedure(const rc: PGLuint; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiColor4fNormal3fVertex3fSUN = procedure(rc: TGLuint; r: TGLfloat; g: TGLfloat; b: TGLfloat; a: TGLfloat; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiColor4fNormal3fVertex3fvSUN = procedure(const rc: PGLuint; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiTexCoord2fVertex3fSUN = procedure(rc: TGLuint; s: TGLfloat; t: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiTexCoord2fVertex3fvSUN = procedure(const rc: PGLuint; const tc: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiTexCoord2fNormal3fVertex3fSUN = procedure(rc: TGLuint; s: TGLfloat; t: TGLfloat; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN = procedure(const rc: PGLuint; const tc: PGLfloat; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN = procedure(rc: TGLuint; s: TGLfloat; t: TGLfloat; r: TGLfloat; g: TGLfloat; b: TGLfloat; a: TGLfloat; nx: TGLfloat; ny: TGLfloat; nz: TGLfloat; x: TGLfloat; y: TGLfloat; z: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TglReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN = procedure(const rc: PGLuint; const tc: PGLfloat; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-  // window support functions
-{$IFDEF DGL_WIN}
-  TwglGetProcAddress = function(ProcName: PAnsiChar): Pointer; stdcall;
-  TwglCopyContext = function(p1: HGLRC; p2: HGLRC; p3: Cardinal): BOOL; stdcall;
-  TwglCreateContext = function(DC: HDC): HGLRC; stdcall;
-  TwglCreateLayerContext = function(p1: HDC; p2: Integer): HGLRC; stdcall;
-  TwglDeleteContext = function(p1: HGLRC): BOOL; stdcall;
-  TwglDescribeLayerPlane = function(p1: HDC; p2, p3: Integer; p4: Cardinal; p5: PLayerPlaneDescriptor): BOOL; stdcall;
-  TwglGetCurrentContext = function: HGLRC; stdcall;
-  TwglGetCurrentDC = function: HDC; stdcall;
-  TwglGetLayerPaletteEntries = function(p1: HDC; p2, p3, p4: Integer; var pcr): Integer; stdcall;
-  TwglMakeCurrent = function(DC: HDC; p2: HGLRC): BOOL; stdcall;
-  TwglRealizeLayerPalette = function(p1: HDC; p2: Integer; p3: BOOL): BOOL; stdcall;
-  TwglSetLayerPaletteEntries = function(p1: HDC; p2, p3, p4: Integer; var pcr): Integer; stdcall;
-  TwglShareLists = function(p1, p2: HGLRC): BOOL; stdcall;
-  TwglSwapLayerBuffers = function(p1: HDC; p2: Cardinal): BOOL; stdcall;
-  TwglSwapMultipleBuffers = function(p1: UINT; const p2: PWGLSWAP): DWORD; stdcall;
-  TwglUseFontBitmapsA = function(DC: HDC; p2, p3, p4: DWORD): BOOL; stdcall;
-  TwglUseFontBitmapsW = function(DC: HDC; p2, p3, p4: DWORD): BOOL; stdcall;
-  TwglUseFontBitmaps = function(DC: HDC; p2, p3, p4: DWORD): BOOL; stdcall;
-
-  TwglUseFontOutlinesA = function(p1: HDC; p2, p3, p4: DWORD; p5, p6: Single; p7: Integer; p8: PGlyphMetricsFloat): BOOL; stdcall;
-  TwglUseFontOutlinesW = function(p1: HDC; p2, p3, p4: DWORD; p5, p6: Single; p7: Integer; p8: PGlyphMetricsFloat): BOOL; stdcall;
-  TwglUseFontOutlines = function(p1: HDC; p2, p3, p4: DWORD; p5, p6: Single; p7: Integer; p8: PGlyphMetricsFloat): BOOL; stdcall;
-
-
-  // WGL_ARB_buffer_region
-  TwglCreateBufferRegionARB = function(hDC: HDC; iLayerPlane: TGLint; uType: TGLuint): THandle; stdcall;
-  TwglDeleteBufferRegionARB = procedure(hRegion: THandle); stdcall;
-  TwglSaveBufferRegionARB = function(hRegion: THandle; x: TGLint; y: TGLint; width: TGLint; height: TGLint): Boolean; stdcall;
-  TwglRestoreBufferRegionARB = function(hRegion: THandle; x: TGLint; y: TGLint; width: TGLint; height: TGLint; xSrc: TGLint; ySrc: TGLint): Boolean; stdcall;
-
-  // WGL_ARB_extensions_string
-  TwglGetExtensionsStringARB = function(hdc: HDC): PAnsiChar; stdcall;
-
-  // WGL_ARB_make_current_read
-  TwglMakeContextCurrentARB = function(hDrawDC: HDC; hReadDC: HDC; hglrc: HGLRC): Boolean; stdcall;
-  TwglGetCurrentReadDCARB = function(): HDC; stdcall;
-
-  // WGL_ARB_pbuffer
-  TwglCreatePbufferARB = function(hDC: HDC; iPixelFormat: TGLint; iWidth: TGLint; iHeight: TGLint; const piAttribList: PGLint): HPBUFFERARB; stdcall;
-  TwglGetPbufferDCARB = function(hPbuffer: HPBUFFERARB): HDC; stdcall;
-  TwglReleasePbufferDCARB = function(hPbuffer: HPBUFFERARB; hDC: HDC): TGLint; stdcall;
-  TwglDestroyPbufferARB = function(hPbuffer: HPBUFFERARB): Boolean; stdcall;
-  TwglQueryPbufferARB = function(hPbuffer: HPBUFFERARB; iAttribute: TGLint; piValue: PGLint): Boolean; stdcall;
-
-  // WGL_ARB_pixel_format
-  TwglGetPixelFormatAttribivARB = function(hdc: HDC; iPixelFormat: TGLint; iLayerPlane: TGLint; nAttributes: TGLuint; const piAttributes: PGLint; piValues: PGLint): Boolean; stdcall;
-  TwglGetPixelFormatAttribfvARB = function(hdc: HDC; iPixelFormat: TGLint; iLayerPlane: TGLint; nAttributes: TGLuint; const piAttributes: PGLint; pfValues: PGLfloat): Boolean; stdcall;
-  TwglChoosePixelFormatARB = function(hdc: HDC; const piAttribIList: PGLint; const pfAttribFList: PGLfloat; nMaxFormats: TGLuint; piFormats: PGLint; nNumFormats: PGLuint): BOOL; stdcall;
-
-  // WGL_ARB_color_buffer_float
-  TwglClampColorARB = procedure(target: TGLenum; clamp: TGLenum); stdcall;
-
-  // WGL_ARB_render_texture
-  TwglBindTexImageARB = function(hPbuffer: HPBUFFERARB; iBuffer: TGLint): Boolean; stdcall;
-  TwglReleaseTexImageARB = function(hPbuffer: HPBUFFERARB; iBuffer: TGLint): Boolean; stdcall;
-  TwglSetPbufferAttribARB = function(hPbuffer: HPBUFFERARB; const piAttribList: PGLint): Boolean; stdcall;
-
-  // WGL_ARB_create_context
-  TwglCreateContextAttribsARB = function(hDC: HDC; hShareContext: HGLRC; const attribList: PGLint): HGLRC; stdcall;
-
-  // WGL_AMD_gpu_association
-  TwglGetGPUIDsAMD = function(maxCount: Cardinal; ids: PCardinal): Cardinal; stdcall;
-  TwglGetGPUInfoAMD = function(id: Cardinal; property_: Integer; dataType: GLenum; size: Cardinal; data: Pointer): Integer; stdcall;
-  TwglGetContextGPUIDAMD = function(hglrc: HGLRC): Cardinal; stdcall;
-  TwglCreateAssociatedContextAMD = function(id: Cardinal): HGLRC; stdcall;
-  TwglCreateAssociatedContextAttribsAMD = function(id: Cardinal; hShareContext: HGLRC; const attribList: PInteger): HGLRC; stdcall;
-  TwglDeleteAssociatedContextAMD = function(hglrc: HGLRC): Boolean; stdcall;
-  TwglMakeAssociatedContextCurrentAMD = function(hglrc: HGLRC): Boolean; stdcall;
-  TwglGetCurrentAssociatedContextAMD = function(): HGLRC; stdcall;
-  TwglBlitContextFramebufferAMD = procedure(dstCtx: HGLRC; srcX0: GLint; srcY0: GLint; srcX1: GLint; srcY1: GLint; dstX0: GLint; dstY0: GLint; dstX1: GLint; dstY1: GLint; mask: GLbitfield; filter: GLenum); stdcall;
-
-  // WGL_EXT_display_color_table
-  TwglCreateDisplayColorTableEXT = function(id: TGLushort): TGLboolean; stdcall;
-  TwglLoadDisplayColorTableEXT = function(const table: PGLushort; length: TGLuint): TGLboolean; stdcall;
-  TwglBindDisplayColorTableEXT = function(id: TGLushort): TGLboolean; stdcall;
-  TwglDestroyDisplayColorTableEXT = procedure(id: TGLushort); stdcall;
-
-  // WGL_EXT_extensions_string
-  TwglGetExtensionsStringEXT = function(): PAnsiChar; stdcall;
-
-  // WGL_EXT_make_current_read
-  TwglMakeContextCurrentEXT = function(hDrawDC: HDC; hReadDC: HDC; hglrc: HGLRC): Boolean; stdcall;
-  TwglGetCurrentReadDCEXT = function(): HDC; stdcall;
-
-  // WGL_EXT_pbuffer
-  TwglCreatePbufferEXT = function(hDC: HDC; iPixelFormat: TGLint; iWidth: TGLint; iHeight: TGLint; const piAttribList: PGLint): HPBUFFEREXT; stdcall;
-  TwglGetPbufferDCEXT = function(hPbuffer: HPBUFFEREXT): HDC; stdcall;
-  TwglReleasePbufferDCEXT = function(hPbuffer: HPBUFFEREXT; hDC: HDC): TGLint; stdcall;
-  TwglDestroyPbufferEXT = function(hPbuffer: HPBUFFEREXT): Boolean; stdcall;
-  TwglQueryPbufferEXT = function(hPbuffer: HPBUFFEREXT; iAttribute: TGLint; piValue: PGLint): Boolean; stdcall;
-
-  // WGL_EXT_pixel_format
-  TwglGetPixelFormatAttribivEXT = function(hdc: HDC; iPixelFormat: TGLint; iLayerPlane: TGLint; nAttributes: TGLuint; piAttributes: PGLint; piValues: PGLint): Boolean; stdcall;
-  TwglGetPixelFormatAttribfvEXT = function(hdc: HDC; iPixelFormat: TGLint; iLayerPlane: TGLint; nAttributes: TGLuint; piAttributes: PGLint; pfValues: PGLfloat): Boolean; stdcall;
-  TwglChoosePixelFormatEXT = function(hdc: HDC; const piAttribIList: PGLint; const pfAttribFList: PGLfloat; nMaxFormats: TGLuint; piFormats: PGLint; nNumFormats: PGLuint): Boolean; stdcall;
-
-  // WGL_EXT_swap_control
-  TwglSwapIntervalEXT = function(interval: TGLint): Boolean; stdcall;
-  TwglGetSwapIntervalEXT = function(): TGLint; stdcall;
-
-  // WGL_I3D_digital_video_control
-  TwglGetDigitalVideoParametersI3D = function(hDC: HDC; iAttribute: TGLint; piValue: PGLint): Boolean; stdcall;
-  TwglSetDigitalVideoParametersI3D = function(hDC: HDC; iAttribute: TGLint; const piValue: PGLint): Boolean; stdcall;
-
-  // WGL_I3D_gamma
-  TwglGetGammaTableParametersI3D = function(hDC: HDC; iAttribute: TGLint; piValue: PGLint): Boolean; stdcall;
-  TwglSetGammaTableParametersI3D = function(hDC: HDC; iAttribute: TGLint; const piValue: PGLint): Boolean; stdcall;
-  TwglGetGammaTableI3D = function(hDC: HDC; iEntries: TGLint; puRed: PGLushort; puGreen: PGLushort; puBlue: PGLushort): Boolean; stdcall;
-  TwglSetGammaTableI3D = function(hDC: HDC; iEntries: TGLint; const puRed: PGLushort; const puGreen: PGLushort; const puBlue: PGLushort): Boolean; stdcall;
-
-  // WGL_I3D_genlock
-  TwglEnableGenlockI3D = function(hDC: HDC): Boolean; stdcall;
-  TwglDisableGenlockI3D = function(hDC: HDC): Boolean; stdcall;
-  TwglIsEnabledGenlockI3D = function(hDC: HDC; pFlag: Boolean): Boolean; stdcall;
-  TwglGenlockSourceI3D = function(hDC: HDC; uSource: TGLuint): Boolean; stdcall;
-  TwglGetGenlockSourceI3D = function(hDC: HDC; uSource: PGLuint): Boolean; stdcall;
-  TwglGenlockSourceEdgeI3D = function(hDC: HDC; uEdge: TGLuint): Boolean; stdcall;
-  TwglGetGenlockSourceEdgeI3D = function(hDC: HDC; uEdge: PGLuint): Boolean; stdcall;
-  TwglGenlockSampleRateI3D = function(hDC: HDC; uRate: TGLuint): Boolean; stdcall;
-  TwglGetGenlockSampleRateI3D = function(hDC: HDC; uRate: PGLuint): Boolean; stdcall;
-  TwglGenlockSourceDelayI3D = function(hDC: HDC; uDelay: TGLuint): Boolean; stdcall;
-  TwglGetGenlockSourceDelayI3D = function(hDC: HDC; uDelay: PGLuint): Boolean; stdcall;
-  TwglQueryGenlockMaxSourceDelayI3D = function(hDC: HDC; uMaxLineDelay: PGLuint; uMaxPixelDelay: PGLuint): Boolean; stdcall;
-
-  // WGL_I3D_image_buffer
-  TwglCreateImageBufferI3D = function(hDC: HDC; dwSize: TGLuint; uFlags: TGLuint): TGLvoid; stdcall;
-  TwglDestroyImageBufferI3D = function(hDC: HDC; pAddress: TGLvoid): Boolean; stdcall;
-  TwglAssociateImageBufferEventsI3D = function(hDC: HDC; const pEvent: THandle; const pAddress: PGLvoid; const pSize: PGLuint; count: TGLuint): Boolean; stdcall;
-  TwglReleaseImageBufferEventsI3D = function(hDC: HDC; const pAddress: PGLvoid; count: TGLuint): Boolean; stdcall;
-
-  // WGL_I3D_swap_frame_lock
-  TwglEnableFrameLockI3D = function(): Boolean; stdcall;
-  TwglDisableFrameLockI3D = function(): Boolean; stdcall;
-  TwglIsEnabledFrameLockI3D = function(pFlag: Boolean): Boolean; stdcall;
-  TwglQueryFrameLockMasterI3D = function(pFlag: Boolean): Boolean; stdcall;
-
-  // WGL_I3D_swap_frame_usage
-  TwglGetFrameUsageI3D = function(pUsage: PGLfloat): Boolean; stdcall;
-  TwglBeginFrameTrackingI3D = function(): Boolean; stdcall;
-  TwglEndFrameTrackingI3D = function(): Boolean; stdcall;
-  TwglQueryFrameTrackingI3D = function(pFrameCount: PGLuint; pMissedFrames: PGLuint; pLastMissedUsage: PGLfloat): Boolean; stdcall;
-
-  // WGL_NV_vertex_array_range
-  TwglAllocateMemoryNV = procedure(size: TGLsizei; readfreq: TGLfloat; writefreq: TGLfloat; priority: TGLfloat); stdcall;
-  TwglFreeMemoryNV = procedure(_pointer: Pointer); stdcall;
-
-  // WGL_NV_present_video
-  TwglEnumerateVideoDevicesNV = function(hdc: HDC; phDeviceList: PHVIDEOOUTPUTDEVICENV): Integer; stdcall;
-  TwglBindVideoDeviceNV = function(hd: HDC; uVideoSlot: Cardinal; hVideoDevice: HVIDEOOUTPUTDEVICENV; piAttribList: PInteger): Boolean; stdcall;
-  TwglQueryCurrentContextNV = function(iAttribute: Integer; piValue: PInteger): Boolean; stdcall;
-
-  // WGL_NV_video_out
-  TwglGetVideoDeviceNV = function(hDC: HDC; numDevices: Integer; hVideoDevice: PHPVIDEODEV): Boolean; stdcall;
-  TwglReleaseVideoDeviceNV = function(hVideoDevice: HPVIDEODEV): Boolean; stdcall;
-  TwglBindVideoImageNV = function(hVideoDevice: HPVIDEODEV; hPbuffer: HPBUFFERARB; iVideoBuffer: Integer): Boolean; stdcall;
-  TwglReleaseVideoImageNV = function(hPbuffer: HPBUFFERARB; iVideoBuffer: Integer): Boolean; stdcall;
-  TwglSendPbufferToVideoNV = function(hPbuffer: HPBUFFERARB; iBufferType: Integer; pulCounterPbuffer: PCardinal; bBlock: Boolean): Boolean; stdcall;
-  TwglGetVideoInfoNV = function(hpVideoDevice: HPVIDEODEV; pulCounterOutputPbuffer: PCardinal; pulCounterOutputVideo: PCardinal): Boolean; stdcall;
-
-  // WGL_NV_swap_group
-  TwglJoinSwapGroupNV = function(hDC: HDC; group: GLuint): Boolean; stdcall;
-  TwglBindSwapBarrierNV = function(group: GLuint; barrier: GLuint): Boolean; stdcall;
-  TwglQuerySwapGroupNV = function(hDC: HDC; group: PGLuint; barrier: PGLuint): Boolean; stdcall;
-  TwglQueryMaxSwapGroupsNV = function(hDC: HDC; mxGroups: PGLuint; maxBarriers: PGLuint): Boolean; stdcall;
-  TwglQueryFrameCountNV = function(hDC: HDC; count: PGLuint): Boolean; stdcall;
-  TwglResetFrameCountNV = function(hDC: HDC): Boolean; stdcall;
-
-  // WGL_NV_gpu_affinity
-  TwglEnumGpusNV = function(iGpuIndex: Cardinal; phGpu: PHGPUNV): Boolean; stdcall;
-  TwglEnumGpuDevicesNV = function(hGpu: HGPUNV; iDeviceIndex: Cardinal; lpGpuDevice: PGPU_DEVICE): Boolean; stdcall;
-  TwglCreateAffinityDCNV = function(const phGpuList: PHGPUNV): HDC; stdcall;
-  TwglEnumGpusFromAffinityDCNV = function(hAffinityDC: HDC; iGpuIndex: Cardinal; hGpu: PHGPUNV): Boolean; stdcall;
-  TwglDeleteDCNV = function(hDC: HDC): Boolean; stdcall;
-
-  // WGL_OML_sync_control
-  TwglGetSyncValuesOML = function(hdc: HDC; ust: PGLint64; msc: PGLint64; sbc: PGLint64): Boolean; stdcall;
-  TwglGetMscRateOML = function(hdc: HDC; numerator: PGLint; denominator: PGLint): Boolean; stdcall;
-  TwglSwapBuffersMscOML = function(hdc: HDC; target_msc: TGLint64; divisor: TGLint64; remainder: TGLint64): TGLint64; stdcall;
-  TwglSwapLayerBuffersMscOML = function(hdc: HDC; fuPlanes: TGLint; target_msc: TGLint64; divisor: TGLint64; remainder: TGLint64): TGLint64; stdcall;
-  TwglWaitForMscOML = function(hdc: HDC; target_msc: TGLint64; divisor: TGLint64; remainder: TGLint64; ust: PGLint64; msc: PGLint64; sbc: PGLint64): Boolean; stdcall;
-  TwglWaitForSbcOML = function(hdc: HDC; target_sbc: TGLint64; ust: PGLint64; msc: PGLint64; sbc: PGLint64): Boolean; stdcall;
-
-  // WGL_3DL_stereo_control
-  TwglSetStereoEmitterState3DL = function(hDC: HDC; uState: UINT): Boolean; stdcall;
-  
-  // WIN_draw_range_elements
-  TglDrawRangeElementsWIN = procedure(mode: TGLenum; start: TGLuint; _end: TGLuint; count: TGLsizei; _type: TGLenum; const indices: PGLvoid); stdcall;
-
-  // WIN_swap_hint
-  TglAddSwapHintRectWIN = procedure(x: TGLint; y: TGLint; width: TGLsizei; height: TGLsizei); stdcall;
-{$ENDIF}
-
-{$IFDEF DGL_LINUX}
-  TglXChooseVisual = function(dpy: PDisplay; screen: GLint; attribList: PGLint): PXVisualInfo; cdecl;
-  TglXCopyContext = procedure(dpy: PDisplay; src: GLXContext; dst: GLXContext; mask: GLuint); cdecl;
-  TglXCreateContext = function(dpy: PDisplay; vis: PXVisualInfo; shareList: GLXContext; direct: GLboolean): GLXContext; cdecl;
-  TglXCreateGLXPixmap = function(dpy: PDisplay; vis: PXVisualInfo; pixmap: Pixmap): GLXPixmap cdecl;
-  TglXDestroyContext = procedure(dpy: PDisplay; ctx: GLXContext); cdecl;
-  TglXDestroyGLXPixmap = procedure(dpy : PDisplay; pix: GLXPixmap); cdecl;
-  TglXGetConfig = function(dpy : PDisplay; vis: PXVisualInfo; attrib: GLint; value: PGLint): GLint; cdecl;
-  TglXGetCurrentContext = function: GLXContext cdecl;
-  TglXGetCurrentDrawable = function: GLXDrawable cdecl;
-  TglXIsDirect = function(dpy: PDisplay; ctx: GLXContext): glboolean; cdecl;
-  TglXMakeCurrent = function(dpy: PDisplay; drawable: GLXDrawable; ctx: GLXContext): GLboolean cdecl;
-  TglXQueryExtension = function(dpy: PDisplay; errorBase: PGLint; eventBase: PGLint): GLboolean; cdecl;
-  TglXQueryVersion = function(dpy: PDisplay; major: PGLint; minor: PGLint): GLboolean cdecl;
-  TglXSwapBuffers = procedure(dpy: PDisplay; drawable: GLXDrawable); cdecl;
-  TglXUseXFont = procedure(font: Font; first: GLint; count: GLint; listBase: GLint); cdecl;
-  TglXWaitGL = procedure; cdecl; 
-  TglXWaitX = procedure; cdecl;
-
-  TglXGetClientString = function(dpy: PDisplay; name: GLint): PGLchar; cdecl;
-  TglXQueryServerString = function(dpy: PDisplay; screen: GLint; name: GLint): PGLchar; cdecl;
-  TglXQueryExtensionsString = function(dpy: PDisplay; screen: GLint): PGLchar; cdecl;
-
-  // GLX_VERSION_1_3
-  TglXGetFBConfigs = function(dpy: PDisplay; screen: GLint; nelements: PGLint): GLXFBConfig; cdecl;
-  TglXChooseFBConfig = function(dpy: PDisplay; screen: GLint; attrib_list: PGLint; nelements: PGLint): GLXFBConfig; cdecl;
-  TglXGetFBConfigAttrib = function(dpy: PDisplay; config: GLXFBConfig; attribute: GLint; value: PGLint): glint; cdecl;
-  TglXGetVisualFromFBConfig = function(dpy: PDisplay; config: GLXFBConfig) : PXVisualInfo;
-  TglXCreateWindow = function(dpy: PDisplay; config: GLXFBConfig; win: Window; attrib_list: PGLint): GLXWindow; cdecl;
-  TglXDestroyWindow = procedure(dpy: PDisplay; win: GLXWindow); cdecl;
-  TglXCreatePixmap = function(dpy: PDisplay; config: GLXFBConfig; pixmap: Pixmap; attrib_list: PGLint): GLXPixmap; cdecl;
-
-  TglXDestroyPixmap = procedure(dpy: PDisplay; pixmap: GLXPixmap); cdecl;
-  TglXCreatePbuffer = function(dpy: PDisplay; config: GLXFBConfig; attrib_list: PGLint): GLXPbuffer; cdecl;
-  TglXDestroyPbuffer = procedure(dpy: PDisplay; pbuf: GLXPbuffer); cdecl;
-  TglXQueryDrawable = procedure(dpy: PDisplay; draw: GLXDrawable; attribute: GLint; value: PGLuint); cdecl;
-  TglXCreateNewContext = function(dpy: PDisplay; config: GLXFBConfig; render_type: GLint; share_list: GLXContext; direct: GLboolean): GLXContext cdecl;
-  TglXMakeContextCurrent = function(display: PDisplay; draw: GLXDrawable; read_: GLXDrawable; ctx: GLXContext): GLboolean; cdecl;
-  TglXGetCurrentReadDrawable = function: GLXDrawable; cdecl;
-  TglXGetCurreentDisplay = function: PDisplay;
-
-  TglXQueryContext = function(dpy: PDisplay; ctx: GLXContext; attribute: GLint; value: PGLint): GLint; cdecl;
-  TglXSelectEvent = procedure(dpy: PDisplay; draw: GLXDrawable; event_mask: GLuint); cdecl;
-  TglXGetSelectedEvent = procedure(dpy: PDisplay; draw: GLXDrawable; event_mask: PGLuint); cdecl;
-
-  // GLX_VERSION_1_4
-  TglXGetProcAddress = function(const name: PAnsiChar): pointer; cdecl;
-
-  // GLX_ARB_get_proc_address
-  TglXGetProcAddressARB = function(const name: PAnsiChar): pointer; cdecl;
-
-  // GLX_ARB_create_context
-  TglXCreateContextAttribsARB = function(dpy: PDisplay; config: GLXFBConfig; share_context: GLXContext; direct: GLboolean; const attrib_list: PGLint): GLXContext; cdecl;
-
-  // GLX_EXT_import_context
-  TglXGetCurrentDisplayEXT = function: PDisplay; cdecl;
-  TglXQueryContextInfoEXT = function(dpy: PDisplay; context: GLXContext; attribute: GLint; value: PGLint): GLint; cdecl;
-  TglXGetContextIDEXT = function(const context: GLXContext): GLXContextID; cdecl;
-  TglXImportContextEXT = function(dpy: PDisplay; contextID: GLXContextID): GLXContext; cdecl;
-  TglXFreeContextEXT = procedure(dpy: PDisplay; context: GLXContext); cdecl;
-  
-  // GLX_EXT_texture_from_pixmap
-  TglXBindTexImageEXT = procedure(dpy: PDisplay; drawable: GLXDrawable; buffer: GLint; const attrib_list: PGLint); cdecl;
-  TglXReleaseTexImageEXT = procedure(dpy: PDisplay; drawable: GLXDrawable; buffer: GLint); cdecl;
-{$ENDIF}
-
-  // GL utility functions and procedures
-  TgluErrorString = function(errCode: TGLEnum): PAnsiChar; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluGetString = function(name: TGLEnum): PAnsiChar; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluOrtho2D = procedure(left, right, bottom, top: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluPerspective = procedure(fovy, aspect, zNear, zFar: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluPickMatrix = procedure(x, y, width, height: TGLdouble; const viewport: TVector4i); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluLookAt = procedure(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluProject = function(objx, objy, obyz: GLdouble; modelMatrix: PGLdouble; projMatrix: PGLdouble; viewport: PGLint; var winx, winy, winz: GLDouble): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluUnProject = function(winx, winy, winz: GLdouble; modelMatrix: PGLdouble; projMatrix: PGLdouble; viewport: PGLint; var objx, objy, objz: GLdouble): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluScaleImage = function(format: TGLEnum; widthin, heightin: TGLint; typein: TGLEnum; datain: Pointer; widthout, heightout: TGLint; typeout: TGLEnum; const dataout: Pointer): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluBuild1DMipmaps = function(target: TGLEnum; components, width: TGLint; format, atype: TGLEnum; const data: Pointer): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluBuild2DMipmaps = function(target: TGLEnum; components, width, height: TGLint; format, atype: TGLEnum; const Data: Pointer): TGLint; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNewQuadric = function: PGLUquadric; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluDeleteQuadric = procedure(state: PGLUquadric); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluQuadricNormals = procedure(quadObject: PGLUquadric; normals: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluQuadricTexture = procedure(quadObject: PGLUquadric; textureCoords: TGLboolean); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluQuadricOrientation = procedure(quadObject: PGLUquadric; orientation: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluQuadricDrawStyle = procedure(quadObject: PGLUquadric; drawStyle: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluCylinder = procedure(quadObject: PGLUquadric; baseRadius, topRadius, height: TGLdouble; slices, stacks: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluDisk = procedure(quadObject: PGLUquadric; innerRadius, outerRadius: TGLdouble; slices, loops: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluPartialDisk = procedure(quadObject: PGLUquadric; innerRadius, outerRadius: TGLdouble; slices, loops: TGLint; startAngle, sweepAngle: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluSphere = procedure(quadObject: PGLUquadric; radius: TGLdouble; slices, stacks: TGLint); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluQuadricCallback = procedure(quadObject: PGLUquadric; which: TGLEnum; fn: TGLUQuadricErrorProc); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNewTess = function: PGLUtesselator; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluDeleteTess = procedure(tess: PGLUtesselator); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessBeginPolygon = procedure(tess: PGLUtesselator; polygon_data: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessBeginContour = procedure(tess: PGLUtesselator); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessVertex = procedure(tess: PGLUtesselator; const coords: TGLArrayd3; data: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessEndContour = procedure(tess: PGLUtesselator); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessEndPolygon = procedure(tess: PGLUtesselator); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessProperty = procedure(tess: PGLUtesselator; which: TGLEnum; value: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessNormal = procedure(tess: PGLUtesselator; x, y, z: TGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluTessCallback = procedure(tess: PGLUtesselator; which: TGLEnum; fn: Pointer); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluGetTessProperty = procedure(tess: PGLUtesselator; which: TGLEnum; value: PGLdouble); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNewNurbsRenderer = function: PGLUnurbs; {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluDeleteNurbsRenderer = procedure(nobj: PGLUnurbs); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluBeginSurface = procedure(nobj: PGLUnurbs); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluBeginCurve = procedure(nobj: PGLUnurbs); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluEndCurve = procedure(nobj: PGLUnurbs); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluEndSurface = procedure(nobj: PGLUnurbs); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluBeginTrim = procedure(nobj: PGLUnurbs); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluEndTrim = procedure(nobj: PGLUnurbs); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluPwlCurve = procedure(nobj: PGLUnurbs; count: TGLint; points: PGLfloat; stride: TGLint; atype: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNurbsCurve = procedure(nobj: PGLUnurbs; nknots: TGLint; knot: PGLfloat; stride: TGLint; ctlarray: PGLfloat; order: TGLint; atype: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNurbsSurface = procedure(nobj: PGLUnurbs; sknot_count: TGLint; sknot: PGLfloat; tknot_count: TGLint; tknot: PGLfloat; s_stride, t_stride: TGLint; ctlarray: PGLfloat; sorder, torder: TGLint; atype: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluLoadSamplingMatrices = procedure(nobj: PGLUnurbs; const modelMatrix, projMatrix: TGLMatrixf4; const viewport: TVector4i); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNurbsProperty = procedure(nobj: PGLUnurbs; aproperty: TGLEnum; value: TGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluGetNurbsProperty = procedure(nobj: PGLUnurbs; aproperty: TGLEnum; value: PGLfloat); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNurbsCallback = procedure(nobj: PGLUnurbs; which: TGLEnum; fn: TGLUNurbsErrorProc); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluBeginPolygon = procedure(tess: PGLUtesselator); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluNextContour = procedure(tess: PGLUtesselator; atype: TGLEnum); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-  TgluEndPolygon = procedure(tess: PGLUtesselator); {$IFDEF DGL_WIN}stdcall; {$ELSE}cdecl; {$ENDIF}
-
-var
-  // GL_VERSION_1_0
-  glCullFace: TglCullFace;
-  glFrontFace: TglFrontFace;
-  glHint: TglHint;
-  glLineWidth: TglLineWidth;
-  glPointSize: TglPointSize;
-  glPolygonMode: TglPolygonMode;
-  glScissor: TglScissor;
-  glTexParameterf: TglTexParameterf;
-  glTexParameterfv: TglTexParameterfv;
-  glTexParameteri: TglTexParameteri;
-  glTexParameteriv: TglTexParameteriv;
-  glTexImage1D: TglTexImage1D;
-  glTexImage2D: TglTexImage2D;
-  glDrawBuffer: TglDrawBuffer;
-  glClear: TglClear;
-  glClearColor: TglClearColor;
-  glClearStencil: TglClearStencil;
-  glClearDepth: TglClearDepth;
-  glStencilMask: TglStencilMask;
-  glColorMask: TglColorMask;
-  glDepthMask: TglDepthMask;
-  glDisable: TglDisable;
-  glEnable: TglEnable;
-  glFinish: TglFinish;
-  glFlush: TglFlush;
-  glBlendFunc: TglBlendFunc;
-  glLogicOp: TglLogicOp;
-  glStencilFunc: TglStencilFunc;
-  glStencilOp: TglStencilOp;
-  glDepthFunc: TglDepthFunc;
-  glPixelStoref: TglPixelStoref;
-  glPixelStorei: TglPixelStorei;
-  glReadBuffer: TglReadBuffer;
-  glReadPixels: TglReadPixels;
-  glGetBooleanv: TglGetBooleanv;
-  glGetDoublev: TglGetDoublev;
-  glGetError: TglGetError;
-  glGetFloatv: TglGetFloatv;
-  glGetIntegerv: TglGetIntegerv;
-  glGetString: TglGetString;
-  glGetTexImage: TglGetTexImage;
-  glGetTexParameteriv: TglGetTexParameteriv;
-  glGetTexParameterfv: TglGetTexParameterfv;
-  glGetTexLevelParameterfv: TglGetTexLevelParameterfv;
-  glGetTexLevelParameteriv: TglGetTexLevelParameteriv;
-  glIsEnabled: TglIsEnabled;
-  glDepthRange: TglDepthRange;
-  glViewport: TglViewport;
-
-  // GL_VERSION_1_1
-  glDrawArrays: TglDrawArrays;
-  glDrawElements: TglDrawElements;
-  glGetPointerv: TglGetPointerv;
-  glPolygonOffset: TglPolygonOffset;
-  glCopyTexImage1D: TglCopyTexImage1D;
-  glCopyTexImage2D: TglCopyTexImage2D;
-  glCopyTexSubImage1D: TglCopyTexSubImage1D;
-  glCopyTexSubImage2D: TglCopyTexSubImage2D;
-  glTexSubImage1D: TglTexSubImage1D;
-  glTexSubImage2D: TglTexSubImage2D;
-  glBindTexture: TglBindTexture;
-  glDeleteTextures: TglDeleteTextures;
-  glGenTextures: TglGenTextures;
-{$ifdef DGL_DEPRECATED}
-  glAccum: TglAccum;
-  glAlphaFunc: TglAlphaFunc;
-  glAreTexturesResident: TglAreTexturesResident;
-  glArrayElement: TglArrayElement;
-  glBegin: TglBegin;
-  glBitmap: TglBitmap;
-  glCallList: TglCallList;
-  glCallLists: TglCallLists;
-  glClearAccum: TglClearAccum;
-  glClearIndex: TglClearIndex;
-  glClipPlane: TglClipPlane;
-  glColor3b: TglColor3b;
-  glColor3bv: TglColor3bv;
-  glColor3d: TglColor3d;
-  glColor3dv: TglColor3dv;
-  glColor3f: TglColor3f;
-  glColor3fv: TglColor3fv;
-  glColor3i: TglColor3i;
-  glColor3iv: TglColor3iv;
-  glColor3s: TglColor3s;
-  glColor3sv: TglColor3sv;
-  glColor3ub: TglColor3ub;
-  glColor3ubv: TglColor3ubv;
-  glColor3ui: TglColor3ui;
-  glColor3uiv: TglColor3uiv;
-  glColor3us: TglColor3us;
-  glColor3usv: TglColor3usv;
-  glColor4b: TglColor4b;
-  glColor4bv: TglColor4bv;
-  glColor4d: TglColor4d;
-  glColor4dv: TglColor4dv;
-  glColor4f: TglColor4f;
-  glColor4fv: TglColor4fv;
-  glColor4i: TglColor4i;
-  glColor4iv: TglColor4iv;
-  glColor4s: TglColor4s;
-  glColor4sv: TglColor4sv;
-  glColor4ub: TglColor4ub;
-  glColor4ubv: TglColor4ubv;
-  glColor4ui: TglColor4ui;
-  glColor4uiv: TglColor4uiv;
-  glColor4us: TglColor4us;
-  glColor4usv: TglColor4usv;
-  glColorMaterial: TglColorMaterial;
-  glColorPointer: TglColorPointer;
-  glCopyPixels: TglCopyPixels;
-  glDeleteLists: TglDeleteLists;
-  glDisableClientState: TglDisableClientState;
-  glDrawPixels: TglDrawPixels;
-  glEdgeFlag: TglEdgeFlag;
-  glEdgeFlagPointer: TglEdgeFlagPointer;
-  glEdgeFlagv: TglEdgeFlagv;
-  glEnableClientState: TglEnableClientState;
-  glEnd: TglEnd;
-  glEndList: TglEndList;
-  glEvalCoord1d: TglEvalCoord1d;
-  glEvalCoord1dv: TglEvalCoord1dv;
-  glEvalCoord1f: TglEvalCoord1f;
-  glEvalCoord1fv: TglEvalCoord1fv;
-  glEvalCoord2d: TglEvalCoord2d;
-  glEvalCoord2dv: TglEvalCoord2dv;
-  glEvalCoord2f: TglEvalCoord2f;
-  glEvalCoord2fv: TglEvalCoord2fv;
-  glEvalMesh1: TglEvalMesh1;
-  glEvalMesh2: TglEvalMesh2;
-  glEvalPoint1: TglEvalPoint1;
-  glEvalPoint2: TglEvalPoint2;
-  glFeedbackBuffer: TglFeedbackBuffer;
-  glFogf: TglFogf;
-  glFogfv: TglFogfv;
-  glFogi: TglFogi;
-  glFogiv: TglFogiv;
-  glFrustum: TglFrustum;
-  glGenLists: TglGenLists;
-  glGetClipPlane: TglGetClipPlane;
-  glGetLightfv: TglGetLightfv;
-  glGetLightiv: TglGetLightiv;
-  glGetMapdv: TglGetMapdv;
-  glGetMapfv: TglGetMapfv;
-  glGetMapiv: TglGetMapiv;
-  glGetMaterialfv: TglGetMaterialfv;
-  glGetMaterialiv: TglGetMaterialiv;
-  glGetPixelMapfv: TglGetPixelMapfv;
-  glGetPixelMapuiv: TglGetPixelMapuiv;
-  glGetPixelMapusv: TglGetPixelMapusv;
-  glGetPolygonStipple: TglGetPolygonStipple;
-  glGetTexEnvfv: TglGetTexEnvfv;
-  glGetTexEnviv: TglGetTexEnviv;
-  glGetTexGendv: TglGetTexGendv;
-  glGetTexGenfv: TglGetTexGenfv;
-  glGetTexGeniv: TglGetTexGeniv;
-  glIndexMask: TglIndexMask;
-  glIndexPointer: TglIndexPointer;
-  glIndexd: TglIndexd;
-  glIndexdv: TglIndexdv;
-  glIndexf: TglIndexf;
-  glIndexfv: TglIndexfv;
-  glIndexi: TglIndexi;
-  glIndexiv: TglIndexiv;
-  glIndexs: TglIndexs;
-  glIndexsv: TglIndexsv;
-  glIndexub: TglIndexub;
-  glIndexubv: TglIndexubv;
-  glInitNames: TglInitNames;
-  glInterleavedArrays: TglInterleavedArrays;
-  glIsList: TglIsList;
-  glIsTexture: TglIsTexture;
-  glLightModelf: TglLightModelf;
-  glLightModelfv: TglLightModelfv;
-  glLightModeli: TglLightModeli;
-  glLightModeliv: TglLightModeliv;
-  glLightf: TglLightf;
-  glLightfv: TglLightfv;
-  glLighti: TglLighti;
-  glLightiv: TglLightiv;
-  glLineStipple: TglLineStipple;
-  glListBase: TglListBase;
-  glLoadIdentity: TglLoadIdentity;
-  glLoadMatrixd: TglLoadMatrixd;
-  glLoadMatrixf: TglLoadMatrixf;
-  glLoadName: TglLoadName;
-  glMap1d: TglMap1d;
-  glMap1f: TglMap1f;
-  glMap2d: TglMap2d;
-  glMap2f: TglMap2f;
-  glMapGrid1d: TglMapGrid1d;
-  glMapGrid1f: TglMapGrid1f;
-  glMapGrid2d: TglMapGrid2d;
-  glMapGrid2f: TglMapGrid2f;
-  glMaterialf: TglMaterialf;
-  glMaterialfv: TglMaterialfv;
-  glMateriali: TglMateriali;
-  glMaterialiv: TglMaterialiv;
-  glMatrixMode: TglMatrixMode;
-  glMultMatrixd: TglMultMatrixd;
-  glMultMatrixf: TglMultMatrixf;
-  glNewList: TglNewList;
-  glNormal3b: TglNormal3b;
-  glNormal3bv: TglNormal3bv;
-  glNormal3d: TglNormal3d;
-  glNormal3dv: TglNormal3dv;
-  glNormal3f: TglNormal3f;
-  glNormal3fv: TglNormal3fv;
-  glNormal3i: TglNormal3i;
-  glNormal3iv: TglNormal3iv;
-  glNormal3s: TglNormal3s;
-  glNormal3sv: TglNormal3sv;
-  glNormalPointer: TglNormalPointer;
-  glOrtho: TglOrtho;
-  glPassThrough: TglPassThrough;
-  glPixelMapfv: TglPixelMapfv;
-  glPixelMapuiv: TglPixelMapuiv;
-  glPixelMapusv: TglPixelMapusv;
-  glPixelTransferf: TglPixelTransferf;
-  glPixelTransferi: TglPixelTransferi;
-  glPixelZoom: TglPixelZoom;
-  glPolygonStipple: TglPolygonStipple;
-  glPopAttrib: TglPopAttrib;
-  glPopClientAttrib: TglPopClientAttrib;
-  glPopMatrix: TglPopMatrix;
-  glPopName: TglPopName;
-  glPrioritizeTextures: TglPrioritizeTextures;
-  glPushAttrib: TglPushAttrib;
-  glPushClientAttrib: TglPushClientAttrib;
-  glPushMatrix: TglPushMatrix;
-  glPushName: TglPushName;
-  glRasterPos2d: TglRasterPos2d;
-  glRasterPos2dv: TglRasterPos2dv;
-  glRasterPos2f: TglRasterPos2f;
-  glRasterPos2fv: TglRasterPos2fv;
-  glRasterPos2i: TglRasterPos2i;
-  glRasterPos2iv: TglRasterPos2iv;
-  glRasterPos2s: TglRasterPos2s;
-  glRasterPos2sv: TglRasterPos2sv;
-  glRasterPos3d: TglRasterPos3d;
-  glRasterPos3dv: TglRasterPos3dv;
-  glRasterPos3f: TglRasterPos3f;
-  glRasterPos3fv: TglRasterPos3fv;
-  glRasterPos3i: TglRasterPos3i;
-  glRasterPos3iv: TglRasterPos3iv;
-  glRasterPos3s: TglRasterPos3s;
-  glRasterPos3sv: TglRasterPos3sv;
-  glRasterPos4d: TglRasterPos4d;
-  glRasterPos4dv: TglRasterPos4dv;
-  glRasterPos4f: TglRasterPos4f;
-  glRasterPos4fv: TglRasterPos4fv;
-  glRasterPos4i: TglRasterPos4i;
-  glRasterPos4iv: TglRasterPos4iv;
-  glRasterPos4s: TglRasterPos4s;
-  glRasterPos4sv: TglRasterPos4sv;
-  glRectd: TglRectd;
-  glRectdv: TglRectdv;
-  glRectf: TglRectf;
-  glRectfv: TglRectfv;
-  glRecti: TglRecti;
-  glRectiv: TglRectiv;
-  glRects: TglRects;
-  glRectsv: TglRectsv;
-  glRenderMode: TglRenderMode;
-  glRotated: TglRotated;
-  glRotatef: TglRotatef;
-  glScaled: TglScaled;
-  glScalef: TglScalef;
-  glSelectBuffer: TglSelectBuffer;
-  glShadeModel: TglShadeModel;
-  glTexCoord1d: TglTexCoord1d;
-  glTexCoord1dv: TglTexCoord1dv;
-  glTexCoord1f: TglTexCoord1f;
-  glTexCoord1fv: TglTexCoord1fv;
-  glTexCoord1i: TglTexCoord1i;
-  glTexCoord1iv: TglTexCoord1iv;
-  glTexCoord1s: TglTexCoord1s;
-  glTexCoord1sv: TglTexCoord1sv;
-  glTexCoord2d: TglTexCoord2d;
-  glTexCoord2dv: TglTexCoord2dv;
-  glTexCoord2f: TglTexCoord2f;
-  glTexCoord2fv: TglTexCoord2fv;
-  glTexCoord2i: TglTexCoord2i;
-  glTexCoord2iv: TglTexCoord2iv;
-  glTexCoord2s: TglTexCoord2s;
-  glTexCoord2sv: TglTexCoord2sv;
-  glTexCoord3d: TglTexCoord3d;
-  glTexCoord3dv: TglTexCoord3dv;
-  glTexCoord3f: TglTexCoord3f;
-  glTexCoord3fv: TglTexCoord3fv;
-  glTexCoord3i: TglTexCoord3i;
-  glTexCoord3iv: TglTexCoord3iv;
-  glTexCoord3s: TglTexCoord3s;
-  glTexCoord3sv: TglTexCoord3sv;
-  glTexCoord4d: TglTexCoord4d;
-  glTexCoord4dv: TglTexCoord4dv;
-  glTexCoord4f: TglTexCoord4f;
-  glTexCoord4fv: TglTexCoord4fv;
-  glTexCoord4i: TglTexCoord4i;
-  glTexCoord4iv: TglTexCoord4iv;
-  glTexCoord4s: TglTexCoord4s;
-  glTexCoord4sv: TglTexCoord4sv;
-  glTexCoordPointer: TglTexCoordPointer;
-  glTexEnvf: TglTexEnvf;
-  glTexEnvfv: TglTexEnvfv;
-  glTexEnvi: TglTexEnvi;
-  glTexEnviv: TglTexEnviv;
-  glTexGend: TglTexGend;
-  glTexGendv: TglTexGendv;
-  glTexGenf: TglTexGenf;
-  glTexGenfv: TglTexGenfv;
-  glTexGeni: TglTexGeni;
-  glTexGeniv: TglTexGeniv;
-  glTranslated: TglTranslated;
-  glTranslatef: TglTranslatef;
-  glVertex2d: TglVertex2d;
-  glVertex2dv: TglVertex2dv;
-  glVertex2f: TglVertex2f;
-  glVertex2fv: TglVertex2fv;
-  glVertex2i: TglVertex2i;
-  glVertex2iv: TglVertex2iv;
-  glVertex2s: TglVertex2s;
-  glVertex2sv: TglVertex2sv;
-  glVertex3d: TglVertex3d;
-  glVertex3dv: TglVertex3dv;
-  glVertex3f: TglVertex3f;
-  glVertex3fv: TglVertex3fv;
-  glVertex3i: TglVertex3i;
-  glVertex3iv: TglVertex3iv;
-  glVertex3s: TglVertex3s;
-  glVertex3sv: TglVertex3sv;
-  glVertex4d: TglVertex4d;
-  glVertex4dv: TglVertex4dv;
-  glVertex4f: TglVertex4f;
-  glVertex4fv: TglVertex4fv;
-  glVertex4i: TglVertex4i;
-  glVertex4iv: TglVertex4iv;
-  glVertex4s: TglVertex4s;
-  glVertex4sv: TglVertex4sv;
-  glVertexPointer: TglVertexPointer;
-{$endif}
-
-  // GL_VERSION_1_2
-  glBlendColor: TglBlendColor;
-  glBlendEquation: TglBlendEquation;
-  glDrawRangeElements: TglDrawRangeElements;
-  glTexImage3D: TglTexImage3D;
-  glTexSubImage3D: TglTexSubImage3D;
-  glCopyTexSubImage3D: TglCopyTexSubImage3D;
-{$ifdef DGL_DEPRECATED}
-  glColorTable: TglColorTable;
-  glColorTableParameterfv: TglColorTableParameterfv;
-  glColorTableParameteriv: TglColorTableParameteriv;
-  glCopyColorTable: TglCopyColorTable;
-  glGetColorTable: TglGetColorTable;
-  glGetColorTableParameterfv: TglGetColorTableParameterfv;
-  glGetColorTableParameteriv: TglGetColorTableParameteriv;
-  glColorSubTable: TglColorSubTable;
-  glCopyColorSubTable: TglCopyColorSubTable;
-  glConvolutionFilter1D: TglConvolutionFilter1D;
-  glConvolutionFilter2D: TglConvolutionFilter2D;
-  glConvolutionParameterf: TglConvolutionParameterf;
-  glConvolutionParameterfv: TglConvolutionParameterfv;
-  glConvolutionParameteri: TglConvolutionParameteri;
-  glConvolutionParameteriv: TglConvolutionParameteriv;
-  glCopyConvolutionFilter1D: TglCopyConvolutionFilter1D;
-  glCopyConvolutionFilter2D: TglCopyConvolutionFilter2D;
-  glGetConvolutionFilter: TglGetConvolutionFilter;
-  glGetConvolutionParameterfv: TglGetConvolutionParameterfv;
-  glGetConvolutionParameteriv: TglGetConvolutionParameteriv;
-  glGetSeparableFilter: TglGetSeparableFilter;
-  glSeparableFilter2D: TglSeparableFilter2D;
-  glGetHistogram: TglGetHistogram;
-  glGetHistogramParameterfv: TglGetHistogramParameterfv;
-  glGetHistogramParameteriv: TglGetHistogramParameteriv;
-  glGetMinmax: TglGetMinmax;
-  glGetMinmaxParameterfv: TglGetMinmaxParameterfv;
-  glGetMinmaxParameteriv: TglGetMinmaxParameteriv;
-  glHistogram: TglHistogram;
-  glMinmax: TglMinmax;
-  glResetHistogram: TglResetHistogram;
-  glResetMinmax: TglResetMinmax;
-{$endif}
-
-  // GL_VERSION_1_3
-  glActiveTexture: TglActiveTexture;
-  glSampleCoverage: TglSampleCoverage;
-  glCompressedTexImage3D: TglCompressedTexImage3D;
-  glCompressedTexImage2D: TglCompressedTexImage2D;
-  glCompressedTexImage1D: TglCompressedTexImage1D;
-  glCompressedTexSubImage3D: TglCompressedTexSubImage3D;
-  glCompressedTexSubImage2D: TglCompressedTexSubImage2D;
-  glCompressedTexSubImage1D: TglCompressedTexSubImage1D;
-  glGetCompressedTexImage: TglGetCompressedTexImage;
-{$ifdef DGL_DEPRECATED}
-  glClientActiveTexture: TglClientActiveTexture;
-  glMultiTexCoord1d: TglMultiTexCoord1d;
-  glMultiTexCoord1dv: TglMultiTexCoord1dv;
-  glMultiTexCoord1f: TglMultiTexCoord1f;
-  glMultiTexCoord1fv: TglMultiTexCoord1fv;
-  glMultiTexCoord1i: TglMultiTexCoord1i;
-  glMultiTexCoord1iv: TglMultiTexCoord1iv;
-  glMultiTexCoord1s: TglMultiTexCoord1s;
-  glMultiTexCoord1sv: TglMultiTexCoord1sv;
-  glMultiTexCoord2d: TglMultiTexCoord2d;
-  glMultiTexCoord2dv: TglMultiTexCoord2dv;
-  glMultiTexCoord2f: TglMultiTexCoord2f;
-  glMultiTexCoord2fv: TglMultiTexCoord2fv;
-  glMultiTexCoord2i: TglMultiTexCoord2i;
-  glMultiTexCoord2iv: TglMultiTexCoord2iv;
-  glMultiTexCoord2s: TglMultiTexCoord2s;
-  glMultiTexCoord2sv: TglMultiTexCoord2sv;
-  glMultiTexCoord3d: TglMultiTexCoord3d;
-  glMultiTexCoord3dv: TglMultiTexCoord3dv;
-  glMultiTexCoord3f: TglMultiTexCoord3f;
-  glMultiTexCoord3fv: TglMultiTexCoord3fv;
-  glMultiTexCoord3i: TglMultiTexCoord3i;
-  glMultiTexCoord3iv: TglMultiTexCoord3iv;
-  glMultiTexCoord3s: TglMultiTexCoord3s;
-  glMultiTexCoord3sv: TglMultiTexCoord3sv;
-  glMultiTexCoord4d: TglMultiTexCoord4d;
-  glMultiTexCoord4dv: TglMultiTexCoord4dv;
-  glMultiTexCoord4f: TglMultiTexCoord4f;
-  glMultiTexCoord4fv: TglMultiTexCoord4fv;
-  glMultiTexCoord4i: TglMultiTexCoord4i;
-  glMultiTexCoord4iv: TglMultiTexCoord4iv;
-  glMultiTexCoord4s: TglMultiTexCoord4s;
-  glMultiTexCoord4sv: TglMultiTexCoord4sv;
-  glLoadTransposeMatrixf: TglLoadTransposeMatrixf;
-  glLoadTransposeMatrixd: TglLoadTransposeMatrixd;
-  glMultTransposeMatrixf: TglMultTransposeMatrixf;
-  glMultTransposeMatrixd: TglMultTransposeMatrixd;
-{$endif}
-
-  // GL_VERSION_1_4
-  glBlendFuncSeparate: TglBlendFuncSeparate;
-  glMultiDrawArrays: TglMultiDrawArrays;
-  glMultiDrawElements: TglMultiDrawElements;
-  glPointParameterf: TglPointParameterf;
-  glPointParameterfv: TglPointParameterfv;
-  glPointParameteri: TglPointParameteri;
-  glPointParameteriv: TglPointParameteriv;
-{$ifdef DGL_DEPRECATED}
-  glFogCoordf: TglFogCoordf;
-  glFogCoordfv: TglFogCoordfv;
-  glFogCoordd: TglFogCoordd;
-  glFogCoorddv: TglFogCoorddv;
-  glFogCoordPointer: TglFogCoordPointer;
-  glSecondaryColor3b: TglSecondaryColor3b;
-  glSecondaryColor3bv: TglSecondaryColor3bv;
-  glSecondaryColor3d: TglSecondaryColor3d;
-  glSecondaryColor3dv: TglSecondaryColor3dv;
-  glSecondaryColor3f: TglSecondaryColor3f;
-  glSecondaryColor3fv: TglSecondaryColor3fv;
-  glSecondaryColor3i: TglSecondaryColor3i;
-  glSecondaryColor3iv: TglSecondaryColor3iv;
-  glSecondaryColor3s: TglSecondaryColor3s;
-  glSecondaryColor3sv: TglSecondaryColor3sv;
-  glSecondaryColor3ub: TglSecondaryColor3ub;
-  glSecondaryColor3ubv: TglSecondaryColor3ubv;
-  glSecondaryColor3ui: TglSecondaryColor3ui;
-  glSecondaryColor3uiv: TglSecondaryColor3uiv;
-  glSecondaryColor3us: TglSecondaryColor3us;
-  glSecondaryColor3usv: TglSecondaryColor3usv;
-  glSecondaryColorPointer: TglSecondaryColorPointer;
-  glWindowPos2d: TglWindowPos2d;
-  glWindowPos2dv: TglWindowPos2dv;
-  glWindowPos2f: TglWindowPos2f;
-  glWindowPos2fv: TglWindowPos2fv;
-  glWindowPos2i: TglWindowPos2i;
-  glWindowPos2iv: TglWindowPos2iv;
-  glWindowPos2s: TglWindowPos2s;
-  glWindowPos2sv: TglWindowPos2sv;
-  glWindowPos3d: TglWindowPos3d;
-  glWindowPos3dv: TglWindowPos3dv;
-  glWindowPos3f: TglWindowPos3f;
-  glWindowPos3fv: TglWindowPos3fv;
-  glWindowPos3i: TglWindowPos3i;
-  glWindowPos3iv: TglWindowPos3iv;
-  glWindowPos3s: TglWindowPos3s;
-  glWindowPos3sv: TglWindowPos3sv;
-{$endif}
-
-  // GL_VERSION_1_5
-  glGenQueries: TglGenQueries;
-  glDeleteQueries: TglDeleteQueries;
-  glIsQuery: TglIsQuery;
-  glBeginQuery: TglBeginQuery;
-  glEndQuery: TglEndQuery;
-  glGetQueryiv: TglGetQueryiv;
-  glGetQueryObjectiv: TglGetQueryObjectiv;
-  glGetQueryObjectuiv: TglGetQueryObjectuiv;
-  glBindBuffer: TglBindBuffer;
-  glDeleteBuffers: TglDeleteBuffers;
-  glGenBuffers: TglGenBuffers;
-  glIsBuffer: TglIsBuffer;
-  glBufferData: TglBufferData;
-  glBufferSubData: TglBufferSubData;
-  glGetBufferSubData: TglGetBufferSubData;
-  glMapBuffer: TglMapBuffer;
-  glUnmapBuffer: TglUnmapBuffer;
-  glGetBufferParameteriv: TglGetBufferParameteriv;
-  glGetBufferPointerv: TglGetBufferPointerv;
-
-  // GL_VERSION_2_0
-  glBlendEquationSeparate: TglBlendEquationSeparate;
-  glDrawBuffers: TglDrawBuffers;
-  glStencilOpSeparate: TglStencilOpSeparate;
-  glStencilFuncSeparate: TglStencilFuncSeparate;
-  glStencilMaskSeparate: TglStencilMaskSeparate;
-  glAttachShader: TglAttachShader;
-  glBindAttribLocation: TglBindAttribLocation;
-  glCompileShader: TglCompileShader;
-  glCreateProgram: TglCreateProgram;
-  glCreateShader: TglCreateShader;
-  glDeleteProgram: TglDeleteProgram;
-  glDeleteShader: TglDeleteShader;
-  glDetachShader: TglDetachShader;
-  glDisableVertexAttribArray: TglDisableVertexAttribArray;
-  glEnableVertexAttribArray: TglEnableVertexAttribArray;
-  glGetActiveAttrib: TglGetActiveAttrib;
-  glGetActiveUniform: TglGetActiveUniform;
-  glGetAttachedShaders: TglGetAttachedShaders;
-  glGetAttribLocation: TglGetAttribLocation;
-  glGetProgramiv: TglGetProgramiv;
-  glGetProgramInfoLog: TglGetProgramInfoLog;
-  glGetShaderiv: TglGetShaderiv;
-  glGetShaderInfoLog: TglGetShaderInfoLog;
-  glGetShaderSource: TglGetShaderSource;
-  glGetUniformLocation: TglGetUniformLocation;
-  glGetUniformfv: TglGetUniformfv;
-  glGetUniformiv: TglGetUniformiv;
-  glGetVertexAttribfv: TglGetVertexAttribfv;
-  glGetVertexAttribiv: TglGetVertexAttribiv;
-  glGetVertexAttribPointerv: TglGetVertexAttribPointerv;
-  glIsProgram: TglIsProgram;
-  glIsShader: TglIsShader;
-  glLinkProgram: TglLinkProgram;
-  glShaderSource: TglShaderSource;
-  glUseProgram: TglUseProgram;
-  glUniform1f: TglUniform1f;
-  glUniform2f: TglUniform2f;
-  glUniform3f: TglUniform3f;
-  glUniform4f: TglUniform4f;
-  glUniform1i: TglUniform1i;
-  glUniform2i: TglUniform2i;
-  glUniform3i: TglUniform3i;
-  glUniform4i: TglUniform4i;
-  glUniform1fv: TglUniform1fv;
-  glUniform2fv: TglUniform2fv;
-  glUniform3fv: TglUniform3fv;
-  glUniform4fv: TglUniform4fv;
-  glUniform1iv: TglUniform1iv;
-  glUniform2iv: TglUniform2iv;
-  glUniform3iv: TglUniform3iv;
-  glUniform4iv: TglUniform4iv;
-  glUniformMatrix2fv: TglUniformMatrix2fv;
-  glUniformMatrix3fv: TglUniformMatrix3fv;
-  glUniformMatrix4fv: TglUniformMatrix4fv;
-  glValidateProgram: TglValidateProgram;
-  glVertexAttrib1d: TglVertexAttrib1d;
-  glVertexAttrib1dv: TglVertexAttrib1dv;
-  glVertexAttrib1f: TglVertexAttrib1f;
-  glVertexAttrib1fv: TglVertexAttrib1fv;
-  glVertexAttrib1s: TglVertexAttrib1s;
-  glVertexAttrib1sv: TglVertexAttrib1sv;
-  glVertexAttrib2d: TglVertexAttrib2d;
-  glVertexAttrib2dv: TglVertexAttrib2dv;
-  glVertexAttrib2f: TglVertexAttrib2f;
-  glVertexAttrib2fv: TglVertexAttrib2fv;
-  glVertexAttrib2s: TglVertexAttrib2s;
-  glVertexAttrib2sv: TglVertexAttrib2sv;
-  glVertexAttrib3d: TglVertexAttrib3d;
-  glVertexAttrib3dv: TglVertexAttrib3dv;
-  glVertexAttrib3f: TglVertexAttrib3f;
-  glVertexAttrib3fv: TglVertexAttrib3fv;
-  glVertexAttrib3s: TglVertexAttrib3s;
-  glVertexAttrib3sv: TglVertexAttrib3sv;
-  glVertexAttrib4Nbv: TglVertexAttrib4Nbv;
-  glVertexAttrib4Niv: TglVertexAttrib4Niv;
-  glVertexAttrib4Nsv: TglVertexAttrib4Nsv;
-  glVertexAttrib4Nub: TglVertexAttrib4Nub;
-  glVertexAttrib4Nubv: TglVertexAttrib4Nubv;
-  glVertexAttrib4Nuiv: TglVertexAttrib4Nuiv;
-  glVertexAttrib4Nusv: TglVertexAttrib4Nusv;
-  glVertexAttrib4bv: TglVertexAttrib4bv;
-  glVertexAttrib4d: TglVertexAttrib4d;
-  glVertexAttrib4dv: TglVertexAttrib4dv;
-  glVertexAttrib4f: TglVertexAttrib4f;
-  glVertexAttrib4fv: TglVertexAttrib4fv;
-  glVertexAttrib4iv: TglVertexAttrib4iv;
-  glVertexAttrib4s: TglVertexAttrib4s;
-  glVertexAttrib4sv: TglVertexAttrib4sv;
-  glVertexAttrib4ubv: TglVertexAttrib4ubv;
-  glVertexAttrib4uiv: TglVertexAttrib4uiv;
-  glVertexAttrib4usv: TglVertexAttrib4usv;
-  glVertexAttribPointer: TglVertexAttribPointer;
-
-  // GL_VERSION_2_1
-  glUniformMatrix2x3fv: TglUniformMatrix2x3fv;
-  glUniformMatrix3x2fv: TglUniformMatrix3x2fv;
-  glUniformMatrix2x4fv: TglUniformMatrix2x4fv;
-  glUniformMatrix4x2fv: TglUniformMatrix4x2fv;
-  glUniformMatrix3x4fv: TglUniformMatrix3x4fv;
-  glUniformMatrix4x3fv: TglUniformMatrix4x3fv;
-
-  // GL_VERSION_3_0
-  glColorMaski: TglColorMaski;
-  glGetBooleani_v: TglGetBooleani_v;
-  glGetIntegeri_v: TglGetIntegeri_v;
-  glEnablei: TglEnablei;
-  glDisablei: TglDisablei;
-  glIsEnabledi: TglIsEnabledi;
-  glBeginTransformFeedback: TglBeginTransformFeedback;
-  glEndTransformFeedback: TglEndTransformFeedback;
-  glBindBufferRange: TglBindBufferRange;
-  glBindBufferBase: TglBindBufferBase;
-  glTransformFeedbackVaryings: TglTransformFeedbackVaryings;
-  glGetTransformFeedbackVarying: TglGetTransformFeedbackVarying;
-  glClampColor: TglClampColor;
-  glBeginConditionalRender: TglBeginConditionalRender;
-  glEndConditionalRender: TglEndConditionalRender;
-  glVertexAttribI1i: TglVertexAttribI1i;
-  glVertexAttribI2i: TglVertexAttribI2i;
-  glVertexAttribI3i: TglVertexAttribI3i;
-  glVertexAttribI4i: TglVertexAttribI4i;
-  glVertexAttribI1ui: TglVertexAttribI1ui;
-  glVertexAttribI2ui: TglVertexAttribI2ui;
-  glVertexAttribI3ui: TglVertexAttribI3ui;
-  glVertexAttribI4ui: TglVertexAttribI4ui;
-  glVertexAttribI1iv: TglVertexAttribI1iv;
-  glVertexAttribI2iv: TglVertexAttribI2iv;
-  glVertexAttribI3iv: TglVertexAttribI3iv;
-  glVertexAttribI4iv: TglVertexAttribI4iv;
-  glVertexAttribI1uiv: TglVertexAttribI1uiv;
-  glVertexAttribI2uiv: TglVertexAttribI2uiv;
-  glVertexAttribI3uiv: TglVertexAttribI3uiv;
-  glVertexAttribI4uiv: TglVertexAttribI4uiv;
-  glVertexAttribI4bv: TglVertexAttribI4bv;
-  glVertexAttribI4sv: TglVertexAttribI4sv;
-  glVertexAttribI4ubv: TglVertexAttribI4ubv;
-  glVertexAttribI4usv: TglVertexAttribI4usv;
-  glVertexAttribIPointer: TglVertexAttribIPointer;
-  glGetVertexAttribIiv: TglGetVertexAttribIiv;
-  glGetVertexAttribIuiv: TglGetVertexAttribIuiv;
-  glGetUniformuiv: TglGetUniformuiv;
-  glBindFragDataLocation: TglBindFragDataLocation;
-  glGetFragDataLocation: TglGetFragDataLocation;
-  glUniform1ui: TglUniform1ui;
-  glUniform2ui: TglUniform2ui;
-  glUniform3ui: TglUniform3ui;
-  glUniform4ui: TglUniform4ui;
-  glUniform1uiv: TglUniform1uiv;
-  glUniform2uiv: TglUniform2uiv;
-  glUniform3uiv: TglUniform3uiv;
-  glUniform4uiv: TglUniform4uiv;
-  glTexParameterIiv: TglTexParameterIiv;
-  glTexParameterIuiv: TglTexParameterIuiv;
-  glGetTexParameterIiv: TglGetTexParameterIiv;
-  glGetTexParameterIuiv: TglGetTexParameterIuiv;
-  glClearBufferiv: TglClearBufferiv;
-  glClearBufferuiv: TglClearBufferuiv;
-  glClearBufferfv: TglClearBufferfv;
-  glClearBufferfi: TglClearBufferfi;
-  glGetStringi: TglGetStringi;
-
-  // GL_VERSION_3_1
-  glDrawArraysInstanced: TglDrawArraysInstanced;
-  glDrawElementsInstanced: TglDrawElementsInstanced;
-  glTexBuffer: TglTexBuffer;
-  glPrimitiveRestartIndex: TglPrimitiveRestartIndex;
-
-  // GL_VERSION_3_2
-  { OpenGL 3.2 also reuses entry points from these extensions: }
-  { ARB_draw_elements_base_vertex }
-  { ARB_provoking_vertex }
-  { ARB_sync }
-  { ARB_texture_multisample }
-  glGetInteger64i_v: TglGetInteger64i_v;
-  glGetBufferParameteri64v: TglGetBufferParameteri64v;
-  glProgramParameteri: TglProgramParameteri;
-  glFramebufferTexture: TglFramebufferTexture;
-  glFramebufferTextureFace: TglFramebufferTextureFace;
-
-  // GL_3DFX_tbuffer
-  glTbufferMask3DFX: TglTbufferMask3DFX;
-
-  // GL_APPLE_element_array
-  glElementPointerAPPLE: TglElementPointerAPPLE;
-  glDrawElementArrayAPPLE: TglDrawElementArrayAPPLE;
-  glDrawRangeElementArrayAPPLE: TglDrawRangeElementArrayAPPLE;
-  glMultiDrawElementArrayAPPLE: TglMultiDrawElementArrayAPPLE;
-  glMultiDrawRangeElementArrayAPPLE: TglMultiDrawRangeElementArrayAPPLE;
-
-  // GL_APPLE_fence
-  glGenFencesAPPLE: TglGenFencesAPPLE;
-  glDeleteFencesAPPLE: TglDeleteFencesAPPLE;
-  glSetFenceAPPLE: TglSetFenceAPPLE;
-  glIsFenceAPPLE: TglIsFenceAPPLE;
-  glTestFenceAPPLE: TglTestFenceAPPLE;
-  glFinishFenceAPPLE: TglFinishFenceAPPLE;
-  glTestObjectAPPLE: TglTestObjectAPPLE;
-  glFinishObjectAPPLE: TglFinishObjectAPPLE;
-
-  // GL_APPLE_vertex_array_object
-  glBindVertexArrayAPPLE: TglBindVertexArrayAPPLE;
-  glDeleteVertexArraysAPPLE: TglDeleteVertexArraysAPPLE;
-  glGenVertexArraysAPPLE: TglGenVertexArraysAPPLE;
-  glIsVertexArrayAPPLE: TglIsVertexArrayAPPLE;
-
-  // GL_APPLE_vertex_array_range
-  glVertexArrayRangeAPPLE: TglVertexArrayRangeAPPLE;
-  glFlushVertexArrayRangeAPPLE: TglFlushVertexArrayRangeAPPLE;
-  glVertexArrayParameteriAPPLE: TglVertexArrayParameteriAPPLE;
-
-  // GL_APPLE_texture_range
-  glTextureRangeAPPLE: TglTextureRangeAPPLE;
-  glGetTexParameterPointervAPPLE: TglGetTexParameterPointervAPPLE;
-
-  // GL_APPLE_vertex_program_evaluators
-  glEnableVertexAttribAPPLE: TglEnableVertexAttribAPPLE;
-  glDisableVertexAttribAPPLE: TglDisableVertexAttribAPPLE;
-  glIsVertexAttribEnabledAPPLE: TglIsVertexAttribEnabledAPPLE;
-  glMapVertexAttrib1dAPPLE: TglMapVertexAttrib1dAPPLE;
-  glMapVertexAttrib1fAPPLE: TglMapVertexAttrib1fAPPLE;
-  glMapVertexAttrib2dAPPLE: TglMapVertexAttrib2dAPPLE;
-  glMapVertexAttrib2fAPPLE: TglMapVertexAttrib2fAPPLE;
-
-  // GL_APPLE_object_purgeable
-  glObjectPurgeableAPPLE: TglObjectPurgeableAPPLE;
-  glObjectUnpurgeableAPPLE: TglObjectUnpurgeableAPPLE;
-  glGetObjectParameterivAPPLE: TglGetObjectParameterivAPPLE;
-
-  // GL_ARB_matrix_palette
-  glCurrentPaletteMatrixARB: TglCurrentPaletteMatrixARB;
-  glMatrixIndexubvARB: TglMatrixIndexubvARB;
-  glMatrixIndexusvARB: TglMatrixIndexusvARB;
-  glMatrixIndexuivARB: TglMatrixIndexuivARB;
-  glMatrixIndexPointerARB: TglMatrixIndexPointerARB;
-
-  // GL_ARB_multisample
-  glSampleCoverageARB: TglSampleCoverageARB;
-
-  // GL_ARB_multitexture
-  glActiveTextureARB: TglActiveTextureARB;
-  glClientActiveTextureARB: TglClientActiveTextureARB;
-  glMultiTexCoord1dARB: TglMultiTexCoord1dARB;
-  glMultiTexCoord1dvARB: TglMultiTexCoord1dvARB;
-  glMultiTexCoord1fARB: TglMultiTexCoord1fARB;
-  glMultiTexCoord1fvARB: TglMultiTexCoord1fvARB;
-  glMultiTexCoord1iARB: TglMultiTexCoord1iARB;
-  glMultiTexCoord1ivARB: TglMultiTexCoord1ivARB;
-  glMultiTexCoord1sARB: TglMultiTexCoord1sARB;
-  glMultiTexCoord1svARB: TglMultiTexCoord1svARB;
-  glMultiTexCoord2dARB: TglMultiTexCoord2dARB;
-  glMultiTexCoord2dvARB: TglMultiTexCoord2dvARB;
-  glMultiTexCoord2fARB: TglMultiTexCoord2fARB;
-  glMultiTexCoord2fvARB: TglMultiTexCoord2fvARB;
-  glMultiTexCoord2iARB: TglMultiTexCoord2iARB;
-  glMultiTexCoord2ivARB: TglMultiTexCoord2ivARB;
-  glMultiTexCoord2sARB: TglMultiTexCoord2sARB;
-  glMultiTexCoord2svARB: TglMultiTexCoord2svARB;
-  glMultiTexCoord3dARB: TglMultiTexCoord3dARB;
-  glMultiTexCoord3dvARB: TglMultiTexCoord3dvARB;
-  glMultiTexCoord3fARB: TglMultiTexCoord3fARB;
-  glMultiTexCoord3fvARB: TglMultiTexCoord3fvARB;
-  glMultiTexCoord3iARB: TglMultiTexCoord3iARB;
-  glMultiTexCoord3ivARB: TglMultiTexCoord3ivARB;
-  glMultiTexCoord3sARB: TglMultiTexCoord3sARB;
-  glMultiTexCoord3svARB: TglMultiTexCoord3svARB;
-  glMultiTexCoord4dARB: TglMultiTexCoord4dARB;
-  glMultiTexCoord4dvARB: TglMultiTexCoord4dvARB;
-  glMultiTexCoord4fARB: TglMultiTexCoord4fARB;
-  glMultiTexCoord4fvARB: TglMultiTexCoord4fvARB;
-  glMultiTexCoord4iARB: TglMultiTexCoord4iARB;
-  glMultiTexCoord4ivARB: TglMultiTexCoord4ivARB;
-  glMultiTexCoord4sARB: TglMultiTexCoord4sARB;
-  glMultiTexCoord4svARB: TglMultiTexCoord4svARB;
-
-  // GL_ARB_point_parameters
-  glPointParameterfARB: TglPointParameterfARB;
-  glPointParameterfvARB: TglPointParameterfvARB;
-
-  // GL_ARB_texture_compression
-  glCompressedTexImage3DARB: TglCompressedTexImage3DARB;
-  glCompressedTexImage2DARB: TglCompressedTexImage2DARB;
-  glCompressedTexImage1DARB: TglCompressedTexImage1DARB;
-  glCompressedTexSubImage3DARB: TglCompressedTexSubImage3DARB;
-  glCompressedTexSubImage2DARB: TglCompressedTexSubImage2DARB;
-  glCompressedTexSubImage1DARB: TglCompressedTexSubImage1DARB;
-  glGetCompressedTexImageARB: TglGetCompressedTexImageARB;
-
-  // GL_ARB_transpose_matrix
-  glLoadTransposeMatrixfARB: TglLoadTransposeMatrixfARB;
-  glLoadTransposeMatrixdARB: TglLoadTransposeMatrixdARB;
-  glMultTransposeMatrixfARB: TglMultTransposeMatrixfARB;
-  glMultTransposeMatrixdARB: TglMultTransposeMatrixdARB;
-
-  // GL_ARB_vertex_blend
-  glWeightbvARB: TglWeightbvARB;
-  glWeightsvARB: TglWeightsvARB;
-  glWeightivARB: TglWeightivARB;
-  glWeightfvARB: TglWeightfvARB;
-  glWeightdvARB: TglWeightdvARB;
-  glWeightubvARB: TglWeightubvARB;
-  glWeightusvARB: TglWeightusvARB;
-  glWeightuivARB: TglWeightuivARB;
-  glWeightPointerARB: TglWeightPointerARB;
-  glVertexBlendARB: TglVertexBlendARB;
-
-  // GL_ARB_vertex_buffer_object
-  glBindBufferARB: TglBindBufferARB;
-  glDeleteBuffersARB: TglDeleteBuffersARB;
-  glGenBuffersARB: TglGenBuffersARB;
-  glIsBufferARB: TglIsBufferARB;
-  glBufferDataARB: TglBufferDataARB;
-  glBufferSubDataARB: TglBufferSubData;
-  glGetBufferSubDataARB: TglGetBufferSubDataARB;
-  glMapBufferARB: TglMapBufferARB;
-  glUnmapBufferARB: TglUnmapBufferARB;
-  glGetBufferParameterivARB: TglGetBufferParameterivARB;
-  glGetBufferPointervARB: TglGetBufferPointervARB;
-
-  // GL_ARB_vertex_program
-  glVertexAttrib1dARB: TglVertexAttrib1dARB;
-  glVertexAttrib1dvARB: TglVertexAttrib1dvARB;
-  glVertexAttrib1fARB: TglVertexAttrib1fARB;
-  glVertexAttrib1fvARB: TglVertexAttrib1fvARB;
-  glVertexAttrib1sARB: TglVertexAttrib1sARB;
-  glVertexAttrib1svARB: TglVertexAttrib1svARB;
-  glVertexAttrib2dARB: TglVertexAttrib2dARB;
-  glVertexAttrib2dvARB: TglVertexAttrib2dvARB;
-  glVertexAttrib2fARB: TglVertexAttrib2fARB;
-  glVertexAttrib2fvARB: TglVertexAttrib2fvARB;
-  glVertexAttrib2sARB: TglVertexAttrib2sARB;
-  glVertexAttrib2svARB: TglVertexAttrib2svARB;
-  glVertexAttrib3dARB: TglVertexAttrib3dARB;
-  glVertexAttrib3dvARB: TglVertexAttrib3dvARB;
-  glVertexAttrib3fARB: TglVertexAttrib3fARB;
-  glVertexAttrib3fvARB: TglVertexAttrib3fvARB;
-  glVertexAttrib3sARB: TglVertexAttrib3sARB;
-  glVertexAttrib3svARB: TglVertexAttrib3svARB;
-  glVertexAttrib4NbvARB: TglVertexAttrib4NbvARB;
-  glVertexAttrib4NivARB: TglVertexAttrib4NivARB;
-  glVertexAttrib4NsvARB: TglVertexAttrib4NsvARB;
-  glVertexAttrib4NubARB: TglVertexAttrib4NubARB;
-  glVertexAttrib4NubvARB: TglVertexAttrib4NubvARB;
-  glVertexAttrib4NuivARB: TglVertexAttrib4NuivARB;
-  glVertexAttrib4NusvARB: TglVertexAttrib4NusvARB;
-  glVertexAttrib4bvARB: TglVertexAttrib4bvARB;
-  glVertexAttrib4dARB: TglVertexAttrib4dARB;
-  glVertexAttrib4dvARB: TglVertexAttrib4dvARB;
-  glVertexAttrib4fARB: TglVertexAttrib4fARB;
-  glVertexAttrib4fvARB: TglVertexAttrib4fvARB;
-  glVertexAttrib4ivARB: TglVertexAttrib4ivARB;
-  glVertexAttrib4sARB: TglVertexAttrib4sARB;
-  glVertexAttrib4svARB: TglVertexAttrib4svARB;
-  glVertexAttrib4ubvARB: TglVertexAttrib4ubvARB;
-  glVertexAttrib4uivARB: TglVertexAttrib4uivARB;
-  glVertexAttrib4usvARB: TglVertexAttrib4usvARB;
-  glVertexAttribPointerARB: TglVertexAttribPointerARB;
-  glEnableVertexAttribArrayARB: TglEnableVertexAttribArrayARB;
-  glDisableVertexAttribArrayARB: TglDisableVertexAttribArrayARB;
-  glProgramStringARB: TglProgramStringARB;
-  glBindProgramARB: TglBindProgramARB;
-  glDeleteProgramsARB: TglDeleteProgramsARB;
-  glGenProgramsARB: TglGenProgramsARB;
-
-  glProgramEnvParameter4dARB: TglProgramEnvParameter4dARB;
-  glProgramEnvParameter4dvARB: TglProgramEnvParameter4dvARB;
-  glProgramEnvParameter4fARB: TglProgramEnvParameter4fARB;
-  glProgramEnvParameter4fvARB: TglProgramEnvParameter4fvARB;
-  glProgramLocalParameter4dARB: TglProgramLocalParameter4dARB;
-  glProgramLocalParameter4dvARB: TglProgramLocalParameter4dvARB;
-  glProgramLocalParameter4fARB: TglProgramLocalParameter4fARB;
-  glProgramLocalParameter4fvARB: TglProgramLocalParameter4fvARB;
-  glGetProgramEnvParameterdvARB: TglGetProgramEnvParameterdvARB;
-  glGetProgramEnvParameterfvARB: TglGetProgramEnvParameterfvARB;
-  glGetProgramLocalParameterdvARB: TglGetProgramLocalParameterdvARB;
-  glGetProgramLocalParameterfvARB: TglGetProgramLocalParameterfvARB;
-  glGetProgramivARB: TglGetProgramivARB;
-  glGetProgramStringARB: TglGetProgramStringARB;
-  glGetVertexAttribdvARB: TglGetVertexAttribdvARB;
-  glGetVertexAttribfvARB: TglGetVertexAttribfvARB;
-  glGetVertexAttribivARB: TglGetVertexAttribivARB;
-  glGetVertexAttribPointervARB: TglGetVertexAttribPointervARB;
-  glIsProgramARB: TglIsProgramARB;
-
-  // GL_ARB_window_pos
-  glWindowPos2dARB: TglWindowPos2dARB;
-  glWindowPos2dvARB: TglWindowPos2dvARB;
-  glWindowPos2fARB: TglWindowPos2fARB;
-  glWindowPos2fvARB: TglWindowPos2fvARB;
-  glWindowPos2iARB: TglWindowPos2iARB;
-  glWindowPos2ivARB: TglWindowPos2ivARB;
-  glWindowPos2sARB: TglWindowPos2sARB;
-  glWindowPos2svARB: TglWindowPos2svARB;
-  glWindowPos3dARB: TglWindowPos3dARB;
-  glWindowPos3dvARB: TglWindowPos3dvARB;
-  glWindowPos3fARB: TglWindowPos3fARB;
-  glWindowPos3fvARB: TglWindowPos3fvARB;
-  glWindowPos3iARB: TglWindowPos3iARB;
-  glWindowPos3ivARB: TglWindowPos3ivARB;
-  glWindowPos3sARB: TglWindowPos3sARB;
-  glWindowPos3svARB: TglWindowPos3svARB;
-
-  // GL_ARB_draw_buffers
-  glDrawBuffersARB: TglDrawBuffersARB;
-
-  // GL_ARB_color_buffer_float
-  glClampColorARB: TglClampColorARB;
-
-  // GL_ARB_vertex_shader
-  glGetActiveAttribARB: TglGetActiveAttribARB;
-  glGetAttribLocationARB: TglGetAttribLocationARB;
-  glBindAttribLocationARB: TglBindAttribLocationARB;
-
-  // GL_ARB_shader_objects
-  glDeleteObjectARB: TglDeleteObjectARB;
-  glGetHandleARB: TglGetHandleARB;
-  glDetachObjectARB: TglDetachObjectARB;
-  glCreateShaderObjectARB: TglCreateShaderObjectARB;
-  glShaderSourceARB: TglShaderSourceARB;
-  glCompileShaderARB: TglCompileShaderARB;
-  glCreateProgramObjectARB: TglCreateProgramObjectARB;
-  glAttachObjectARB: TglAttachObjectARB;
-  glLinkProgramARB: TglLinkProgramARB;
-  glUseProgramObjectARB: TglUseProgramObjectARB;
-  glValidateProgramARB: TglValidateProgramARB;
-  glUniform1fARB: TglUniform1fARB;
-  glUniform2fARB: TglUniform2fARB;
-  glUniform3fARB: TglUniform3fARB;
-  glUniform4fARB: TglUniform4fARB;
-  glUniform1iARB: TglUniform1iARB;
-  glUniform2iARB: TglUniform2iARB;
-  glUniform3iARB: TglUniform3iARB;
-  glUniform4iARB: TglUniform4iARB;
-  glUniform1fvARB: TglUniform1fvARB;
-  glUniform2fvARB: TglUniform2fvARB;
-  glUniform3fvARB: TglUniform3fvARB;
-  glUniform4fvARB: TglUniform4fvARB;
-  glUniform1ivARB: TglUniform1ivARB;
-  glUniform2ivARB: TglUniform2ivARB;
-  glUniform3ivARB: TglUniform3ivARB;
-  glUniform4ivARB: TglUniform4ivARB;
-  glUniformMatrix2fvARB: TglUniformMatrix2fvARB;
-  glUniformMatrix3fvARB: TglUniformMatrix3fvARB;
-  glUniformMatrix4fvARB: TglUniformMatrix4fvARB;
-  glGetObjectParameterfvARB: TglGetObjectParameterfvARB;
-  glGetObjectParameterivARB: TglGetObjectParameterivARB;
-  glGetInfoLogARB: TglGetInfoLogARB;
-  glGetAttachedObjectsARB: TglGetAttachedObjectsARB;
-  glGetUniformLocationARB: TglGetUniformLocationARB;
-  glGetActiveUniformARB: TglGetActiveUniformARB;
-  glGetUniformfvARB: TglGetUniformfvARB;
-  glGetUniformivARB: TglGetUniformivARB;
-  glGetShaderSourceARB: TglGetShaderSourceARB;
-
-  // GL_ARB_Occlusion_Query
-  glGenQueriesARB: TglGenQueriesARB;
-  glDeleteQueriesARB: TglDeleteQueriesARB;
-  glIsQueryARB: TglIsQueryARB;
-  glBeginQueryARB: TglBeginQueryARB;
-  glEndQueryARB: TglEndQueryARB;
-  glGetQueryivARB: TglGetQueryivARB;
-  glGetQueryObjectivARB: TglGetQueryObjectivARB;
-  glGetQueryObjectuivARB: TglGetQueryObjectuivARB;
-
-  // GL_ARB_draw_instanced
-  glDrawArraysInstancedARB: TglDrawArraysInstancedARB;
-  glDrawElementsInstancedARB: TglDrawElementsInstancedARB;
-
-  // GL_ARB_framebuffer_object
-  glIsRenderbuffer: TglIsRenderbuffer;
-  glBindRenderbuffer: TglBindRenderbuffer;
-  glDeleteRenderbuffers: TglDeleteRenderbuffers;
-  glGenRenderbuffers: TglGenRenderbuffers;
-  glRenderbufferStorage: TglRenderbufferStorage;
-  glGetRenderbufferParameteriv: TglGetRenderbufferParameteriv;
-  glIsFramebuffer: TglIsFramebuffer;
-  glBindFramebuffer: TglBindFramebuffer;
-  glDeleteFramebuffers: TglDeleteFramebuffers;
-  glGenFramebuffers: TglGenFramebuffers;
-  glCheckFramebufferStatus: TglCheckFramebufferStatus;
-  glFramebufferTexture1D: TglFramebufferTexture1D;
-  glFramebufferTexture2D: TglFramebufferTexture2D;
-  glFramebufferTexture3D: TglFramebufferTexture3D;
-  glFramebufferRenderbuffer: TglFramebufferRenderbuffer;
-  glGetFramebufferAttachmentParameteriv: TglGetFramebufferAttachmentParameteriv;
-  glGenerateMipmap: TglGenerateMipmap;
-  glBlitFramebuffer: TglBlitFramebuffer;
-  glRenderbufferStorageMultisample: TglRenderbufferStorageMultisample;
-  glFramebufferTextureLayer: TglFramebufferTextureLayer;
-
-  // GL_ARB_geometry_shader4
-  glProgramParameteriARB: TglProgramParameteriARB;
-  glFramebufferTextureARB: TglFramebufferTextureARB;
-  glFramebufferTextureLayerARB: TglFramebufferTextureLayerARB;
-  glFramebufferTextureFaceARB: TglFramebufferTextureFaceARB;
-
-  // GL_ARB_instanced_arrays
-  glVertexAttribDivisorARB: TglVertexAttribDivisorARB;
-
-  // GL_ARB_map_buffer_range
-  glMapBufferRange: TglMapBufferRange;
-  glFlushMappedBufferRange: TglFlushMappedBufferRange;
-
-  // GL_ARB_texture_buffer_object
-  glTexBufferARB: TglTexBufferARB;
-
-  // GL_ARB_vertex_array_object
-  glBindVertexArray: TglBindVertexArray;
-  glDeleteVertexArrays: TglDeleteVertexArrays;
-  glGenVertexArrays: TglGenVertexArrays;
-  glIsVertexArray: TglIsVertexArray;
-
-  // GL_ARB_uniform_buffer_object
-  glGetUniformIndices: TglGetUniformIndices;
-  glGetActiveUniformsiv: TglGetActiveUniformsiv;
-  glGetActiveUniformName: TglGetActiveUniformName;
-  glGetUniformBlockIndex: TglGetUniformBlockIndex;
-  glGetActiveUniformBlockiv: TglGetActiveUniformBlockiv;
-  glGetActiveUniformBlockName: TglGetActiveUniformBlockName;
-  glUniformBlockBinding: TglUniformBlockBinding;
-
-  // GL_ARB_copy_buffer
-  glCopyBufferSubData: TglCopyBufferSubData;
-
-  // GL_ARB_draw_elements_base_vertex
-  glDrawElementsBaseVertex: TglDrawElementsBaseVertex;
-  glDrawRangeElementsBaseVertex: TglDrawRangeElementsBaseVertex;
-  glDrawElementsInstancedBaseVertex: TglDrawElementsInstancedBaseVertex;
-  glMultiDrawElementsBaseVertex: TglMultiDrawElementsBaseVertex;
-
-  // GL_ARB_provoking_vertex
-  glProvokingVertex: TglProvokingVertex;
-
-  // GL_ARB_sync
-  glFenceSync: TglFenceSync;
-  glIsSync: TglIsSync;
-  glDeleteSync: TglDeleteSync;
-  glClientWaitSync: TglClientWaitSync;
-  glWaitSync: TglWaitSync;
-  glGetInteger64v: TglGetInteger64v;
-  glGetSynciv: TglGetSynciv;
-
-  // GL_ARB_texture_multisample
-  glTexImage2DMultisample: TglTexImage2DMultisample;
-  glTexImage3DMultisample: TglTexImage3DMultisample;
-  glGetMultisamplefv: TglGetMultisamplefv;
-  glSampleMaski: TglSampleMaski;
-
-  // GL_ARB_draw_buffers_blend
-  glBlendEquationi: TglBlendEquationi;
-  glBlendEquationSeparatei: TglBlendEquationSeparatei;
-  glBlendFunci: TglBlendFunci;
-  glBlendFuncSeparatei: TglBlendFuncSeparatei;
-
-  // GL_ARB_sample_shading
-  glMinSampleShading: TglMinSampleShading;
-
-  // GL_ATI_draw_buffers
-  glDrawBuffersATI: TglDrawBuffersATI;
-
-  // GL_ATI_element_array
-  glElementPointerATI: TglElementPointerATI;
-  glDrawElementArrayATI: TglDrawElementArrayATI;
-  glDrawRangeElementArrayATI: TglDrawRangeElementArrayATI;
-
-  // GL_ATI_envmap_bumpmap
-  glTexBumpParameterivATI: TglTexBumpParameterivATI;
-  glTexBumpParameterfvATI: TglTexBumpParameterfvATI;
-  glGetTexBumpParameterivATI: TglGetTexBumpParameterivATI;
-  glGetTexBumpParameterfvATI: TglGetTexBumpParameterfvATI;
-
-  // GL_ATI_fragment_shader
-  glGenFragmentShadersATI: TglGenFragmentShadersATI;
-  glBindFragmentShaderATI: TglBindFragmentShaderATI;
-  glDeleteFragmentShaderATI: TglDeleteFragmentShaderATI;
-  glBeginFragmentShaderATI: TglBeginFragmentShaderATI;
-  glEndFragmentShaderATI: TglEndFragmentShaderATI;
-  glPassTexCoordATI: TglPassTexCoordATI;
-  glSampleMapATI: TglSampleMapATI;
-  glColorFragmentOp1ATI: TglColorFragmentOp1ATI;
-  glColorFragmentOp2ATI: TglColorFragmentOp2ATI;
-  glColorFragmentOp3ATI: TglColorFragmentOp3ATI;
-  glAlphaFragmentOp1ATI: TglAlphaFragmentOp1ATI;
-  glAlphaFragmentOp2ATI: TglAlphaFragmentOp2ATI;
-  glAlphaFragmentOp3ATI: TglAlphaFragmentOp3ATI;
-  glSetFragmentShaderConstantATI: TglSetFragmentShaderConstantATI;
-
-  // GL_ATI_map_object_buffer
-  glMapObjectBufferATI: TglMapObjectBufferATI;
-  glUnmapObjectBufferATI: TglUnmapObjectBufferATI;
-
-  // GL_ATI_pn_triangles
-  glPNTrianglesiATI: TglPNTrianglesiATI;
-  glPNTrianglesfATI: TglPNTrianglesfATI;
-
-  // GL_ATI_separate_stencil
-  glStencilOpSeparateATI: TglStencilOpSeparateATI;
-  glStencilFuncSeparateATI: TglStencilFuncSeparateATI;
-
-  // GL_ATI_vertex_array_object
-  glNewObjectBufferATI: TglNewObjectBufferATI;
-  glIsObjectBufferATI: TglIsObjectBufferATI;
-  glUpdateObjectBufferATI: TglUpdateObjectBufferATI;
-  glGetObjectBufferfvATI: TglGetObjectBufferfvATI;
-  glGetObjectBufferivATI: TglGetObjectBufferivATI;
-  glFreeObjectBufferATI: TglFreeObjectBufferATI;
-  glArrayObjectATI: TglArrayObjectATI;
-  glGetArrayObjectfvATI: TglGetArrayObjectfvATI;
-  glGetArrayObjectivATI: TglGetArrayObjectivATI;
-  glVariantArrayObjectATI: TglVariantArrayObjectATI;
-  glGetVariantArrayObjectfvATI: TglGetVariantArrayObjectfvATI;
-  glGetVariantArrayObjectivATI: TglGetVariantArrayObjectivATI;
-  glVertexAttribArrayObjectATI: TglVertexAttribArrayObjectATI;
-  glGetVertexAttribArrayObjectfvATI: TglGetVertexAttribArrayObjectfvATI;
-  glGetVertexAttribArrayObjectivATI: TglGetVertexAttribArrayObjectivATI;
-
-  // GL_ATI_vertex_streams
-  glVertexStream1sATI: TglVertexStream1sATI;
-  glVertexStream1svATI: TglVertexStream1svATI;
-  glVertexStream1iATI: TglVertexStream1iATI;
-  glVertexStream1ivATI: TglVertexStream1ivATI;
-  glVertexStream1fATI: TglVertexStream1fATI;
-  glVertexStream1fvATI: TglVertexStream1fvATI;
-  glVertexStream1dATI: TglVertexStream1dATI;
-  glVertexStream1dvATI: TglVertexStream1dvATI;
-  glVertexStream2sATI: TglVertexStream2sATI;
-  glVertexStream2svATI: TglVertexStream2svATI;
-  glVertexStream2iATI: TglVertexStream2iATI;
-  glVertexStream2ivATI: TglVertexStream2ivATI;
-  glVertexStream2fATI: TglVertexStream2fATI;
-  glVertexStream2fvATI: TglVertexStream2fvATI;
-  glVertexStream2dATI: TglVertexStream2dATI;
-  glVertexStream2dvATI: TglVertexStream2dvATI;
-  glVertexStream3sATI: TglVertexStream3sATI;
-  glVertexStream3svATI: TglVertexStream3svATI;
-  glVertexStream3iATI: TglVertexStream3iATI;
-  glVertexStream3ivATI: TglVertexStream3ivATI;
-  glVertexStream3fATI: TglVertexStream3fATI;
-  glVertexStream3fvATI: TglVertexStream3fvATI;
-  glVertexStream3dATI: TglVertexStream3dATI;
-  glVertexStream3dvATI: TglVertexStream3dvATI;
-  glVertexStream4sATI: TglVertexStream4sATI;
-  glVertexStream4svATI: TglVertexStream4svATI;
-  glVertexStream4iATI: TglVertexStream4iATI;
-  glVertexStream4ivATI: TglVertexStream4ivATI;
-  glVertexStream4fATI: TglVertexStream4fATI;
-  glVertexStream4fvATI: TglVertexStream4fvATI;
-  glVertexStream4dATI: TglVertexStream4dATI;
-  glVertexStream4dvATI: TglVertexStream4dvATI;
-  glNormalStream3bATI: TglNormalStream3bATI;
-  glNormalStream3bvATI: TglNormalStream3bvATI;
-  glNormalStream3sATI: TglNormalStream3sATI;
-  glNormalStream3svATI: TglNormalStream3svATI;
-  glNormalStream3iATI: TglNormalStream3iATI;
-  glNormalStream3ivATI: TglNormalStream3ivATI;
-  glNormalStream3fATI: TglNormalStream3fATI;
-  glNormalStream3fvATI: TglNormalStream3fvATI;
-  glNormalStream3dATI: TglNormalStream3dATI;
-  glNormalStream3dvATI: TglNormalStream3dvATI;
-  glClientActiveVertexStreamATI: TglClientActiveVertexStreamATI;
-  glVertexBlendEnviATI: TglVertexBlendEnviATI;
-  glVertexBlendEnvfATI: TglVertexBlendEnvfATI;
-
-  // GL_AMD_performance_monitor
-  glGetPerfMonitorGroupsAMD: TglGetPerfMonitorGroupsAMD;
-  glGetPerfMonitorCountersAMD: TglGetPerfMonitorCountersAMD;
-  glGetPerfMonitorGroupStringAMD: TglGetPerfMonitorGroupStringAMD;
-  glGetPerfMonitorCounterStringAMD: TglGetPerfMonitorCounterStringAMD;
-  glGetPerfMonitorCounterInfoAMD: TglGetPerfMonitorCounterInfoAMD;
-  glGenPerfMonitorsAMD: TglGenPerfMonitorsAMD;
-  glDeletePerfMonitorsAMD: TglDeletePerfMonitorsAMD;
-  glSelectPerfMonitorCountersAMD: TglSelectPerfMonitorCountersAMD;
-  glBeginPerfMonitorAMD: TglBeginPerfMonitorAMD;
-  glEndPerfMonitorAMD: TglEndPerfMonitorAMD;
-  glGetPerfMonitorCounterDataAMD: TglGetPerfMonitorCounterDataAMD;
-
-  // GL_EXT_blend_color
-  glBlendColorEXT: TglBlendColorEXT;
-
-  // GL_EXT_blend_func_separate
-  glBlendFuncSeparateEXT: TglBlendFuncSeparateEXT;
-
-  // GL_EXT_blend_minmax
-  glBlendEquationEXT: TglBlendEquationEXT;
-
-  // GL_EXT_color_subtable
-  glColorSubTableEXT: TglColorSubTableEXT;
-  glCopyColorSubTableEXT: TglCopyColorSubTableEXT;
-
-  // GL_EXT_compiled_vertex_array
-  glLockArraysEXT: TglLockArraysEXT;
-  glUnlockArraysEXT: TglUnlockArraysEXT;
-
-  // GL_EXT_convolution
-  glConvolutionFilter1DEXT: TglConvolutionFilter1DEXT;
-  glConvolutionFilter2DEXT: TglConvolutionFilter2DEXT;
-  glConvolutionParameterfEXT: TglConvolutionParameterfEXT;
-  glConvolutionParameterfvEXT: TglConvolutionParameterfvEXT;
-  glConvolutionParameteriEXT: TglConvolutionParameteriEXT;
-  glConvolutionParameterivEXT: TglConvolutionParameterivEXT;
-  glCopyConvolutionFilter1DEXT: TglCopyConvolutionFilter1DEXT;
-  glCopyConvolutionFilter2DEXT: TglCopyConvolutionFilter2DEXT;
-  glGetConvolutionFilterEXT: TglGetConvolutionFilterEXT;
-  glGetConvolutionParameterfvEXT: TglGetConvolutionParameterfvEXT;
-  glGetConvolutionParameterivEXT: TglGetConvolutionParameterivEXT;
-  glGetSeparableFilterEXT: TglGetSeparableFilterEXT;
-  glSeparableFilter2DEXT: TglSeparableFilter2DEXT;
-
-  // GL_EXT_coordinate_frame
-  glTangent3bEXT: TglTangent3bEXT;
-  glTangent3bvEXT: TglTangent3bvEXT;
-  glTangent3dEXT: TglTangent3dEXT;
-  glTangent3dvEXT: TglTangent3dvEXT;
-  glTangent3fEXT: TglTangent3fEXT;
-  glTangent3fvEXT: TglTangent3fvEXT;
-  glTangent3iEXT: TglTangent3iEXT;
-  glTangent3ivEXT: TglTangent3ivEXT;
-  glTangent3sEXT: TglTangent3sEXT;
-  glTangent3svEXT: TglTangent3svEXT;
-  glBinormal3bEXT: TglBinormal3bEXT;
-  glBinormal3bvEXT: TglBinormal3bvEXT;
-  glBinormal3dEXT: TglBinormal3dEXT;
-  glBinormal3dvEXT: TglBinormal3dvEXT;
-  glBinormal3fEXT: TglBinormal3fEXT;
-  glBinormal3fvEXT: TglBinormal3fvEXT;
-  glBinormal3iEXT: TglBinormal3iEXT;
-  glBinormal3ivEXT: TglBinormal3ivEXT;
-  glBinormal3sEXT: TglBinormal3sEXT;
-  glBinormal3svEXT: TglBinormal3svEXT;
-  glTangentPointerEXT: TglTangentPointerEXT;
-  glBinormalPointerEXT: TglBinormalPointerEXT;
-
-  // GL_EXT_copy_texture
-  glCopyTexImage1DEXT: TglCopyTexImage1DEXT;
-  glCopyTexImage2DEXT: TglCopyTexImage2DEXT;
-  glCopyTexSubImage1DEXT: TglCopyTexSubImage1DEXT;
-  glCopyTexSubImage2DEXT: TglCopyTexSubImage2DEXT;
-  glCopyTexSubImage3DEXT: TglCopyTexSubImage3DEXT;
-
-  // GL_EXT_cull_vertex
-  glCullParameterdvEXT: TglCullParameterdvEXT;
-  glCullParameterfvEXT: TglCullParameterfvEXT;
-
-  // GL_EXT_draw_range_elements
-  glDrawRangeElementsEXT: TglDrawRangeElementsEXT;
-
-  // GL_EXT_fog_coord
-  glFogCoordfEXT: TglFogCoordfEXT;
-  glFogCoordfvEXT: TglFogCoordfvEXT;
-  glFogCoorddEXT: TglFogCoorddEXT;
-  glFogCoorddvEXT: TglFogCoorddvEXT;
-  glFogCoordPointerEXT: TglFogCoordPointerEXT;
-
-  // GL_EXT_framebuffer_object
-  glIsRenderbufferEXT: TglIsRenderbufferEXT;
-  glBindRenderbufferEXT: TglBindRenderbufferEXT;
-  glDeleteRenderbuffersEXT: TglDeleteRenderbuffersEXT;
-  glGenRenderbuffersEXT: TglGenRenderbuffersEXT;
-  glRenderbufferStorageEXT: TglRenderbufferStorageEXT;
-  glGetRenderbufferParameterivEXT: TglGetRenderbufferParameterivEXT;
-  glIsFramebufferEXT: TglIsFramebufferEXT;
-  glBindFramebufferEXT: TglBindFramebufferEXT;
-  glDeleteFramebuffersEXT: TglDeleteFramebuffersEXT;
-  glGenFramebuffersEXT: TglGenFramebuffersEXT;
-  glCheckFramebufferStatusEXT: TglCheckFramebufferStatusEXT;
-  glFramebufferTexture1DEXT: TglFramebufferTexture1DEXT;
-  glFramebufferTexture2DEXT: TglFramebufferTexture2DEXT;
-  glFramebufferTexture3DEXT: TglFramebufferTexture3DEXT;
-  glFramebufferRenderbufferEXT: TglFramebufferRenderbufferEXT;
-  glGetFramebufferAttachmentParameterivEXT: TglGetFramebufferAttachmentParameterivEXT;
-  glGenerateMipmapEXT: TglGenerateMipmapEXT;
-
-  // GL_EXT_histogram
-  glGetHistogramEXT: TglGetHistogramEXT;
-  glGetHistogramParameterfvEXT: TglGetHistogramParameterfvEXT;
-  glGetHistogramParameterivEXT: TglGetHistogramParameterivEXT;
-  glGetMinmaxEXT: TglGetMinmaxEXT;
-  glGetMinmaxParameterfvEXT: TglGetMinmaxParameterfvEXT;
-  glGetMinmaxParameterivEXT: TglGetMinmaxParameterivEXT;
-  glHistogramEXT: TglHistogramEXT;
-  glMinmaxEXT: TglMinmaxEXT;
-  glResetHistogramEXT: TglResetHistogramEXT;
-  glResetMinmaxEXT: TglResetMinmaxEXT;
-
-  // GL_EXT_index_func
-  glIndexFuncEXT: TglIndexFuncEXT;
-
-  // GL_EXT_index_material
-  glIndexMaterialEXT: TglIndexMaterialEXT;
-
-  // GL_EXT_light_texture
-  glApplyTextureEXT: TglApplyTextureEXT;
-  glTextureLightEXT: TglTextureLightEXT;
-  glTextureMaterialEXT: TglTextureMaterialEXT;
-
-  // GL_EXT_multi_draw_arrays
-  glMultiDrawArraysEXT: TglMultiDrawArraysEXT;
-  glMultiDrawElementsEXT: TglMultiDrawElementsEXT;
-
-  // GL_EXT_multisample
-  glSampleMaskEXT: TglSampleMaskEXT;
-  glSamplePatternEXT: TglSamplePatternEXT;
-
-  // GL_EXT_paletted_texture
-  glColorTableEXT: TglColorTableEXT;
-  glGetColorTableEXT: TglGetColorTableEXT;
-  glGetColorTableParameterivEXT: TglGetColorTableParameterivEXT;
-  glGetColorTableParameterfvEXT: TglGetColorTableParameterfvEXT;
-
-  // GL_EXT_pixel_transform
-  glPixelTransformParameteriEXT: TglPixelTransformParameteriEXT;
-  glPixelTransformParameterfEXT: TglPixelTransformParameterfEXT;
-  glPixelTransformParameterivEXT: TglPixelTransformParameterivEXT;
-  glPixelTransformParameterfvEXT: TglPixelTransformParameterfvEXT;
-
-  // GL_EXT_point_parameters
-  glPointParameterfEXT: TglPointParameterfEXT;
-  glPointParameterfvEXT: TglPointParameterfvEXT;
-
-  // GL_EXT_polygon_offset
-  glPolygonOffsetEXT: TglPolygonOffsetEXT;
-
-  // GL_EXT_secondary_color
-  glSecondaryColor3bEXT: TglSecondaryColor3bEXT;
-  glSecondaryColor3bvEXT: TglSecondaryColor3bvEXT;
-  glSecondaryColor3dEXT: TglSecondaryColor3dEXT;
-  glSecondaryColor3dvEXT: TglSecondaryColor3dvEXT;
-  glSecondaryColor3fEXT: TglSecondaryColor3fEXT;
-  glSecondaryColor3fvEXT: TglSecondaryColor3fvEXT;
-  glSecondaryColor3iEXT: TglSecondaryColor3iEXT;
-  glSecondaryColor3ivEXT: TglSecondaryColor3ivEXT;
-  glSecondaryColor3sEXT: TglSecondaryColor3sEXT;
-  glSecondaryColor3svEXT: TglSecondaryColor3svEXT;
-  glSecondaryColor3ubEXT: TglSecondaryColor3ubEXT;
-  glSecondaryColor3ubvEXT: TglSecondaryColor3ubvEXT;
-  glSecondaryColor3uiEXT: TglSecondaryColor3uiEXT;
-  glSecondaryColor3uivEXT: TglSecondaryColor3uivEXT;
-  glSecondaryColor3usEXT: TglSecondaryColor3usEXT;
-  glSecondaryColor3usvEXT: TglSecondaryColor3usvEXT;
-  glSecondaryColorPointerEXT: TglSecondaryColorPointerEXT;
-
-  // GL_EXT_stencil_two_side
-  glActiveStencilFaceEXT: TglActiveStencilFaceEXT;
-
-  // GL_EXT_subtexture
-  glTexSubImage1DEXT: TglTexSubImage1DEXT;
-  glTexSubImage2DEXT: TglTexSubImage2DEXT;
-
-  // GL_EXT_texture3D
-  glTexImage3DEXT: TglTexImage3DEXT;
-  glTexSubImage3DEXT: TglTexSubImage3DEXT;
-
-  // GL_EXT_texture_object
-  glAreTexturesResidentEXT: TglAreTexturesResidentEXT;
-  glBindTextureEXT: TglBindTextureEXT;
-  glDeleteTexturesEXT: TglDeleteTexturesEXT;
-  glGenTexturesEXT: TglGenTexturesEXT;
-  glIsTextureEXT: TglIsTextureEXT;
-  glPrioritizeTexturesEXT: TglPrioritizeTexturesEXT;
-
-  // GL_EXT_texture_perturb_normal
-  glTextureNormalEXT: TglTextureNormalEXT;
-
-  // GL_EXT_vertex_array
-  glArrayElementEXT: TglArrayElementEXT;
-  glColorPointerEXT: TglColorPointerEXT;
-  glDrawArraysEXT: TglDrawArraysEXT;
-  glEdgeFlagPointerEXT: TglEdgeFlagPointerEXT;
-  glGetPointervEXT: TglGetPointervEXT;
-  glIndexPointerEXT: TglIndexPointerEXT;
-  glNormalPointerEXT: TglNormalPointerEXT;
-  glTexCoordPointerEXT: TglTexCoordPointerEXT;
-  glVertexPointerEXT: TglVertexPointerEXT;
-
-  // GL_EXT_vertex_shader
-  glBeginVertexShaderEXT: TglBeginVertexShaderEXT;
-  glEndVertexShaderEXT: TglEndVertexShaderEXT;
-  glBindVertexShaderEXT: TglBindVertexShaderEXT;
-  glGenVertexShadersEXT: TglGenVertexShadersEXT;
-  glDeleteVertexShaderEXT: TglDeleteVertexShaderEXT;
-  glShaderOp1EXT: TglShaderOp1EXT;
-  glShaderOp2EXT: TglShaderOp2EXT;
-  glShaderOp3EXT: TglShaderOp3EXT;
-  glSwizzleEXT: TglSwizzleEXT;
-  glWriteMaskEXT: TglWriteMaskEXT;
-  glInsertComponentEXT: TglInsertComponentEXT;
-  glExtractComponentEXT: TglExtractComponentEXT;
-  glGenSymbolsEXT: TglGenSymbolsEXT;
-  glSetInvariantEXT: TglSetInvariantEXT;
-  glSetLocalConstantEXT: TglSetLocalConstantEXT;
-  glVariantbvEXT: TglVariantbvEXT;
-  glVariantsvEXT: TglVariantsvEXT;
-  glVariantivEXT: TglVariantivEXT;
-  glVariantfvEXT: TglVariantfvEXT;
-  glVariantdvEXT: TglVariantdvEXT;
-  glVariantubvEXT: TglVariantubvEXT;
-  glVariantusvEXT: TglVariantusvEXT;
-  glVariantuivEXT: TglVariantuivEXT;
-  glVariantPointerEXT: TglVariantPointerEXT;
-  glEnableVariantClientStateEXT: TglEnableVariantClientStateEXT;
-  glDisableVariantClientStateEXT: TglDisableVariantClientStateEXT;
-  glBindLightParameterEXT: TglBindLightParameterEXT;
-  glBindMaterialParameterEXT: TglBindMaterialParameterEXT;
-  glBindTexGenParameterEXT: TglBindTexGenParameterEXT;
-  glBindTextureUnitParameterEXT: TglBindTextureUnitParameterEXT;
-  glBindParameterEXT: TglBindParameterEXT;
-  glIsVariantEnabledEXT: TglIsVariantEnabledEXT;
-  glGetVariantBooleanvEXT: TglGetVariantBooleanvEXT;
-  glGetVariantIntegervEXT: TglGetVariantIntegervEXT;
-  glGetVariantFloatvEXT: TglGetVariantFloatvEXT;
-  glGetVariantPointervEXT: TglGetVariantPointervEXT;
-  glGetInvariantBooleanvEXT: TglGetInvariantBooleanvEXT;
-  glGetInvariantIntegervEXT: TglGetInvariantIntegervEXT;
-  glGetInvariantFloatvEXT: TglGetInvariantFloatvEXT;
-  glGetLocalConstantBooleanvEXT: TglGetLocalConstantBooleanvEXT;
-  glGetLocalConstantIntegervEXT: TglGetLocalConstantIntegervEXT;
-  glGetLocalConstantFloatvEXT: TglGetLocalConstantFloatvEXT;
-
-  // GL_EXT_vertex_weighting
-  glVertexWeightfEXT: TglVertexWeightfEXT;
-  glVertexWeightfvEXT: TglVertexWeightfvEXT;
-  glVertexWeightPointerEXT: TglVertexWeightPointerEXT;
-
-  // GL_EXT_stencil_clear_tag
-  glStencilClearTagEXT: TglStencilClearTagEXT;
-
-  // GL_EXT_framebuffer_blit
-  glBlitFramebufferEXT: TglBlitFramebufferEXT;
-
-  // GL_EXT_framebuffer_multisample
-  glRenderbufferStorageMultisampleEXT: TglRenderbufferStorageMultisampleEXT;
-
-  // GL_EXT_timer_query
-  glGetQueryObjecti64vEXT: TglGetQueryObjecti64vEXT;
-  glGetQueryObjectui64vEXT: TglGetQueryObjectui64vEXT;
-
-  // GL_EXT_gpu_program_parameters
-  glProgramEnvParameters4fvEXT: TglProgramEnvParameters4fvEXT;
-  glProgramLocalParameters4fvEXT: TglProgramLocalParameters4fvEXT;
-
-  // GL_EXT_bindable_uniform
-  glUniformBufferEXT: TglUniformBufferEXT;
-  glGetUniformBufferSizeEXT: TglGetUniformBufferSizeEXT;
-  glGetUniformOffsetEXT: TglGetUniformOffsetEXT;
-
-  // GL_EXT_draw_buffers2
-  glColorMaskIndexedEXT: TglColorMaskIndexedEXT;
-  glGetBooleanIndexedvEXT: TglGetBooleanIndexedvEXT;
-  glGetIntegerIndexedvEXT: TglGetIntegerIndexedvEXT;
-  glEnableIndexedEXT: TglEnableIndexedEXT;
-  glDisableIndexedEXT: TglDisableIndexedEXT;
-  glIsEnabledIndexedEXT: TglIsEnabledIndexedEXT;
-
-  // GL_EXT_draw_instanced
-  glDrawArraysInstancedEXT: TglDrawArraysInstancedEXT;
-  glDrawElementsInstancedEXT: TglDrawElementsInstancedEXT;
-
-  // GL_EXT_geometry_shader4
-  glProgramParameteriEXT: TglProgramParameteriEXT;
-  glFramebufferTextureEXT: TglFramebufferTextureEXT;
-//  glFramebufferTextureLayerEXT: TglFramebufferTextureLayerEXT;
-  glFramebufferTextureFaceEXT: TglFramebufferTextureFaceEXT;
-
-  // GL_EXT_gpu_shader4
-  glVertexAttribI1iEXT: TglVertexAttribI1iEXT;
-  glVertexAttribI2iEXT: TglVertexAttribI2iEXT;
-  glVertexAttribI3iEXT: TglVertexAttribI3iEXT;
-  glVertexAttribI4iEXT: TglVertexAttribI4iEXT;
-  glVertexAttribI1uiEXT: TglVertexAttribI1uiEXT;
-  glVertexAttribI2uiEXT: TglVertexAttribI2uiEXT;
-  glVertexAttribI3uiEXT: TglVertexAttribI3uiEXT;
-  glVertexAttribI4uiEXT: TglVertexAttribI4uiEXT;
-  glVertexAttribI1ivEXT: TglVertexAttribI1ivEXT;
-  glVertexAttribI2ivEXT: TglVertexAttribI2ivEXT;
-  glVertexAttribI3ivEXT: TglVertexAttribI3ivEXT;
-  glVertexAttribI4ivEXT: TglVertexAttribI4ivEXT;
-  glVertexAttribI1uivEXT: TglVertexAttribI1uivEXT;
-  glVertexAttribI2uivEXT: TglVertexAttribI2uivEXT;
-  glVertexAttribI3uivEXT: TglVertexAttribI3uivEXT;
-  glVertexAttribI4uivEXT: TglVertexAttribI4uivEXT;
-  glVertexAttribI4bvEXT:TglVertexAttribI4bvEXT ;
-  glVertexAttribI4svEXT: TglVertexAttribI4svEXT;
-  glVertexAttribI4ubvEXT: TglVertexAttribI4ubvEXT;
-  glVertexAttribI4usvEXT: TglVertexAttribI4usvEXT;
-  glVertexAttribIPointerEXT: TglVertexAttribIPointerEXT;
-  glGetVertexAttribIivEXT: TglGetVertexAttribIivEXT;
-  glGetVertexAttribIuivEXT: TglGetVertexAttribIuivEXT;
-  glUniform1uiEXT: TglUniform1uiEXT;
-  glUniform2uiEXT: TglUniform2uiEXT;
-  glUniform3uiEXT: TglUniform3uiEXT;
-  glUniform4uiEXT: TglUniform4uiEXT;
-  glUniform1uivEXT: TglUniform1uivEXT;
-  glUniform2uivEXT: TglUniform2uivEXT;
-  glUniform3uivEXT: TglUniform3uivEXT;
-  glUniform4uivEXT: TglUniform4uivEXT;
-  glGetUniformuivEXT: TglGetUniformuivEXT;
-  glBindFragDataLocationEXT: TglBindFragDataLocationEXT;
-  glGetFragDataLocationEXT: TglGetFragDataLocationEXT;
-
-  // GL_EXT_texture_array
-  glFramebufferTextureLayerEXT: TglFramebufferTextureLayerEXT;
-
-  // GL_EXT_texture_buffer_object
-  glTexBufferEXT: TglTexBufferEXT;
-
-  // GL_EXT_texture_integer
-  glClearColorIiEXT: TglClearColorIiEXT;
-  glClearColorIuiEXT: TglClearColorIuiEXT;
-  glTexParameterIivEXT: TglTexParameterIivEXT;
-  glTexParameterIuivEXT: TglTexParameterIuivEXT;
-  glGetTexParameterIivEXT: TglGetTexParameterIivEXT;
-  glGetTexParameterIiuvEXT: TglGetTexParameterIiuvEXT;
-
-  // GL_EXT_transform_feedback
-  glBeginTransformFeedbackEXT: TglBeginTransformFeedbackEXT;
-  glEndTransformFeedbackEXT: TglEndTransformFeedbackEXT;
-  glBindBufferRangeEXT: TglBindBufferRangeEXT;
-  glBindBufferOffsetEXT: TglBindBufferOffsetEXT;
-  glBindBufferBaseEXT: TglBindBufferBaseEXT;
-  glTransformFeedbackVaryingsEXT: TglTransformFeedbackVaryingsEXT;
-  glGetTransformFeedbackVaryingEXT: TglGetTransformFeedbackVaryingEXT;
-
-  // GL_EXT_direct_state_access
-  glClientAttribDefaultEXT: TglClientAttribDefaultEXT;
-  glPushClientAttribDefaultEXT: TglPushClientAttribDefaultEXT;
-  glMatrixLoadfEXT: TglMatrixLoadfEXT;
-  glMatrixLoaddEXT: TglMatrixLoaddEXT;
-  glMatrixMultfEXT: TglMatrixMultfEXT;
-  glMatrixMultdEXT: TglMatrixMultdEXT;
-  glMatrixLoadIdentityEXT: TglMatrixLoadIdentityEXT;
-  glMatrixRotatefEXT: TglMatrixRotatefEXT;
-  glMatrixRotatedEXT: TglMatrixRotatedEXT;
-  glMatrixScalefEXT: TglMatrixScalefEXT;
-  glMatrixScaledEXT: TglMatrixScaledEXT;
-  glMatrixTranslatefEXT: TglMatrixTranslatefEXT;
-  glMatrixTranslatedEXT: TglMatrixTranslatedEXT;
-  glMatrixFrustumEXT: TglMatrixFrustumEXT;
-  glMatrixOrthoEXT: TglMatrixOrthoEXT;
-  glMatrixPopEXT: TglMatrixPopEXT;
-  glMatrixPushEXT: TglMatrixPushEXT;
-  glMatrixLoadTransposefEXT: TglMatrixLoadTransposefEXT;
-  glMatrixLoadTransposedEXT: TglMatrixLoadTransposedEXT;
-  glMatrixMultTransposefEXT: TglMatrixMultTransposefEXT;
-  glMatrixMultTransposedEXT: TglMatrixMultTransposedEXT;
-  glTextureParameterfEXT: TglTextureParameterfEXT;
-  glTextureParameterfvEXT: TglTextureParameterfvEXT;
-  glTextureParameteriEXT: TglTextureParameteriEXT;
-  glTextureParameterivEXT: TglTextureParameterivEXT;
-  glTextureImage1DEXT: TglTextureImage1DEXT;
-  glTextureImage2DEXT: TglTextureImage2DEXT;
-  glTextureSubImage1DEXT: TglTextureSubImage1DEXT;
-  glTextureSubImage2DEXT: TglTextureSubImage2DEXT;
-  glCopyTextureImage1DEXT: TglCopyTextureImage1DEXT;
-  glCopyTextureImage2DEXT: TglCopyTextureImage2DEXT;
-  glCopyTextureSubImage1DEXT: TglCopyTextureSubImage1DEXT;
-  glCopyTextureSubImage2DEXT: TglCopyTextureSubImage2DEXT;
-  glGetTextureImageEXT: TglGetTextureImageEXT;
-  glGetTextureParameterfvEXT: TglGetTextureParameterfvEXT;
-  glGetTextureParameterivEXT: TglGetTextureParameterivEXT;
-  glGetTextureLevelParameterfvEXT: TglGetTextureLevelParameterfvEXT;
-  glGetTextureLevelParameterivEXT: TglGetTextureLevelParameterivEXT;
-  glTextureImage3DEXT: TglTextureImage3DEXT;
-  glTextureSubImage3DEXT: TglTextureSubImage3DEXT;
-  glCopyTextureSubImage3DEXT: TglCopyTextureSubImage3DEXT;
-  glMultiTexParameterfEXT: TglMultiTexParameterfEXT;
-  glMultiTexParameterfvEXT: TglMultiTexParameterfvEXT;
-  glMultiTexParameteriEXT: TglMultiTexParameteriEXT;
-  glMultiTexParameterivEXT: TglMultiTexParameterivEXT;
-  glMultiTexImage1DEXT: TglMultiTexImage1DEXT;
-  glMultiTexImage2DEXT: TglMultiTexImage2DEXT;
-  glMultiTexSubImage1DEXT: TglMultiTexSubImage1DEXT;
-  glMultiTexSubImage2DEXT: TglMultiTexSubImage2DEXT;
-  glCopyMultiTexImage1DEXT: TglCopyMultiTexImage1DEXT;
-  glCopyMultiTexImage2DEXT: TglCopyMultiTexImage2DEXT;
-  glCopyMultiTexSubImage1DEXT: TglCopyMultiTexSubImage1DEXT;
-  glCopyMultiTexSubImage2DEXT: TglCopyMultiTexSubImage2DEXT;
-  glGetMultiTexImageEXT: TglGetMultiTexImageEXT;
-  glGetMultiTexParameterfvEXT: TglGetMultiTexParameterfvEXT;
-  glGetMultiTexParameterivEXT: TglGetMultiTexParameterivEXT;
-  glGetMultiTexLevelParameterfvEXT: TglGetMultiTexLevelParameterfvEXT;
-  glGetMultiTexLevelParameterivEXT: TglGetMultiTexLevelParameterivEXT;
-  glMultiTexImage3DEXT: TglMultiTexImage3DEXT;
-  glMultiTexSubImage3DEXT: TglMultiTexSubImage3DEXT;
-  glCopyMultiTexSubImage3DEXT: TglCopyMultiTexSubImage3DEXT;
-  glBindMultiTextureEXT: TglBindMultiTextureEXT;
-  glEnableClientStateIndexedEXT: TglEnableClientStateIndexedEXT;
-  glDisableClientStateIndexedEXT: TglDisableClientStateIndexedEXT;
-  glMultiTexCoordPointerEXT: TglMultiTexCoordPointerEXT;
-  glMultiTexEnvfEXT: TglMultiTexEnvfEXT;
-  glMultiTexEnvfvEXT: TglMultiTexEnvfvEXT;
-  glMultiTexEnviEXT: TglMultiTexEnviEXT;
-  glMultiTexEnvivEXT: TglMultiTexEnvivEXT;
-  glMultiTexGendEXT: TglMultiTexGendEXT;
-  glMultiTexGendvEXT: TglMultiTexGendvEXT;
-  glMultiTexGenfEXT: TglMultiTexGenfEXT;
-  glMultiTexGenfvEXT: TglMultiTexGenfvEXT;
-  glMultiTexGeniEXT: TglMultiTexGeniEXT;
-  glMultiTexGenivEXT: TglMultiTexGenivEXT;
-  glGetMultiTexEnvfvEXT: TglGetMultiTexEnvfvEXT;
-  glGetMultiTexEnvivEXT: TglGetMultiTexEnvivEXT;
-  glGetMultiTexGendvEXT: TglGetMultiTexGendvEXT;
-  glGetMultiTexGenfvEXT: TglGetMultiTexGenfvEXT;
-  glGetMultiTexGenivEXT: TglGetMultiTexGenivEXT;
-  glGetFloatIndexedvEXT: TglGetFloatIndexedvEXT;
-  glGetDoubleIndexedvEXT: TglGetDoubleIndexedvEXT;
-  glGetPointerIndexedvEXT: TglGetPointerIndexedvEXT;
-  glCompressedTextureImage3DEXT: TglCompressedTextureImage3DEXT;
-  glCompressedTextureImage2DEXT: TglCompressedTextureImage2DEXT;
-  glCompressedTextureImage1DEXT: TglCompressedTextureImage1DEXT;
-  glCompressedTextureSubImage3DEXT: TglCompressedTextureSubImage3DEXT;
-  glCompressedTextureSubImage2DEXT: TglCompressedTextureSubImage2DEXT;
-  glCompressedTextureSubImage1DEXT: TglCompressedTextureSubImage1DEXT;
-  glGetCompressedTextureImageEXT: TglGetCompressedTextureImageEXT;
-  glCompressedMultiTexImage3DEXT: TglCompressedMultiTexImage3DEXT;
-  glCompressedMultiTexImage2DEXT: TglCompressedMultiTexImage2DEXT;
-  glCompressedMultiTexImage1DEXT: TglCompressedMultiTexImage1DEXT;
-  glCompressedMultiTexSubImage3DEXT: TglCompressedMultiTexSubImage3DEXT;
-  glCompressedMultiTexSubImage2DEXT: TglCompressedMultiTexSubImage2DEXT;
-  glCompressedMultiTexSubImage1DEXT: TglCompressedMultiTexSubImage1DEXT;
-  glGetCompressedMultiTexImageEXT: TglGetCompressedMultiTexImageEXT;
-  glNamedProgramStringEXT: TglNamedProgramStringEXT;
-  glNamedProgramLocalParameter4dEXT: TglNamedProgramLocalParameter4dEXT;
-  glNamedProgramLocalParameter4dvEXT: TglNamedProgramLocalParameter4dvEXT;
-  glNamedProgramLocalParameter4fEXT: TglNamedProgramLocalParameter4fEXT;
-  glNamedProgramLocalParameter4fvEXT: TglNamedProgramLocalParameter4fvEXT;
-  glGetNamedProgramLocalParameterdvEXT: TglGetNamedProgramLocalParameterdvEXT;
-  glGetNamedProgramLocalParameterfvEXT: TglGetNamedProgramLocalParameterfvEXT;
-  glGetNamedProgramivEXT: TglGetNamedProgramivEXT;
-  glGetNamedProgramStringEXT: TglGetNamedProgramStringEXT;
-  glNamedProgramLocalParameters4fvEXT: TglNamedProgramLocalParameters4fvEXT;
-  glNamedProgramLocalParameterI4iEXT: TglNamedProgramLocalParameterI4iEXT;
-  glNamedProgramLocalParameterI4ivEXT: TglNamedProgramLocalParameterI4ivEXT;
-  glNamedProgramLocalParametersI4ivEXT: TglNamedProgramLocalParametersI4ivEXT;
-  glNamedProgramLocalParameterI4uiEXT: TglNamedProgramLocalParameterI4uiEXT;
-  glNamedProgramLocalParameterI4uivEXT: TglNamedProgramLocalParameterI4uivEXT;
-  glNamedProgramLocalParametersI4uivEXT: TglNamedProgramLocalParametersI4uivEXT;
-  glGetNamedProgramLocalParameterIivEXT: TglGetNamedProgramLocalParameterIivEXT;
-  glGetNamedProgramLocalParameterIuivEXT: TglGetNamedProgramLocalParameterIuivEXT;
-  glTextureParameterIivEXT: TglTextureParameterIivEXT;
-  glTextureParameterIuivEXT: TglTextureParameterIuivEXT;
-  glGetTextureParameterIivEXT: TglGetTextureParameterIivEXT;
-  glGetTextureParameterIuivEXT: TglGetTextureParameterIuivEXT;
-  glMultiTexParameterIivEXT: TglMultiTexParameterIivEXT;
-  glMultiTexParameterIuivEXT: TglMultiTexParameterIuivEXT;
-  glGetMultiTexParameterIivEXT: TglGetMultiTexParameterIivEXT;
-  glGetMultiTexParameterIuivEXT: TglGetMultiTexParameterIuivEXT;
-  glProgramUniform1fEXT: TglProgramUniform1fEXT;
-  glProgramUniform2fEXT: TglProgramUniform2fEXT;
-  glProgramUniform3fEXT: TglProgramUniform3fEXT;
-  glProgramUniform4fEXT: TglProgramUniform4fEXT;
-  glProgramUniform1iEXT: TglProgramUniform1iEXT;
-  glProgramUniform2iEXT: TglProgramUniform2iEXT;
-  glProgramUniform3iEXT: TglProgramUniform3iEXT;
-  glProgramUniform4iEXT: TglProgramUniform4iEXT;
-  glProgramUniform1fvEXT: TglProgramUniform1fvEXT;
-  glProgramUniform2fvEXT: TglProgramUniform2fvEXT;
-  glProgramUniform3fvEXT: TglProgramUniform3fvEXT;
-  glProgramUniform4fvEXT: TglProgramUniform4fvEXT;
-  glProgramUniform1ivEXT: TglProgramUniform1ivEXT;
-  glProgramUniform2ivEXT: TglProgramUniform2ivEXT;
-  glProgramUniform3ivEXT: TglProgramUniform3ivEXT;
-  glProgramUniform4ivEXT: TglProgramUniform4ivEXT;
-  glProgramUniformMatrix2fvEXT: TglProgramUniformMatrix2fvEXT;
-  glProgramUniformMatrix3fvEXT: TglProgramUniformMatrix3fvEXT;
-  glProgramUniformMatrix4fvEXT: TglProgramUniformMatrix4fvEXT;
-  glProgramUniformMatrix2x3fvEXT: TglProgramUniformMatrix2x3fvEXT;
-  glProgramUniformMatrix3x2fvEXT: TglProgramUniformMatrix3x2fvEXT;
-  glProgramUniformMatrix2x4fvEXT: TglProgramUniformMatrix2x4fvEXT;
-  glProgramUniformMatrix4x2fvEXT: TglProgramUniformMatrix4x2fvEXT;
-  glProgramUniformMatrix3x4fvEXT: TglProgramUniformMatrix3x4fvEXT;
-  glProgramUniformMatrix4x3fvEXT: TglProgramUniformMatrix4x3fvEXT;
-  glProgramUniform1uiEXT: TglProgramUniform1uiEXT;
-  glProgramUniform2uiEXT: TglProgramUniform2uiEXT;
-  glProgramUniform3uiEXT: TglProgramUniform3uiEXT;
-  glProgramUniform4uiEXT: TglProgramUniform4uiEXT;
-  glProgramUniform1uivEXT: TglProgramUniform1uivEXT;
-  glProgramUniform2uivEXT: TglProgramUniform2uivEXT;
-  glProgramUniform3uivEXT: TglProgramUniform3uivEXT;
-  glProgramUniform4uivEXT: TglProgramUniform4uivEXT;
-  glNamedBufferDataEXT: TglNamedBufferDataEXT;
-  glNamedBufferSubDataEXT: TglNamedBufferSubDataEXT;
-  glMapNamedBufferEXT: TglMapNamedBufferEXT;
-  glUnmapNamedBufferEXT: TglUnmapNamedBufferEXT;
-  glGetNamedBufferParameterivEXT: TglGetNamedBufferParameterivEXT;
-  glGetNamedBufferPointervEXT: TglGetNamedBufferPointervEXT;
-  glGetNamedBufferSubDataEXT: TglGetNamedBufferSubDataEXT;
-  glTextureBufferEXT: TglTextureBufferEXT;
-  glMultiTexBufferEXT: TglMultiTexBufferEXT;
-  glNamedRenderbufferStorageEXT: TglNamedRenderbufferStorageEXT;
-  glGetNamedRenderbufferParameterivEXT: TglGetNamedRenderbufferParameterivEXT;
-  glCheckNamedFramebufferStatusEXT: TglCheckNamedFramebufferStatusEXT;
-  glNamedFramebufferTexture1DEXT: TglNamedFramebufferTexture1DEXT;
-  glNamedFramebufferTexture2DEXT: TglNamedFramebufferTexture2DEXT;
-  glNamedFramebufferTexture3DEXT: TglNamedFramebufferTexture3DEXT;
-  glNamedFramebufferRenderbufferEXT: TglNamedFramebufferRenderbufferEXT;
-  glGetNamedFramebufferAttachmentParameterivEXT: TglGetNamedFramebufferAttachmentParameterivEXT;
-  glGenerateTextureMipmapEXT: TglGenerateTextureMipmapEXT;
-  glGenerateMultiTexMipmapEXT: TglGenerateMultiTexMipmapEXT;
-  glFramebufferDrawBufferEXT: TglFramebufferDrawBufferEXT;
-  glFramebufferDrawBuffersEXT: TglFramebufferDrawBuffersEXT;
-  glFramebufferReadBufferEXT: TglFramebufferReadBufferEXT;
-  glGetFramebufferParameterivEXT: TglGetFramebufferParameterivEXT;
-  glNamedRenderbufferStorageMultisampleEXT: TglNamedRenderbufferStorageMultisampleEXT;
-  glNamedRenderbufferStorageMultisampleCoverageEXT: TglNamedRenderbufferStorageMultisampleCoverageEXT;
-  glNamedFramebufferTextureEXT: TglNamedFramebufferTextureEXT;
-  glNamedFramebufferTextureLayerEXT: TglNamedFramebufferTextureLayerEXT;
-  glNamedFramebufferTextureFaceEXT: TglNamedFramebufferTextureFaceEXT;
-  glTextureRenderbufferEXT: TglTextureRenderbufferEXT;
-  glMultiTexRenderbufferEXT: TglMultiTexRenderbufferEXT;
-
-  // GL_HP_image_transform
-  glImageTransformParameteriHP: TglImageTransformParameteriHP;
-  glImageTransformParameterfHP: TglImageTransformParameterfHP;
-  glImageTransformParameterivHP: TglImageTransformParameterivHP;
-  glImageTransformParameterfvHP: TglImageTransformParameterfvHP;
-  glGetImageTransformParameterivHP: TglGetImageTransformParameterivHP;
-  glGetImageTransformParameterfvHP: TglGetImageTransformParameterfvHP;
-
-  // GL_EXT_depth_bounds_test
-  glDepthBoundsEXT: TglDepthBoundsEXT;
-
-  // GL_EXT_blend_equation_separate
-  glBlendEquationSeparateEXT: TglBlendEquationSeparateEXT;
-
-  // GL_IBM_multimode_draw_arrays
-  glMultiModeDrawArraysIBM: TglMultiModeDrawArraysIBM;
-  glMultiModeDrawElementsIBM: TglMultiModeDrawElementsIBM;
-
-  // GL_IBM_vertex_array_lists
-  glColorPointerListIBM: TglColorPointerListIBM;
-  glSecondaryColorPointerListIBM: TglSecondaryColorPointerListIBM;
-  glEdgeFlagPointerListIBM: TglEdgeFlagPointerListIBM;
-  glFogCoordPointerListIBM: TglFogCoordPointerListIBM;
-  glIndexPointerListIBM: TglIndexPointerListIBM;
-  glNormalPointerListIBM: TglNormalPointerListIBM;
-  glTexCoordPointerListIBM: TglTexCoordPointerListIBM;
-  glVertexPointerListIBM: TglVertexPointerListIBM;
-
-  // GL_INGR_blend_func_separate
-  glBlendFuncSeparateINGR: TglBlendFuncSeparateINGR;
-
-  // GL_INTEL_parallel_arrays
-  glVertexPointervINTEL: TglVertexPointervINTEL;
-  glNormalPointervINTEL: TglNormalPointervINTEL;
-  glColorPointervINTEL: TglColorPointervINTEL;
-  glTexCoordPointervINTEL: TglTexCoordPointervINTEL;
-
-  // GL_MESA_resize_buffers
-  glResizeBuffersMESA: TglResizeBuffersMESA;
-
-  // GL_MESA_window_pos
-  glWindowPos2dMESA: TglWindowPos2dMESA;
-  glWindowPos2dvMESA: TglWindowPos2dvMESA;
-  glWindowPos2fMESA: TglWindowPos2fMESA;
-  glWindowPos2fvMESA: TglWindowPos2fvMESA;
-  glWindowPos2iMESA: TglWindowPos2iMESA;
-  glWindowPos2ivMESA: TglWindowPos2ivMESA;
-  glWindowPos2sMESA: TglWindowPos2sMESA;
-  glWindowPos2svMESA: TglWindowPos2svMESA;
-  glWindowPos3dMESA: TglWindowPos3dMESA;
-  glWindowPos3dvMESA: TglWindowPos3dvMESA;
-  glWindowPos3fMESA: TglWindowPos3fMESA;
-  glWindowPos3fvMESA: TglWindowPos3fvMESA;
-  glWindowPos3iMESA: TglWindowPos3iMESA;
-  glWindowPos3ivMESA: TglWindowPos3ivMESA;
-  glWindowPos3sMESA: TglWindowPos3sMESA;
-  glWindowPos3svMESA: TglWindowPos3svMESA;
-  glWindowPos4dMESA: TglWindowPos4dMESA;
-  glWindowPos4dvMESA: TglWindowPos4dvMESA;
-  glWindowPos4fMESA: TglWindowPos4fMESA;
-  glWindowPos4fvMESA: TglWindowPos4fvMESA;
-  glWindowPos4iMESA: TglWindowPos4iMESA;
-  glWindowPos4ivMESA: TglWindowPos4ivMESA;
-  glWindowPos4sMESA: TglWindowPos4sMESA;
-  glWindowPos4svMESA: TglWindowPos4svMESA;
-
-  // GL_NV_evaluators
-  glMapControlPointsNV: TglMapControlPointsNV;
-  glMapParameterivNV: TglMapParameterivNV;
-  glMapParameterfvNV: TglMapParameterfvNV;
-  glGetMapControlPointsNV: TglGetMapControlPointsNV;
-  glGetMapParameterivNV: TglGetMapParameterivNV;
-  glGetMapParameterfvNV: TglGetMapParameterfvNV;
-  glGetMapAttribParameterivNV: TglGetMapAttribParameterivNV;
-  glGetMapAttribParameterfvNV: TglGetMapAttribParameterfvNV;
-  glEvalMapsNV: TglEvalMapsNV;
-
-  // GL_NV_fence
-  glDeleteFencesNV: TglDeleteFencesNV;
-  glGenFencesNV: TglGenFencesNV;
-  glIsFenceNV: TglIsFenceNV;
-  glTestFenceNV: TglTestFenceNV;
-  glGetFenceivNV: TglGetFenceivNV;
-  glFinishFenceNV: TglFinishFenceNV;
-  glSetFenceNV: TglSetFenceNV;
-
-  // GL_NV_fragment_program
-  glProgramNamedParameter4fNV: TglProgramNamedParameter4fNV;
-  glProgramNamedParameter4dNV: TglProgramNamedParameter4dNV;
-  glProgramNamedParameter4fvNV: TglProgramNamedParameter4fvNV;
-  glProgramNamedParameter4dvNV: TglProgramNamedParameter4dvNV;
-  glGetProgramNamedParameterfvNV: TglGetProgramNamedParameterfvNV;
-  glGetProgramNamedParameterdvNV: TglGetProgramNamedParameterdvNV;
-
-  // GL_NV_half_float
-  glVertex2hNV: TglVertex2hNV;
-  glVertex2hvNV: TglVertex2hvNV;
-  glVertex3hNV: TglVertex3hNV;
-  glVertex3hvNV: TglVertex3hvNV;
-  glVertex4hNV: TglVertex4hNV;
-  glVertex4hvNV: TglVertex4hvNV;
-  glNormal3hNV: TglNormal3hNV;
-  glNormal3hvNV: TglNormal3hvNV;
-  glColor3hNV: TglColor3hNV;
-  glColor3hvNV: TglColor3hvNV;
-  glColor4hNV: TglColor4hNV;
-  glColor4hvNV: TglColor4hvNV;
-  glTexCoord1hNV: TglTexCoord1hNV;
-  glTexCoord1hvNV: TglTexCoord1hvNV;
-  glTexCoord2hNV: TglTexCoord2hNV;
-  glTexCoord2hvNV: TglTexCoord2hvNV;
-  glTexCoord3hNV: TglTexCoord3hNV;
-  glTexCoord3hvNV: TglTexCoord3hvNV;
-  glTexCoord4hNV: TglTexCoord4hNV;
-  glTexCoord4hvNV: TglTexCoord4hvNV;
-  glMultiTexCoord1hNV: TglMultiTexCoord1hNV;
-  glMultiTexCoord1hvNV: TglMultiTexCoord1hvNV;
-  glMultiTexCoord2hNV: TglMultiTexCoord2hNV;
-  glMultiTexCoord2hvNV: TglMultiTexCoord2hvNV;
-  glMultiTexCoord3hNV: TglMultiTexCoord3hNV;
-  glMultiTexCoord3hvNV: TglMultiTexCoord3hvNV;
-  glMultiTexCoord4hNV: TglMultiTexCoord4hNV;
-  glMultiTexCoord4hvNV: TglMultiTexCoord4hvNV;
-  glFogCoordhNV: TglFogCoordhNV;
-  glFogCoordhvNV: TglFogCoordhvNV;
-  glSecondaryColor3hNV: TglSecondaryColor3hNV;
-  glSecondaryColor3hvNV: TglSecondaryColor3hvNV;
-  glVertexWeighthNV: TglVertexWeighthNV;
-  glVertexWeighthvNV: TglVertexWeighthvNV;
-  glVertexAttrib1hNV: TglVertexAttrib1hNV;
-  glVertexAttrib1hvNV: TglVertexAttrib1hvNV;
-  glVertexAttrib2hNV: TglVertexAttrib2hNV;
-  glVertexAttrib2hvNV: TglVertexAttrib2hvNV;
-  glVertexAttrib3hNV: TglVertexAttrib3hNV;
-  glVertexAttrib3hvNV: TglVertexAttrib3hvNV;
-  glVertexAttrib4hNV: TglVertexAttrib4hNV;
-  glVertexAttrib4hvNV: TglVertexAttrib4hvNV;
-  glVertexAttribs1hvNV: TglVertexAttribs1hvNV;
-  glVertexAttribs2hvNV: TglVertexAttribs2hvNV;
-  glVertexAttribs3hvNV: TglVertexAttribs3hvNV;
-  glVertexAttribs4hvNV: TglVertexAttribs4hvNV;
-
-  // GL_NV_occlusion_query
-  glGenOcclusionQueriesNV: TglGenOcclusionQueriesNV;
-  glDeleteOcclusionQueriesNV: TglDeleteOcclusionQueriesNV;
-  glIsOcclusionQueryNV: TglIsOcclusionQueryNV;
-  glBeginOcclusionQueryNV: TglBeginOcclusionQueryNV;
-  glEndOcclusionQueryNV: TglEndOcclusionQueryNV;
-  glGetOcclusionQueryivNV: TglGetOcclusionQueryivNV;
-  glGetOcclusionQueryuivNV: TglGetOcclusionQueryuivNV;
-
-  // GL_NV_pixel_data_range
-  glPixelDataRangeNV: TglPixelDataRangeNV;
-  glFlushPixelDataRangeNV: TglFlushPixelDataRangeNV;
-
-  // GL_NV_point_sprite
-  glPointParameteriNV: TglPointParameteriNV;
-  glPointParameterivNV: TglPointParameterivNV;
-
-  // GL_NV_primitive_restart
-  glPrimitiveRestartNV: TglPrimitiveRestartNV;
-  glPrimitiveRestartIndexNV: TglPrimitiveRestartIndexNV;
-
-  // GL_NV_register_combiners
-  glCombinerParameterfvNV: TglCombinerParameterfvNV;
-  glCombinerParameterfNV: TglCombinerParameterfNV;
-  glCombinerParameterivNV: TglCombinerParameterivNV;
-  glCombinerParameteriNV: TglCombinerParameteriNV;
-  glCombinerInputNV: TglCombinerInputNV;
-  glCombinerOutputNV: TglCombinerOutputNV;
-  glFinalCombinerInputNV: TglFinalCombinerInputNV;
-  glGetCombinerInputParameterfvNV: TglGetCombinerInputParameterfvNV;
-  glGetCombinerInputParameterivNV: TglGetCombinerInputParameterivNV;
-  glGetCombinerOutputParameterfvNV: TglGetCombinerOutputParameterfvNV;
-  glGetCombinerOutputParameterivNV: TglGetCombinerOutputParameterivNV;
-  glGetFinalCombinerInputParameterfvNV: TglGetFinalCombinerInputParameterfvNV;
-  glGetFinalCombinerInputParameterivNV: TglGetFinalCombinerInputParameterivNV;
-
-  // GL_NV_register_combiners2
-  glCombinerStageParameterfvNV: TglCombinerStageParameterfvNV;
-  glGetCombinerStageParameterfvNV: TglGetCombinerStageParameterfvNV;
-
-  // GL_NV_vertex_array_range
-  glFlushVertexArrayRangeNV: TglFlushVertexArrayRangeNV;
-  glVertexArrayRangeNV: TglVertexArrayRangeNV;
-
-  // GL_NV_vertex_program
-  glAreProgramsResidentNV: TglAreProgramsResidentNV;
-  glBindProgramNV: TglBindProgramNV;
-  glDeleteProgramsNV: TglDeleteProgramsNV;
-  glExecuteProgramNV: TglExecuteProgramNV;
-  glGenProgramsNV: TglGenProgramsNV;
-  glGetProgramParameterdvNV: TglGetProgramParameterdvNV;
-  glGetProgramParameterfvNV: TglGetProgramParameterfvNV;
-  glGetProgramivNV: TglGetProgramivNV;
-  glGetProgramStringNV: TglGetProgramStringNV;
-  glGetTrackMatrixivNV: TglGetTrackMatrixivNV;
-  glGetVertexAttribdvNV: TglGetVertexAttribdvNV;
-  glGetVertexAttribfvNV: TglGetVertexAttribfvNV;
-  glGetVertexAttribivNV: TglGetVertexAttribivNV;
-  glGetVertexAttribPointervNV: TglGetVertexAttribPointervNV;
-  glIsProgramNV: TglIsProgramNV;
-  glLoadProgramNV: TglLoadProgramNV;
-  glProgramParameter4dNV: TglProgramParameter4dNV;
-  glProgramParameter4dvNV: TglProgramParameter4dvNV;
-  glProgramParameter4fNV: TglProgramParameter4fNV;
-  glProgramParameter4fvNV: TglProgramParameter4fvNV;
-  glProgramParameters4dvNV: TglProgramParameters4dvNV;
-  glProgramParameters4fvNV: TglProgramParameters4fvNV;
-  glRequestResidentProgramsNV: TglRequestResidentProgramsNV;
-  glTrackMatrixNV: TglTrackMatrixNV;
-  glVertexAttribPointerNV: TglVertexAttribPointerNV;
-  glVertexAttrib1dNV: TglVertexAttrib1dNV;
-  glVertexAttrib1dvNV: TglVertexAttrib1dvNV;
-  glVertexAttrib1fNV: TglVertexAttrib1fNV;
-  glVertexAttrib1fvNV: TglVertexAttrib1fvNV;
-  glVertexAttrib1sNV: TglVertexAttrib1sNV;
-  glVertexAttrib1svNV: TglVertexAttrib1svNV;
-  glVertexAttrib2dNV: TglVertexAttrib2dNV;
-  glVertexAttrib2dvNV: TglVertexAttrib2dvNV;
-  glVertexAttrib2fNV: TglVertexAttrib2fNV;
-  glVertexAttrib2fvNV: TglVertexAttrib2fvNV;
-  glVertexAttrib2sNV: TglVertexAttrib2sNV;
-  glVertexAttrib2svNV: TglVertexAttrib2svNV;
-  glVertexAttrib3dNV: TglVertexAttrib3dNV;
-  glVertexAttrib3dvNV: TglVertexAttrib3dvNV;
-  glVertexAttrib3fNV: TglVertexAttrib3fNV;
-  glVertexAttrib3fvNV: TglVertexAttrib3fvNV;
-  glVertexAttrib3sNV: TglVertexAttrib3sNV;
-  glVertexAttrib3svNV: TglVertexAttrib3svNV;
-  glVertexAttrib4dNV: TglVertexAttrib4dNV;
-  glVertexAttrib4dvNV: TglVertexAttrib4dvNV;
-  glVertexAttrib4fNV: TglVertexAttrib4fNV;
-  glVertexAttrib4fvNV: TglVertexAttrib4fvNV;
-  glVertexAttrib4sNV: TglVertexAttrib4sNV;
-  glVertexAttrib4svNV: TglVertexAttrib4svNV;
-  glVertexAttrib4ubNV: TglVertexAttrib4ubNV;
-  glVertexAttrib4ubvNV: TglVertexAttrib4ubvNV;
-  glVertexAttribs1dvNV: TglVertexAttribs1dvNV;
-  glVertexAttribs1fvNV: TglVertexAttribs1fvNV;
-  glVertexAttribs1svNV: TglVertexAttribs1svNV;
-  glVertexAttribs2dvNV: TglVertexAttribs2dvNV;
-  glVertexAttribs2fvNV: TglVertexAttribs2fvNV;
-  glVertexAttribs2svNV: TglVertexAttribs2svNV;
-  glVertexAttribs3dvNV: TglVertexAttribs3dvNV;
-  glVertexAttribs3fvNV: TglVertexAttribs3fvNV;
-  glVertexAttribs3svNV: TglVertexAttribs3svNV;
-  glVertexAttribs4dvNV: TglVertexAttribs4dvNV;
-  glVertexAttribs4fvNV: TglVertexAttribs4fvNV;
-  glVertexAttribs4svNV: TglVertexAttribs4svNV;
-  glVertexAttribs4ubvNV: TglVertexAttribs4ubvNV;
-
-  // GL_NV_depth_buffer_float
-  glDepthRangedNV: TglDepthRangedNV;
-  glClearDepthdNV: TglClearDepthdNV;
-  glDepthBoundsdNV: TglDepthBoundsdNV;
-
-  // GL_NV_framebuffer_multisample_coverage
-  glRenderbufferStorageMultsampleCoverageNV: TglRenderbufferStorageMultsampleCoverageNV;
-
-  // GL_NV_geometry_program4
-  glProgramVertexLimitNV: TglProgramVertexLimitNV;
-
-  // GL_NV_gpu_program4
-  glProgramLocalParameterI4iNV: TglProgramLocalParameterI4iNV;
-  glProgramLocalParameterI4ivNV: TglProgramLocalParameterI4ivNV;
-  glProgramLocalParametersI4ivNV: TglProgramLocalParametersI4ivNV;
-  glProgramLocalParameterI4uiNV: TglProgramLocalParameterI4uiNV;
-  glProgramLocalParameterI4uivNV: TglProgramLocalParameterI4uivNV;
-  glProgramLocalParametersI4uivNV: TglProgramLocalParametersI4uivNV;
-  glProgramEnvParameterI4iNV: TglProgramEnvParameterI4iNV;
-  glProgramEnvParameterI4ivNV: TglProgramEnvParameterI4ivNV;
-  glProgramEnvParametersI4ivNV: TglProgramEnvParametersI4ivNV;
-  glProgramEnvParameterI4uiNV: TglProgramEnvParameterI4uiNV;
-  glProgramEnvParameterI4uivNV: TglProgramEnvParameterI4uivNV;
-  glProgramEnvParametersI4uivNV: TglProgramEnvParametersI4uivNV;
-  glGetProgramLocalParameterIivNV: TglGetProgramLocalParameterIivNV;
-  glGetProgramLocalParameterIuivNV: TglGetProgramLocalParameterIuivNV;
-  glGetProgramEnvParameterIivNV: TglGetProgramEnvParameterIivNV;
-  glGetProgramEnvParameterIuivNV: TglGetProgramEnvParameterIuivNV;
-
-  // GL_NV_parameter_buffer_object
-  glProgramBufferParametersfvNV: TglProgramBufferParametersfvNV;
-  glProgramBufferParametersIivNV: TglProgramBufferParametersIivNV;
-  glProgramBufferParametersIuivNV: TglProgramBufferParametersIuivNV;
-
-  // GL_NV_transform_feedback
-  glBeginTransformFeedbackNV: TglBeginTransformFeedbackNV;
-  glEndTransformFeedbackNV: TglEndTransformFeedbackNV;
-  glTransformFeedbackAttribsNV: TglTransformFeedbackAttribsNV;
-  glBindBufferRangeNV: TglBindBufferRangeNV;
-  glBindBufferOffsetNV: TglBindBufferOffsetNV;
-  glBindBufferBaseNV: TglBindBufferBaseNV;
-  glTransformFeedbackVaryingsNV: TglTransformFeedbackVaryingsNV;
-  glActiveVaryingNV: TglActiveVaryingNV;
-  glGetVaryingLocationNV: TglGetVaryingLocationNV;
-  glGetActiveVaryingNV: TglGetActiveVaryingNV;
-  glGetTransformFeedbackVaryingNV: TglGetTransformFeedbackVaryingNV;
-
-  // GL_NV_conditional_render
-  glBeginConditionalRenderNV: TglBeginConditionalRenderNV;
-  glEndConditionalRenderNV: TglEndConditionalRenderNV;
-
-  // GL_NV_present_video
-  glPresentFrameKeyedNV: TglPresentFrameKeyedNV;
-  glPresentFrameDualFillNV: TglPresentFrameDualFillNV;
-  glGetVideoivNV: TglGetVideoivNV;
-  glGetVideouivNV: TglGetVideouivNV;
-  glGetVideoi64vNV: TglGetVideoi64vNV;
-  glGetVideoui64vNV: TglGetVideoui64vNV;
-//  glVideoParameterivNV: TglVideoParameterivNV;
-
-  // GL_NV_explicit_multisample
-  glGetMultisamplefvNV: TglGetMultisamplefvNV;
-  glSampleMaskIndexedNV: TglSampleMaskIndexedNV;
-  glTexRenderbufferNV: TglTexRenderbufferNV;
-
-  // GL_NV_transform_feedback2
-  glBindTransformFeedbackNV: TglBindTransformFeedbackNV;
-  glDeleteTransformFeedbacksNV: TglDeleteTransformFeedbacksNV;
-  glGenTransformFeedbacksNV: TglGenTransformFeedbacksNV;
-  glIsTransformFeedbackNV: TglIsTransformFeedbackNV;
-  glPauseTransformFeedbackNV: TglPauseTransformFeedbackNV;
-  glResumeTransformFeedbackNV: TglResumeTransformFeedbackNV;
-  glDrawTransformFeedbackNV: TglDrawTransformFeedbackNV;
-
-  // GL_PGI_misc_hints
-  glHintPGI: TglHintPGI;
-
-  // GL_SGIS_detail_texture
-  glDetailTexFuncSGIS: TglDetailTexFuncSGIS;
-  glGetDetailTexFuncSGIS: TglGetDetailTexFuncSGIS;
-
-  // GL_SGIS_fog_function
-  glFogFuncSGIS: TglFogFuncSGIS;
-  glGetFogFuncSGIS: TglGetFogFuncSGIS;
-
-  // GL_SGIS_multisample
-  glSampleMaskSGIS: TglSampleMaskSGIS;
-  glSamplePatternSGIS: TglSamplePatternSGIS;
-
-  // GL_SGIS_pixel_texture
-  glPixelTexGenParameteriSGIS: TglPixelTexGenParameteriSGIS;
-  glPixelTexGenParameterivSGIS: TglPixelTexGenParameterivSGIS;
-  glPixelTexGenParameterfSGIS: TglPixelTexGenParameterfSGIS;
-  glPixelTexGenParameterfvSGIS: TglPixelTexGenParameterfvSGIS;
-  glGetPixelTexGenParameterivSGIS: TglGetPixelTexGenParameterivSGIS;
-  glGetPixelTexGenParameterfvSGIS: TglGetPixelTexGenParameterfvSGIS;
-
-  // GL_SGIS_point_parameters
-  glPointParameterfSGIS: TglPointParameterfSGIS;
-  glPointParameterfvSGIS: TglPointParameterfvSGIS;
-
-  // GL_SGIS_sharpen_texture
-  glSharpenTexFuncSGIS: TglSharpenTexFuncSGIS;
-  glGetSharpenTexFuncSGIS: TglGetSharpenTexFuncSGIS;
-
-  // GL_SGIS_texture4D
-  glTexImage4DSGIS: TglTexImage4DSGIS;
-  glTexSubImage4DSGIS: TglTexSubImage4DSGIS;
-
-  // GL_SGIS_texture_color_mask
-  glTextureColorMaskSGIS: TglTextureColorMaskSGIS;
-
-  // GL_SGIS_texture_filter4
-  glGetTexFilterFuncSGIS: TglGetTexFilterFuncSGIS;
-  glTexFilterFuncSGIS: TglTexFilterFuncSGIS;
-
-  // GL_SGIX_async
-  glAsyncMarkerSGIX: TglAsyncMarkerSGIX;
-  glFinishAsyncSGIX: TglFinishAsyncSGIX;
-  glPollAsyncSGIX: TglPollAsyncSGIX;
-  glGenAsyncMarkersSGIX: TglGenAsyncMarkersSGIX;
-  glDeleteAsyncMarkersSGIX: TglDeleteAsyncMarkersSGIX;
-  glIsAsyncMarkerSGIX: TglIsAsyncMarkerSGIX;
-
-  // GL_SGIX_flush_raster
-  glFlushRasterSGIX: TglFlushRasterSGIX;
-
-  // GL_SGIX_fragment_lighting
-  glFragmentColorMaterialSGIX: TglFragmentColorMaterialSGIX;
-  glFragmentLightfSGIX: TglFragmentLightfSGIX;
-  glFragmentLightfvSGIX: TglFragmentLightfvSGIX;
-  glFragmentLightiSGIX: TglFragmentLightiSGIX;
-  glFragmentLightivSGIX: TglFragmentLightivSGIX;
-  glFragmentLightModelfSGIX: TglFragmentLightModelfSGIX;
-  glFragmentLightModelfvSGIX: TglFragmentLightModelfvSGIX;
-  glFragmentLightModeliSGIX: TglFragmentLightModeliSGIX;
-  glFragmentLightModelivSGIX: TglFragmentLightModelivSGIX;
-  glFragmentMaterialfSGIX: TglFragmentMaterialfSGIX;
-  glFragmentMaterialfvSGIX: TglFragmentMaterialfvSGIX;
-  glFragmentMaterialiSGIX: TglFragmentMaterialiSGIX;
-  glFragmentMaterialivSGIX: TglFragmentMaterialivSGIX;
-  glGetFragmentLightfvSGIX: TglGetFragmentLightfvSGIX;
-  glGetFragmentLightivSGIX: TglGetFragmentLightivSGIX;
-  glGetFragmentMaterialfvSGIX: TglGetFragmentMaterialfvSGIX;
-  glGetFragmentMaterialivSGIX: TglGetFragmentMaterialivSGIX;
-  glLightEnviSGIX: TglLightEnviSGIX;
-
-  // GL_SGIX_framezoom
-  glFrameZoomSGIX: TglFrameZoomSGIX;
-
-  // GL_SGIX_igloo_interface
-  glIglooInterfaceSGIX: TglIglooInterfaceSGIX;
-
-  // GL_SGIX_instruments
-  glGetInstrumentsSGIX: TglGetInstrumentsSGIX;
-  glInstrumentsBufferSGIX: TglInstrumentsBufferSGIX;
-  glPollInstrumentsSGIX: TglPollInstrumentsSGIX;
-  glReadInstrumentsSGIX: TglReadInstrumentsSGIX;
-  glStartInstrumentsSGIX: TglStartInstrumentsSGIX;
-  glStopInstrumentsSGIX: TglStopInstrumentsSGIX;
-
-  // GL_SGIX_list_priority
-  glGetListParameterfvSGIX: TglGetListParameterfvSGIX;
-  glGetListParameterivSGIX: TglGetListParameterivSGIX;
-  glListParameterfSGIX: TglListParameterfSGIX;
-  glListParameterfvSGIX: TglListParameterfvSGIX;
-  glListParameteriSGIX: TglListParameteriSGIX;
-  glListParameterivSGIX: TglListParameterivSGIX;
-
-  // GL_SGIX_pixel_texture
-  glPixelTexGenSGIX: TglPixelTexGenSGIX;
-
-  // GL_SGIX_polynomial_ffd
-  glDeformationMap3dSGIX: TglDeformationMap3dSGIX;
-  glDeformationMap3fSGIX: TglDeformationMap3fSGIX;
-  glDeformSGIX: TglDeformSGIX;
-  glLoadIdentityDeformationMapSGIX: TglLoadIdentityDeformationMapSGIX;
-
-  // GL_SGIX_reference_plane
-  glReferencePlaneSGIX: TglReferencePlaneSGIX;
-
-  // GL_SGIX_sprite
-  glSpriteParameterfSGIX: TglSpriteParameterfSGIX;
-  glSpriteParameterfvSGIX: TglSpriteParameterfvSGIX;
-  glSpriteParameteriSGIX: TglSpriteParameteriSGIX;
-  glSpriteParameterivSGIX: TglSpriteParameterivSGIX;
-
-  // GL_SGIX_tag_sample_buffer
-  glTagSampleBufferSGIX: TglTagSampleBufferSGIX;
-
-  // GL_SGI_color_table
-  glColorTableSGI: TglColorTableSGI;
-  glColorTableParameterfvSGI: TglColorTableParameterfvSGI;
-  glColorTableParameterivSGI: TglColorTableParameterivSGI;
-  glCopyColorTableSGI: TglCopyColorTableSGI;
-  glGetColorTableSGI: TglGetColorTableSGI;
-  glGetColorTableParameterfvSGI: TglGetColorTableParameterfvSGI;
-  glGetColorTableParameterivSGI: TglGetColorTableParameterivSGI;
-
-  // GL_SUNX_constant_data
-  glFinishTextureSUNX: TglFinishTextureSUNX;
-
-  // GL_SUN_global_alpha
-  glGlobalAlphaFactorbSUN: TglGlobalAlphaFactorbSUN;
-  glGlobalAlphaFactorsSUN: TglGlobalAlphaFactorsSUN;
-  glGlobalAlphaFactoriSUN: TglGlobalAlphaFactoriSUN;
-  glGlobalAlphaFactorfSUN: TglGlobalAlphaFactorfSUN;
-  glGlobalAlphaFactordSUN: TglGlobalAlphaFactordSUN;
-  glGlobalAlphaFactorubSUN: TglGlobalAlphaFactorubSUN;
-  glGlobalAlphaFactorusSUN: TglGlobalAlphaFactorusSUN;
-  glGlobalAlphaFactoruiSUN: TglGlobalAlphaFactoruiSUN;
-
-  // GL_SUN_mesh_array
-  glDrawMeshArraysSUN: TglDrawMeshArraysSUN;
-
-  // GL_SUN_triangle_list
-  glReplacementCodeuiSUN: TglReplacementCodeuiSUN;
-  glReplacementCodeusSUN: TglReplacementCodeusSUN;
-  glReplacementCodeubSUN: TglReplacementCodeubSUN;
-  glReplacementCodeuivSUN: TglReplacementCodeuivSUN;
-  glReplacementCodeusvSUN: TglReplacementCodeusvSUN;
-  glReplacementCodeubvSUN: TglReplacementCodeubvSUN;
-  glReplacementCodePointerSUN: TglReplacementCodePointerSUN;
-
-  // GL_SUN_vertex
-  glColor4ubVertex2fSUN: TglColor4ubVertex2fSUN;
-  glColor4ubVertex2fvSUN: TglColor4ubVertex2fvSUN;
-  glColor4ubVertex3fSUN: TglColor4ubVertex3fSUN;
-  glColor4ubVertex3fvSUN: TglColor4ubVertex3fvSUN;
-  glColor3fVertex3fSUN: TglColor3fVertex3fSUN;
-  glColor3fVertex3fvSUN: TglColor3fVertex3fvSUN;
-  glNormal3fVertex3fSUN: TglNormal3fVertex3fSUN;
-  glNormal3fVertex3fvSUN: TglNormal3fVertex3fvSUN;
-  glColor4fNormal3fVertex3fSUN: TglColor4fNormal3fVertex3fSUN;
-  glColor4fNormal3fVertex3fvSUN: TglColor4fNormal3fVertex3fvSUN;
-  glTexCoord2fVertex3fSUN: TglTexCoord2fVertex3fSUN;
-  glTexCoord2fVertex3fvSUN: TglTexCoord2fVertex3fvSUN;
-  glTexCoord4fVertex4fSUN: TglTexCoord4fVertex4fSUN;
-  glTexCoord4fVertex4fvSUN: TglTexCoord4fVertex4fvSUN;
-  glTexCoord2fColor4ubVertex3fSUN: TglTexCoord2fColor4ubVertex3fSUN;
-  glTexCoord2fColor4ubVertex3fvSUN: TglTexCoord2fColor4ubVertex3fvSUN;
-  glTexCoord2fColor3fVertex3fSUN: TglTexCoord2fColor3fVertex3fSUN;
-  glTexCoord2fColor3fVertex3fvSUN: TglTexCoord2fColor3fVertex3fvSUN;
-  glTexCoord2fNormal3fVertex3fSUN: TglTexCoord2fNormal3fVertex3fSUN;
-  glTexCoord2fNormal3fVertex3fvSUN: TglTexCoord2fNormal3fVertex3fvSUN;
-  glTexCoord2fColor4fNormal3fVertex3fSUN: TglTexCoord2fColor4fNormal3fVertex3fSUN;
-  glTexCoord2fColor4fNormal3fVertex3fvSUN: TglTexCoord2fColor4fNormal3fVertex3fvSUN;
-  glTexCoord4fColor4fNormal3fVertex4fSUN: TglTexCoord4fColor4fNormal3fVertex4fSUN;
-  glTexCoord4fColor4fNormal3fVertex4fvSUN: TglTexCoord4fColor4fNormal3fVertex4fvSUN;
-  glReplacementCodeuiVertex3fSUN: TglReplacementCodeuiVertex3fSUN;
-  glReplacementCodeuiVertex3fvSUN: TglReplacementCodeuiVertex3fvSUN;
-  glReplacementCodeuiColor4ubVertex3fSUN: TglReplacementCodeuiColor4ubVertex3fSUN;
-  glReplacementCodeuiColor4ubVertex3fvSUN: TglReplacementCodeuiColor4ubVertex3fvSUN;
-  glReplacementCodeuiColor3fVertex3fSUN: TglReplacementCodeuiColor3fVertex3fSUN;
-  glReplacementCodeuiColor3fVertex3fvSUN: TglReplacementCodeuiColor3fVertex3fvSUN;
-  glReplacementCodeuiNormal3fVertex3fSUN: TglReplacementCodeuiNormal3fVertex3fSUN;
-  glReplacementCodeuiNormal3fVertex3fvSUN: TglReplacementCodeuiNormal3fVertex3fvSUN;
-  glReplacementCodeuiColor4fNormal3fVertex3fSUN: TglReplacementCodeuiColor4fNormal3fVertex3fSUN;
-  glReplacementCodeuiColor4fNormal3fVertex3fvSUN: TglReplacementCodeuiColor4fNormal3fVertex3fvSUN;
-  glReplacementCodeuiTexCoord2fVertex3fSUN: TglReplacementCodeuiTexCoord2fVertex3fSUN;
-  glReplacementCodeuiTexCoord2fVertex3fvSUN: TglReplacementCodeuiTexCoord2fVertex3fvSUN;
-  glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN: TglReplacementCodeuiTexCoord2fNormal3fVertex3fSUN;
-  glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN: TglReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN;
-  glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN: TglReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN;
-  glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN: TglReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN;
-
-{$IFDEF DGL_WIN}
-  wglGetProcAddress: TwglGetProcAddress;
-  wglCopyContext: TwglCopyContext;
-  wglCreateContext: TwglCreateContext;
-  wglCreateLayerContext: TwglCreateLayerContext;
-  wglDeleteContext: TwglDeleteContext;
-  wglDescribeLayerPlane: TwglDescribeLayerPlane;
-  wglGetCurrentContext: TwglGetCurrentContext;
-  wglGetCurrentDC: TwglGetCurrentDC;
-  wglGetLayerPaletteEntries: TwglGetLayerPaletteEntries;
-  wglMakeCurrent: TwglMakeCurrent;
-  wglRealizeLayerPalette: TwglRealizeLayerPalette;
-  wglSetLayerPaletteEntries: TwglSetLayerPaletteEntries;
-  wglShareLists: TwglShareLists;
-  wglSwapLayerBuffers: TwglSwapLayerBuffers;
-  wglSwapMultipleBuffers: TwglSwapMultipleBuffers;
-  wglUseFontBitmapsA: TwglUseFontBitmapsA;
-  wglUseFontOutlinesA: TwglUseFontOutlinesA;
-  wglUseFontBitmapsW: TwglUseFontBitmapsW;
-  wglUseFontOutlinesW: TwglUseFontOutlinesW;
-  wglUseFontBitmaps: TwglUseFontBitmaps;
-  wglUseFontOutlines: TwglUseFontOutlines;
-
-   // WGL_ARB_buffer_region
-  wglCreateBufferRegionARB: TwglCreateBufferRegionARB;
-  wglDeleteBufferRegionARB: TwglDeleteBufferRegionARB;
-  wglSaveBufferRegionARB: TwglSaveBufferRegionARB;
-  wglRestoreBufferRegionARB: TwglRestoreBufferRegionARB;
-
-  // WGL_ARB_extensions_string
-  wglGetExtensionsStringARB: TwglGetExtensionsStringARB;
-
-  // WGL_ARB_make_current_read
-  wglMakeContextCurrentARB: TwglMakeContextCurrentARB;
-  wglGetCurrentReadDCARB: TwglGetCurrentReadDCARB;
-
-  // WGL_ARB_pbuffer
-  wglCreatePbufferARB: TwglCreatePbufferARB;
-  wglGetPbufferDCARB: TwglGetPbufferDCARB;
-  wglReleasePbufferDCARB: TwglReleasePbufferDCARB;
-  wglDestroyPbufferARB: TwglDestroyPbufferARB;
-  wglQueryPbufferARB: TwglQueryPbufferARB;
-
-  // WGL_ARB_pixel_format
-  wglGetPixelFormatAttribivARB: TwglGetPixelFormatAttribivARB;
-  wglGetPixelFormatAttribfvARB: TwglGetPixelFormatAttribfvARB;
-  wglChoosePixelFormatARB: TwglChoosePixelFormatARB;
-  // WGL_ARB_color_buffer_float
-  wglClampColorARB: TwglClampColorARB;
-
-  // WGL_ARB_render_texture
-  wglBindTexImageARB: TwglBindTexImageARB;
-  wglReleaseTexImageARB: TwglReleaseTexImageARB;
-  wglSetPbufferAttribARB: TwglSetPbufferAttribARB;
-
-  // WGL_ARB_create_context
-  wglCreateContextAttribsARB: TwglCreateContextAttribsARB;
-
-  // WGL_AMD_gpu_association
-  wglGetGPUIDsAMD: TwglGetGPUIDsAMD;
-  wglGetGPUInfoAMD: TwglGetGPUInfoAMD;
-  wglGetContextGPUIDAMD: TwglGetContextGPUIDAMD;
-  wglCreateAssociatedContextAMD: TwglCreateAssociatedContextAMD;
-  wglCreateAssociatedContextAttribsAMD: TwglCreateAssociatedContextAttribsAMD;
-  wglDeleteAssociatedContextAMD: TwglDeleteAssociatedContextAMD;
-  wglMakeAssociatedContextCurrentAMD: TwglMakeAssociatedContextCurrentAMD;
-  wglGetCurrentAssociatedContextAMD: TwglGetCurrentAssociatedContextAMD;
-  wglBlitContextFramebufferAMD: TwglBlitContextFramebufferAMD;
-
-  // WGL_EXT_display_color_table
-  wglCreateDisplayColorTableEXT: TwglCreateDisplayColorTableEXT;
-  wglLoadDisplayColorTableEXT: TwglLoadDisplayColorTableEXT;
-  wglBindDisplayColorTableEXT: TwglBindDisplayColorTableEXT;
-  wglDestroyDisplayColorTableEXT: TwglDestroyDisplayColorTableEXT;
-
-  // WGL_EXT_extensions_string
-  wglGetExtensionsStringEXT: TwglGetExtensionsStringEXT;
-
-  // WGL_EXT_make_current_read
-  wglMakeContextCurrentEXT: TwglMakeContextCurrentEXT;
-  wglGetCurrentReadDCEXT: TwglGetCurrentReadDCEXT;
-
-  // WGL_EXT_pbuffer
-  wglCreatePbufferEXT: TwglCreatePbufferEXT;
-  wglGetPbufferDCEXT: TwglGetPbufferDCEXT;
-  wglReleasePbufferDCEXT: TwglReleasePbufferDCEXT;
-  wglDestroyPbufferEXT: TwglDestroyPbufferEXT;
-  wglQueryPbufferEXT: TwglQueryPbufferEXT;
-
-  // WGL_EXT_pixel_format
-  wglGetPixelFormatAttribivEXT: TwglGetPixelFormatAttribivEXT;
-  wglGetPixelFormatAttribfvEXT: TwglGetPixelFormatAttribfvEXT;
-  wglChoosePixelFormatEXT: TwglChoosePixelFormatEXT;
-
-  // WGL_EXT_swap_control
-  wglSwapIntervalEXT: TwglSwapIntervalEXT;
-  wglGetSwapIntervalEXT: TwglGetSwapIntervalEXT;
-
-  // WGL_I3D_digital_video_control
-  wglGetDigitalVideoParametersI3D: TwglGetDigitalVideoParametersI3D;
-  wglSetDigitalVideoParametersI3D: TwglSetDigitalVideoParametersI3D;
-
-  // WGL_I3D_gamma
-  wglGetGammaTableParametersI3D: TwglGetGammaTableParametersI3D;
-  wglSetGammaTableParametersI3D: TwglSetGammaTableParametersI3D;
-  wglGetGammaTableI3D: TwglGetGammaTableI3D;
-  wglSetGammaTableI3D: TwglSetGammaTableI3D;
-
-  // WGL_I3D_genlock
-  wglEnableGenlockI3D: TwglEnableGenlockI3D;
-  wglDisableGenlockI3D: TwglDisableGenlockI3D;
-  wglIsEnabledGenlockI3D: TwglIsEnabledGenlockI3D;
-  wglGenlockSourceI3D: TwglGenlockSourceI3D;
-  wglGetGenlockSourceI3D: TwglGetGenlockSourceI3D;
-  wglGenlockSourceEdgeI3D: TwglGenlockSourceEdgeI3D;
-  wglGetGenlockSourceEdgeI3D: TwglGetGenlockSourceEdgeI3D;
-  wglGenlockSampleRateI3D: TwglGenlockSampleRateI3D;
-  wglGetGenlockSampleRateI3D: TwglGetGenlockSampleRateI3D;
-  wglGenlockSourceDelayI3D: TwglGenlockSourceDelayI3D;
-  wglGetGenlockSourceDelayI3D: TwglGetGenlockSourceDelayI3D;
-  wglQueryGenlockMaxSourceDelayI3D: TwglQueryGenlockMaxSourceDelayI3D;
-
-  // WGL_I3D_image_buffer
-  wglCreateImageBufferI3D: TwglCreateImageBufferI3D;
-  wglDestroyImageBufferI3D: TwglDestroyImageBufferI3D;
-  wglAssociateImageBufferEventsI3D: TwglAssociateImageBufferEventsI3D;
-  wglReleaseImageBufferEventsI3D: TwglReleaseImageBufferEventsI3D;
-
-  // WGL_I3D_swap_frame_lock
-  wglEnableFrameLockI3D: TwglEnableFrameLockI3D;
-  wglDisableFrameLockI3D: TwglDisableFrameLockI3D;
-  wglIsEnabledFrameLockI3D: TwglIsEnabledFrameLockI3D;
-  wglQueryFrameLockMasterI3D: TwglQueryFrameLockMasterI3D;
-
-  // WGL_I3D_swap_frame_usage
-  wglGetFrameUsageI3D: TwglGetFrameUsageI3D;
-  wglBeginFrameTrackingI3D: TwglBeginFrameTrackingI3D;
-  wglEndFrameTrackingI3D: TwglEndFrameTrackingI3D;
-  wglQueryFrameTrackingI3D: TwglQueryFrameTrackingI3D;
-
-  // WGL_NV_vertex_array_range
-  wglAllocateMemoryNV: TwglAllocateMemoryNV;
-  wglFreeMemoryNV: TwglFreeMemoryNV;
-
-  // WGL_NV_present_video
-  wglEnumerateVideoDevicesNV: TwglEnumerateVideoDevicesNV;
-  wglBindVideoDeviceNV: TwglBindVideoDeviceNV;
-  wglQueryCurrentContextNV: TwglQueryCurrentContextNV;
-
-  // WGL_NV_video_out
-  wglGetVideoDeviceNV: TwglGetVideoDeviceNV;
-  wglReleaseVideoDeviceNV: TwglReleaseVideoDeviceNV;
-  wglBindVideoImageNV: TwglBindVideoImageNV;
-  wglReleaseVideoImageNV: TwglReleaseVideoImageNV;
-  wglSendPbufferToVideoNV: TwglSendPbufferToVideoNV;
-  wglGetVideoInfoNV: TwglGetVideoInfoNV;
-
-  // WGL_NV_swap_group
-  wglJoinSwapGroupNV: TwglJoinSwapGroupNV;
-  wglBindSwapBarrierNV: TwglBindSwapBarrierNV;
-  wglQuerySwapGroupNV: TwglQuerySwapGroupNV;
-  wglQueryMaxSwapGroupsNV: TwglQueryMaxSwapGroupsNV;
-  wglQueryFrameCountNV: TwglQueryFrameCountNV;
-  wglResetFrameCountNV: TwglResetFrameCountNV;
-
-  // WGL_NV_gpu_affinity
-  wglEnumGpusNV: TwglEnumGpusNV;
-  wglEnumGpuDevicesNV: TwglEnumGpuDevicesNV;
-  wglCreateAffinityDCNV: TwglCreateAffinityDCNV;
-  wglEnumGpusFromAffinityDCNV: TwglEnumGpusFromAffinityDCNV;
-  wglDeleteDCNV: TwglDeleteDCNV;
-
-  // WGL_OML_sync_control
-  wglGetSyncValuesOML: TwglGetSyncValuesOML;
-  wglGetMscRateOML: TwglGetMscRateOML;
-  wglSwapBuffersMscOML: TwglSwapBuffersMscOML;
-  wglSwapLayerBuffersMscOML: TwglSwapLayerBuffersMscOML;
-  wglWaitForMscOML: TwglWaitForMscOML;
-  wglWaitForSbcOML: TwglWaitForSbcOML;
-
-  // WGL_3DL_stereo_control
-  wglSetStereoEmitterState3DL: TwglSetStereoEmitterState3DL;
-
-  // WIN_draw_range_elements
-  glDrawRangeElementsWIN: TglDrawRangeElementsWIN;
-
-  // WIN_swap_hint
-  glAddSwapHintRectWIN: TglAddSwapHintRectWIN;
-{$ENDIF}
-
-{$IFDEF DGL_LINUX}
-  glXChooseVisual: TglXChooseVisual;
-  glXCopyContext: TglXCopyContext;
-  glXCreateContext: TglXCreateContext;
-  glXCreateGLXPixmap: TglXCreateGLXPixmap;
-  glXDestroyContext: TglXDestroyContext;
-  glXDestroyGLXPixmap: TglXDestroyGLXPixmap;
-  glXGetConfig: TglXGetConfig;
-  glXGetCurrentContext: TglXGetCurrentContext;
-  glXGetCurrentDrawable: TglXGetCurrentDrawable;
-  glXIsDirect: TglXIsDirect;
-  glXMakeCurrent: TglXMakeCurrent;
-  glXQueryExtension: TglXQueryExtension;
-  glXQueryVersion: TglXQueryVersion;
-  glXSwapBuffers: TglXSwapBuffers;
-  glXUseXFont: TglXUseXFont;
-  glXWaitGL: TglXWaitGL;
-  glXWaitX: TglXWaitX;
-
-  glXGetClientString: TglXGetClientString;
-  glXQueryServerString: TglXQueryServerString;
-  glXQueryExtensionsString: TglXQueryExtensionsString;
-
-  // GLX_VERSION_1_3
-  glXGetFBConfigs: TglXGetFBConfigs;
-  glXChooseFBConfig: TglXChooseFBConfig;
-  glXGetFBConfigAttrib: TglXGetFBConfigAttrib;
-  glXGetVisualFromFBConfig: TglXGetVisualFromFBConfig;
-  glXCreateWindow: TglXCreateWindow;
-  glXDestroyWindow: TglXDestroyWindow;
-  glXCreatePixmap: TglXCreatePixmap;
-
-  glXDestroyPixmap: TglXDestroyPixmap;
-  glXCreatePbuffer: TglXCreatePbuffer;
-  glXDestroyPbuffer: TglXDestroyPbuffer;
-  glXQueryDrawable: TglXQueryDrawable;
-  glXCreateNewContext: TglXCreateNewContext;
-  glXMakeContextCurrent: TglXMakeContextCurrent;
-  glXGetCurrentReadDrawable: TglXGetCurrentReadDrawable;
-  glXGetCurreentDisplay: TglXGetCurreentDisplay;
-
-  glXQueryContext: TglXQueryContext;
-  glXSelectEvent: TglXSelectEvent;
-  glXGetSelectedEvent: TglXGetSelectedEvent;
-
-  // GLX_VERSION_1_4
-  glXGetProcAddress: TglXGetProcAddress;
-
-  // GLX_ARB_get_proc_address
-  glXGetProcAddressARB: TglXGetProcAddressARB;
-
-  // GLX_ARB_create_context
-  glXCreateContextAttribsARB: TglXCreateContextAttribsARB;
-  
-  // GLX_EXT_import_context
-  glXGetCurrentDisplayEXT: TglXGetCurrentDisplayEXT;
-  glXQueryContextInfoEXT: TglXQueryContextInfoEXT;
-  glXGetContextIDEXT: TglXGetContextIDEXT;
-  glXImportContextEXT: TglXImportContextEXT;
-  glXFreeContextEXT: TglXFreeContextEXT;
-  
-  // GLX_EXT_texture_from_pixmap
-  glXBindTexImageEXT: TglXBindTexImageEXT;
-  glXReleaseTexImageEXT: TglXReleaseTexImageEXT;
-{$ENDIF}
-
-  // GL utility functions and procedures
-  gluErrorString: TgluErrorString;
-  gluGetString: TgluGetString;
-  gluOrtho2D: TgluOrtho2D;
-  gluPerspective: TgluPerspective;
-  gluPickMatrix: TgluPickMatrix;
-  gluLookAt: TgluLookAt;
-  gluProject: TgluProject;
-  gluUnProject: TgluUnProject;
-  gluScaleImage: TgluScaleImage;
-  gluBuild1DMipmaps: TgluBuild1DMipmaps;
-  gluBuild2DMipmaps: TgluBuild2DMipmaps;
-  gluNewQuadric: TgluNewQuadric;
-  gluDeleteQuadric: TgluDeleteQuadric;
-  gluQuadricNormals: TgluQuadricNormals;
-  gluQuadricTexture: TgluQuadricTexture;
-  gluQuadricOrientation: TgluQuadricOrientation;
-  gluQuadricDrawStyle: TgluQuadricDrawStyle;
-  gluCylinder: TgluCylinder;
-  gluDisk: TgluDisk;
-  gluPartialDisk: TgluPartialDisk;
-  gluSphere: TgluSphere;
-  gluQuadricCallback: TgluQuadricCallback;
-  gluNewTess: TgluNewTess;
-  gluDeleteTess: TgluDeleteTess;
-  gluTessBeginPolygon: TgluTessBeginPolygon;
-  gluTessBeginContour: TgluTessBeginContour;
-  gluTessVertex: TgluTessVertex;
-  gluTessEndContour: TgluTessEndContour;
-  gluTessEndPolygon: TgluTessEndPolygon;
-  gluTessProperty: TgluTessProperty;
-  gluTessNormal: TgluTessNormal;
-  gluTessCallback: TgluTessCallback;
-  gluGetTessProperty: TgluGetTessProperty;
-  gluNewNurbsRenderer: TgluNewNurbsRenderer;
-  gluDeleteNurbsRenderer: TgluDeleteNurbsRenderer;
-  gluBeginSurface: TgluBeginSurface;
-  gluBeginCurve: TgluBeginCurve;
-  gluEndCurve: TgluEndCurve;
-  gluEndSurface: TgluEndSurface;
-  gluBeginTrim: TgluBeginTrim;
-  gluEndTrim: TgluEndTrim;
-  gluPwlCurve: TgluPwlCurve;
-  gluNurbsCurve: TgluNurbsCurve;
-  gluNurbsSurface: TgluNurbsSurface;
-  gluLoadSamplingMatrices: TgluLoadSamplingMatrices;
-  gluNurbsProperty: TgluNurbsProperty;
-  gluGetNurbsProperty: TgluGetNurbsProperty;
-  gluNurbsCallback: TgluNurbsCallback;
-  gluBeginPolygon: TgluBeginPolygon;
-  gluNextContour: TgluNextContour;
-  gluEndPolygon: TgluEndPolygon;
-
-
-type
-  TRCOptions = set of (opDoubleBuffered, opGDI, opStereo);
-
-var
-  GL_LibHandle: Pointer = nil;
-  GLU_LibHandle: Pointer = nil;
-
-  LastPixelFormat: Integer;
-  ExtensionsRead: Boolean;
-  ImplementationRead: Boolean;
-
-
-const
-{$IFDEF DGL_WIN}
-  OPENGL_LIBNAME = 'OpenGL32.dll';
-  GLU_LIBNAME = 'GLU32.dll';
-{$ELSE}
-  {$IFDEF darwin}
-    OPENGL_LIBNAME = 'libGL.dylib';
-    GLU_LIBNAME = 'libGLU.dylib';
-  {$ELSE}
-    OPENGL_LIBNAME = 'libGL.so.1';
-    GLU_LIBNAME = 'libGLU.so.1';
-  {$ENDIF}
-{$ENDIF}
-
-function InitOpenGL(LibName: String = OPENGL_LIBNAME; GLULibName: String = GLU_LIBNAME): Boolean;
-
-function dglGetProcAddress(ProcName: PAnsiChar; LibHandle: Pointer = nil): Pointer;
-function dglCheckExtension(Extension: AnsiString): Boolean;
-
-procedure ReadExtensions;
-procedure ReadImplementationProperties;
-
-// =============================================================================
-// Helper-Functions
-// =============================================================================
-{$IFDEF DGL_WIN}
-  function CreateRenderingContext(DC: HDC; Options: TRCOptions; ColorBits, ZBits, StencilBits, AccumBits, AuxBuffers: Integer; Layer: Integer): HGLRC;
-  procedure DestroyRenderingContext(RC: HGLRC);
-
-  procedure ActivateRenderingContext(DC: HDC; RC: HGLRC; loadext: boolean = true);
-  procedure DeactivateRenderingContext;
-{$ENDIF}
-
-
-procedure ReadOpenGLCore;
-procedure Read_GL_3DFX_tbuffer;
-procedure Read_GL_APPLE_element_array;
-procedure Read_GL_APPLE_fence;
-procedure Read_GL_APPLE_vertex_array_object;
-procedure Read_GL_APPLE_vertex_array_range;
-procedure Read_GL_APPLE_texture_range;
-procedure Read_GL_APPLE_vertex_program_evaluators;
-procedure Read_GL_APPLE_object_purgeable;
-procedure Read_GL_ARB_matrix_palette;
-procedure Read_GL_ARB_multitexture;
-procedure Read_GL_ARB_point_parameters;
-procedure Read_GL_ARB_texture_compression;
-procedure Read_GL_ARB_transpose_matrix;
-procedure Read_GL_ARB_vertex_blend;
-procedure Read_GL_ARB_vertex_buffer_object;
-procedure Read_GL_ARB_vertex_program;
-procedure Read_GL_ARB_window_pos;
-procedure Read_GL_ARB_color_buffer_float;
-procedure Read_GL_ARB_Shader_Objects;
-procedure Read_GL_ARB_occlusion_query;
-procedure Read_GL_ARB_draw_instanced;
-procedure Read_GL_ARB_framebuffer_object;
-procedure Read_GL_ARB_geometry_shader4;
-procedure Read_GL_ARB_instanced_arrays;
-procedure Read_GL_ARB_map_buffer_range;
-procedure Read_GL_ARB_texture_buffer_object;
-procedure Read_GL_ARB_vertex_array_object;
-procedure Read_GL_ARB_uniform_buffer_object;
-procedure Read_GL_ARB_copy_buffer;
-procedure Read_GL_ARB_draw_elements_base_vertex;
-procedure Read_GL_ARB_provoking_vertex;
-procedure Read_GL_ARB_sync;
-procedure Read_GL_ARB_texture_multisample;
-procedure Read_GL_ARB_draw_buffers_blend;
-procedure Read_GL_ARB_sample_shading;
-procedure Read_GL_ATI_draw_buffers;
-procedure Read_GL_ATI_element_array;
-procedure Read_GL_ATI_envmap_bumpmap;
-procedure Read_GL_ATI_fragment_shader;
-procedure Read_GL_ATI_map_object_buffer;
-procedure Read_GL_ATI_pn_triangles;
-procedure Read_GL_ATI_separate_stencil;
-procedure Read_GL_ATI_vertex_array_object;
-procedure Read_GL_ATI_vertex_attrib_array_object;
-procedure Read_GL_ATI_vertex_streams;
-procedure Read_GL_AMD_performance_monitor;
-procedure Read_GL_EXT_blend_color;
-procedure Read_GL_EXT_blend_func_separate;
-procedure Read_GL_EXT_blend_minmax;
-procedure Read_GL_EXT_color_subtable;
-procedure Read_GL_EXT_compiled_vertex_array;
-procedure Read_GL_EXT_convolution;
-procedure Read_GL_EXT_coordinate_frame;
-procedure Read_GL_EXT_copy_texture;
-procedure Read_GL_EXT_cull_vertex;
-procedure Read_GL_EXT_draw_range_elements;
-procedure Read_GL_EXT_fog_coord;
-procedure Read_GL_EXT_framebuffer_object;
-procedure Read_GL_EXT_histogram;
-procedure Read_GL_EXT_index_func;
-procedure Read_GL_EXT_index_material;
-procedure Read_GL_EXT_multi_draw_arrays;
-procedure Read_GL_EXT_multisample;
-procedure Read_GL_EXT_paletted_texture;
-procedure Read_GL_EXT_pixel_transform;
-procedure Read_GL_EXT_point_parameters;
-procedure Read_GL_EXT_polygon_offset;
-procedure Read_GL_EXT_secondary_color;
-procedure Read_GL_EXT_stencil_two_side;
-procedure Read_GL_EXT_subtexture;
-procedure Read_GL_EXT_texture3D;
-procedure Read_GL_EXT_texture_object;
-procedure Read_GL_EXT_texture_perturb_normal;
-procedure Read_GL_EXT_vertex_array;
-procedure Read_GL_EXT_vertex_shader;
-procedure Read_GL_EXT_vertex_weighting;
-procedure Read_GL_EXT_depth_bounds_test;
-procedure Read_GL_EXT_blend_equation_separate;
-procedure Read_GL_EXT_stencil_clear_tag;
-procedure Read_GL_EXT_framebuffer_blit;
-procedure Read_GL_EXT_framebuffer_multisample;
-procedure Read_GL_EXT_timer_query;
-procedure Read_GL_EXT_gpu_program_parameters;
-procedure Read_GL_EXT_bindable_uniform;
-procedure Read_GL_EXT_draw_buffers2;
-procedure Read_GL_EXT_draw_instanced;
-procedure Read_GL_EXT_geometry_shader4;
-procedure Read_GL_EXT_gpu_shader4;
-procedure Read_GL_EXT_texture_array;
-procedure Read_GL_EXT_texture_buffer_object;
-procedure Read_GL_EXT_texture_integer;
-procedure Read_GL_EXT_transform_feedback;
-procedure Read_GL_EXT_direct_state_access;
-procedure Read_GL_HP_image_transform;
-procedure Read_GL_IBM_multimode_draw_arrays;
-procedure Read_GL_IBM_vertex_array_lists;
-procedure Read_GL_INGR_blend_func_separate;
-procedure Read_GL_INTEL_parallel_arrays;
-procedure Read_GL_MESA_resize_buffers;
-procedure Read_GL_MESA_window_pos;
-procedure Read_GL_NV_evaluators;
-procedure Read_GL_NV_fence;
-procedure Read_GL_NV_fragment_program;
-procedure Read_GL_NV_half_float;
-procedure Read_GL_NV_occlusion_query;
-procedure Read_GL_NV_pixel_data_range;
-procedure Read_GL_NV_point_sprite;
-procedure Read_GL_NV_primitive_restart;
-procedure Read_GL_NV_register_combiners;
-procedure Read_GL_NV_register_combiners2;
-procedure Read_GL_NV_vertex_array_range;
-procedure Read_GL_NV_vertex_program;
-procedure Read_GL_NV_depth_buffer_float;
-procedure Read_GL_NV_framebuffer_multisample_coverage;
-procedure Read_GL_NV_geometry_program4;
-procedure Read_GL_NV_gpu_program4;
-procedure Read_GL_NV_parameter_buffer_object;
-procedure Read_GL_NV_transform_feedback;
-procedure Read_GL_NV_conditional_render;
-procedure Read_GL_NV_present_video;
-procedure Read_GL_NV_explicit_multisample;
-procedure Read_GL_NV_transform_feedback2;
-procedure Read_GL_PGI_misc_hints;
-procedure Read_GL_SGIS_detail_texture;
-procedure Read_GL_SGIS_fog_function;
-procedure Read_GL_SGIS_multisample;
-procedure Read_GL_SGIS_pixel_texture;
-procedure Read_GL_SGIS_point_parameters;
-procedure Read_GL_SGIS_sharpen_texture;
-procedure Read_GL_SGIS_texture4D;
-procedure Read_GL_SGIS_texture_color_mask;
-procedure Read_GL_SGIS_texture_filter4;
-procedure Read_GL_SGIX_async;
-procedure Read_GL_SGIX_flush_raster;
-procedure Read_GL_SGIX_fragment_lighting;
-procedure Read_GL_SGIX_framezoom;
-procedure Read_GL_SGIX_igloo_interface;
-procedure Read_GL_SGIX_instruments;
-procedure Read_GL_SGIX_list_priority;
-procedure Read_GL_SGIX_pixel_texture;
-procedure Read_GL_SGIX_polynomial_ffd;
-procedure Read_GL_SGIX_reference_plane;
-procedure Read_GL_SGIX_sprite;
-procedure Read_GL_SGIX_tag_sample_buffer;
-procedure Read_GL_SGI_color_table;
-procedure Read_GL_SUNX_constant_data;
-procedure Read_GL_SUN_global_alpha;
-procedure Read_GL_SUN_mesh_array;
-procedure Read_GL_SUN_triangle_list;
-procedure Read_GL_SUN_vertex;
-
-{$IFDEF DGL_WIN}
-procedure Read_WGL_ARB_buffer_region;
-procedure Read_WGL_ARB_extensions_string;
-procedure Read_WGL_ARB_make_current_read;
-procedure Read_WGL_ARB_pbuffer;
-procedure Read_WGL_ARB_pixel_format;
-procedure Read_WGL_ARB_pixel_format_float;
-procedure Read_WGL_ARB_render_texture;
-procedure Read_WGL_ARB_create_context;
-procedure Read_WGL_AMD_gpu_association;
-procedure Read_WGL_EXT_display_color_table;
-procedure Read_WGL_EXT_extensions_string;
-procedure Read_WGL_EXT_make_current_read;
-procedure Read_WGL_EXT_pbuffer;
-procedure Read_WGL_EXT_pixel_format;
-procedure Read_WGL_EXT_swap_control;
-procedure Read_WGL_I3D_digital_video_control;
-procedure Read_WGL_I3D_gamma;
-procedure Read_WGL_I3D_genlock;
-procedure Read_WGL_I3D_image_buffer;
-procedure Read_WGL_I3D_swap_frame_lock;
-procedure Read_WGL_I3D_swap_frame_usage;
-procedure Read_WGL_NV_vertex_array_range;
-procedure Read_WGL_NV_present_video;
-procedure Read_WGL_NV_video_out;
-procedure Read_WGL_NV_swap_group;
-procedure Read_WGL_NV_gpu_affinity;
-procedure Read_WGL_OML_sync_control;
-procedure Read_WGL_3DL_stereo_control;
-
-procedure Read_WIN_draw_range_elements;
-procedure Read_WIN_swap_hint;
-{$ENDIF}
-
-
-implementation
-
-
-{$IFDEF DGL_LINUX}
-const
-  RTLD_LAZY = $001;
-  RTLD_NOW = $002;
-  RTLD_BINDING_MASK = $003;
-
-  // Seems to work on Debian / Fedora
-  LibraryLib = {$IFDEF Linux} 'libdl.so.2'{$ELSE} 'c'{$ENDIF};
-
-function dlopen(Name: PAnsiChar; Flags: LongInt): Pointer; cdecl; external LibraryLib name 'dlopen';
-function dlclose(Lib: Pointer): LongInt; cdecl; external LibraryLib name 'dlclose';
-
-function dlsym(Lib: Pointer; Name: PAnsiChar): Pointer; cdecl; external LibraryLib name 'dlsym';
-{$ENDIF}
-
-
-function dglLoadLibrary(Name: PChar): Pointer;
-begin
-  {$IFDEF DGL_WIN}
-  Result := Pointer(LoadLibrary(Name));
-  {$ENDIF}
-
-  {$IFDEF DGL_LINUX}
-  Result := dlopen(Name, RTLD_LAZY);
-  {$ENDIF}
-end;
-
-
-function dglFreeLibrary(LibHandle: Pointer): Boolean;
-begin
-  if LibHandle = nil then
-    Result := False
-  else
-    {$IFDEF DGL_WIN}
-    Result := FreeLibrary(HMODULE(LibHandle));
-    {$ENDIF}
-
-    {$IFDEF DGL_LINUX}
-    Result := dlclose(LibHandle) = 0;
-    {$ENDIF}
-end;
-
-
-function dglGetProcAddress(ProcName: PAnsiChar; LibHandle: Pointer = nil): Pointer;
-begin
-  if LibHandle = nil then
-    LibHandle := GL_LibHandle;
-
-  {$IFDEF DGL_WIN}
-  Result := GetProcAddress(HMODULE(LibHandle), ProcName);
-  {$ENDIF}
-
-  {$IFDEF DGL_LINUX}
-  Result := dlsym(LibHandle, ProcName);
-  {$ENDIF}
-
-  if result <> nil then
-    exit;
-
-  {$IFDEF DGL_WIN}
-    if Addr(wglGetProcAddress) <> nil then
-      Result := wglGetProcAddress(ProcName);
-  {$ENDIF}
-
-  {$IFDEF DGL_LINUX}
-    if Addr(glXGetProcAddress) <> nil then
-      Result := glXGetProcAddress(ProcName);
-
-    if result <> nil then
-      exit;
-
-    if Addr(glXGetProcAddressARB) <> nil then
-      Result := glXGetProcAddressARB(ProcName);
-  {$ENDIF}
-end;
-
-
-function Int_GetExtensionString: AnsiString;
-begin
-  // generel extension string
-  if not Assigned(@glGetString) then
-    glGetString := dglGetProcAddress('glGetString');
-
-  if Assigned(@glGetString) then
-    Result := glGetString(GL_EXTENSIONS)
-  else
-    Result := '';
-
-  if (GL_LibHandle <> nil) then begin
-    {$IFDEF DGL_WIN}
-      // wglGetExtensionsStringEXT
-      if not Assigned(@wglGetExtensionsStringEXT) then
-        wglGetExtensionsStringEXT := dglGetProcAddress('wglGetExtensionsStringEXT');
-
-      if Assigned(@wglGetExtensionsStringEXT) then
-        Result := Result + #32 + wglGetExtensionsStringEXT;
-
-      // wglGetExtensionsStringARB
-      if not Assigned(@wglGetExtensionsStringARB) then
-        wglGetExtensionsStringARB := dglGetProcAddress('wglGetExtensionsStringARB');
-
-      if Assigned(@wglGetExtensionsStringARB) then
-        Result := Result + #32 + wglGetExtensionsStringARB(wglGetCurrentDC);
-    {$ENDIF}
-  end;
-
-  Result := #32 + Result + #32;
-end;
-
-
-function Int_CheckExtension(AllExtensions, CheckExtension: AnsiString): Boolean;
-begin
-  Result := Pos(#32 + CheckExtension + #32, AllExtensions) > 0;
-end;
-
-
-function dglCheckExtension(Extension: AnsiString): Boolean;
-var
-  Extensions: AnsiString;
-begin
-  Extensions := Int_GetExtensionString;
-  Result := Int_CheckExtension(Extensions, Extension);
-end;
-
-
-
-function InitOpenGL(LibName: String; GLULibName: String): Boolean;
-begin
-  Result := False;
-
-  // free opened libraries
-  if GL_LibHandle <> nil then
-    dglFreeLibrary(GL_LibHandle);
-
-  if GLU_LibHandle <> nil then
-    dglFreeLibrary(GLU_LibHandle);
-
-  // load library
-  GL_LibHandle := dglLoadLibrary(PChar(LibName));
-  GLU_LibHandle := dglLoadLibrary(PChar(GLULibName));
-
-  // load GL functions
-  if (GL_LibHandle <> nil) then begin
-    {$IFDEF DGL_WIN}
-      wglCopyContext := dglGetProcAddress('wglCopyContext');
-      wglCreateLayerContext := dglGetProcAddress('wglCreateLayerContext');
-      wglCreateContext := dglGetProcAddress('wglCreateContext');
-      wglDeleteContext := dglGetProcAddress('wglDeleteContext');
-      wglDescribeLayerPlane := dglGetProcAddress('wglDescribeLayerPlane');
-      wglGetCurrentContext := dglGetProcAddress('wglGetCurrentContext');
-      wglGetCurrentDC := dglGetProcAddress('wglGetCurrentDC');
-      wglGetLayerPaletteEntries := dglGetProcAddress('wglGetLayerPaletteEntries');
-      wglGetProcAddress := dglGetProcAddress('wglGetProcAddress');
-      wglMakeCurrent := dglGetProcAddress('wglMakeCurrent');
-      wglRealizeLayerPalette := dglGetProcAddress('wglRealizeLayerPalette');
-      wglSetLayerPaletteEntries := dglGetProcAddress('wglSetLayerPaletteEntries');
-      wglShareLists := dglGetProcAddress('wglShareLists');
-      wglSwapLayerBuffers := dglGetProcAddress('wglSwapLayerBuffers');
-      wglSwapMultipleBuffers := dglGetProcAddress('wglSwapMultipleBuffers');
-      wglUseFontBitmapsA := dglGetProcAddress('wglUseFontBitmapsA');
-      wglUseFontOutlinesA := dglGetProcAddress('wglUseFontOutlinesA');
-      wglUseFontBitmapsW := dglGetProcAddress('wglUseFontBitmapsW');
-      wglUseFontOutlinesW := dglGetProcAddress('wglUseFontOutlinesW');
-      wglUseFontBitmaps := dglGetProcAddress('wglUseFontBitmapsA');
-      wglUseFontOutlines := dglGetProcAddress('wglUseFontOutlinesA');
-    {$ENDIF}
-
-    {$IFDEF DGL_LINUX}
-      glXChooseVisual := dglGetProcAddress('glXChooseVisual');
-      glXCopyContext := dglGetProcAddress('glXCopyContext');
-      glXCreateContext := dglGetProcAddress('glXCreateContext');
-      glXCreateGLXPixmap := dglGetProcAddress('glXCreateGLXPixmap');
-      glXDestroyContext := dglGetProcAddress('glXDestroyContext');
-      glXDestroyGLXPixmap := dglGetProcAddress('glXDestroyGLXPixmap');
-      glXGetConfig := dglGetProcAddress('glXGetConfig');
-      glXGetCurrentContext := dglGetProcAddress('glXGetCurrentContext');
-      glXGetCurrentDrawable := dglGetProcAddress('glXGetCurrentDrawable');
-      glXIsDirect := dglGetProcAddress('glXIsDirect');
-      glXMakeCurrent := dglGetProcAddress('glXMakeCurrent');
-      glXQueryExtension := dglGetProcAddress('glXQueryExtension');
-      glXQueryVersion := dglGetProcAddress('glXQueryVersion');
-      glXSwapBuffers := dglGetProcAddress('glXSwapBuffers');
-      glXUseXFont := dglGetProcAddress('glXUseXFont');
-      glXWaitGL := dglGetProcAddress('glXWaitGL');
-      glXWaitX := dglGetProcAddress('glXWaitX');
-
-      glXGetClientString := dglGetProcAddress('glXGetClientString');
-      glXQueryServerString := dglGetProcAddress('glXQueryServerString');
-      glXQueryExtensionsString := dglGetProcAddress('glXQueryExtensionsString');
-
-      // GLX_VERSION_1_3
-      glXGetFBConfigs := dglGetProcAddress('glXGetFBConfigs');
-      glXChooseFBConfig := dglGetProcAddress('glXChooseFBConfig');
-      glXGetFBConfigAttrib := dglGetProcAddress('glXGetFBConfigAttrib');
-      glXGetVisualFromFBConfig := dglGetProcAddress('glXGetVisualFromFBConfig');
-      glXCreateWindow := dglGetProcAddress('glXCreateWindow');
-      glXDestroyWindow := dglGetProcAddress('glXDestroyWindow');
-      glXCreatePixmap := dglGetProcAddress('glXCreatePixmap');
-
-      glXDestroyPixmap := dglGetProcAddress('glXDestroyPixmap');
-      glXCreatePbuffer := dglGetProcAddress('glXCreatePbuffer');
-      glXDestroyPbuffer := dglGetProcAddress('glXDestroyPbuffer');
-      glXQueryDrawable := dglGetProcAddress('glXQueryDrawable');
-      glXCreateNewContext := dglGetProcAddress('glXCreateNewContext');
-      glXMakeContextCurrent := dglGetProcAddress('glXMakeContextCurrent');
-      glXGetCurrentReadDrawable := dglGetProcAddress('glXGetCurrentReadDrawable');
-      glXGetCurreentDisplay := dglGetProcAddress('glXGetCurreentDisplay');
-
-      glXQueryContext := dglGetProcAddress('glXQueryContext');
-      glXSelectEvent := dglGetProcAddress('glXSelectEvent');
-      glXGetSelectedEvent := dglGetProcAddress('glXGetSelectedEvent');
-
-      // GLX_VERSION_1_4
-      glXGetProcAddress := dglGetProcAddress('glXGetProcAddress');
-
-      // GLX_ARB_get_proc_address
-      glXGetProcAddressARB := dglGetProcAddress('glXGetProcAddressARB');
-
-      // GLX_ARB_create_context
-      glXCreateContextAttribsARB := dglGetProcAddress('glXCreateContextAttribsARB');
-
-      // GLX_EXT_import_context
-      glXGetCurrentDisplayEXT := dglGetProcAddress('glXGetCurrentDisplayEXT');
-      glXQueryContextInfoEXT := dglGetProcAddress('glXQueryContextInfoEXT');
-      glXGetContextIDEXT := dglGetProcAddress('glXGetContextIDEXT');
-      glXImportContextEXT := dglGetProcAddress('glXImportContextEXT');
-      glXFreeContextEXT := dglGetProcAddress('glXFreeContextEXT');
-      
-      // GLX_EXT_texture_from_pixmap
-      glXBindTexImageEXT := dglGetProcAddress('glXBindTexImageEXT');
-      glXReleaseTexImageEXT := dglGetProcAddress('glXReleaseTexImageEXT');
-    {$ENDIF}
-
-    Result := True;
-  end;
-
-  // load GLU functions
-  if GLU_LibHandle <> nil then begin
-    // GLU ========================================================================
-    gluBeginCurve := dglGetProcAddress('gluBeginCurve', GLU_LibHandle);
-    gluBeginPolygon := dglGetProcAddress('gluBeginPolygon', GLU_LibHandle);
-    gluBeginSurface := dglGetProcAddress('gluBeginSurface', GLU_LibHandle);
-    gluBeginTrim := dglGetProcAddress('gluBeginTrim', GLU_LibHandle);
-    gluBuild1DMipmaps := dglGetProcAddress('gluBuild1DMipmaps', GLU_LibHandle);
-    gluBuild2DMipmaps := dglGetProcAddress('gluBuild2DMipmaps', GLU_LibHandle);
-    gluCylinder := dglGetProcAddress('gluCylinder', GLU_LibHandle);
-    gluDeleteNurbsRenderer := dglGetProcAddress('gluDeleteNurbsRenderer', GLU_LibHandle);
-    gluDeleteQuadric := dglGetProcAddress('gluDeleteQuadric', GLU_LibHandle);
-    gluDeleteTess := dglGetProcAddress('gluDeleteTess', GLU_LibHandle);
-    gluDisk := dglGetProcAddress('gluDisk', GLU_LibHandle);
-    gluEndCurve := dglGetProcAddress('gluEndCurve', GLU_LibHandle);
-    gluEndPolygon := dglGetProcAddress('gluEndPolygon', GLU_LibHandle);
-    gluEndSurface := dglGetProcAddress('gluEndSurface', GLU_LibHandle);
-    gluEndTrim := dglGetProcAddress('gluEndTrim', GLU_LibHandle);
-    gluErrorString := dglGetProcAddress('gluErrorString', GLU_LibHandle);
-    gluGetNurbsProperty := dglGetProcAddress('gluGetNurbsProperty', GLU_LibHandle);
-    gluGetString := dglGetProcAddress('gluGetString', GLU_LibHandle);
-    gluGetTessProperty := dglGetProcAddress('gluGetTessProperty', GLU_LibHandle);
-    gluLoadSamplingMatrices := dglGetProcAddress('gluLoadSamplingMatrices', GLU_LibHandle);
-    gluLookAt := dglGetProcAddress('gluLookAt', GLU_LibHandle);
-    gluNewNurbsRenderer := dglGetProcAddress('gluNewNurbsRenderer', GLU_LibHandle);
-    gluNewQuadric := dglGetProcAddress('gluNewQuadric', GLU_LibHandle);
-    gluNewTess := dglGetProcAddress('gluNewTess', GLU_LibHandle);
-    gluNextContour := dglGetProcAddress('gluNextContour', GLU_LibHandle);
-    gluNurbsCallback := dglGetProcAddress('gluNurbsCallback', GLU_LibHandle);
-    gluNurbsCurve := dglGetProcAddress('gluNurbsCurve', GLU_LibHandle);
-    gluNurbsProperty := dglGetProcAddress('gluNurbsProperty', GLU_LibHandle);
-    gluNurbsSurface := dglGetProcAddress('gluNurbsSurface', GLU_LibHandle);
-    gluOrtho2D := dglGetProcAddress('gluOrtho2D', GLU_LibHandle);
-    gluPartialDisk := dglGetProcAddress('gluPartialDisk', GLU_LibHandle);
-    gluPerspective := dglGetProcAddress('gluPerspective', GLU_LibHandle);
-    gluPickMatrix := dglGetProcAddress('gluPickMatrix', GLU_LibHandle);
-    gluProject := dglGetProcAddress('gluProject', GLU_LibHandle);
-    gluPwlCurve := dglGetProcAddress('gluPwlCurve', GLU_LibHandle);
-    gluQuadricCallback := dglGetProcAddress('gluQuadricCallback', GLU_LibHandle);
-    gluQuadricDrawStyle := dglGetProcAddress('gluQuadricDrawStyle', GLU_LibHandle);
-    gluQuadricNormals := dglGetProcAddress('gluQuadricNormals', GLU_LibHandle);
-    gluQuadricOrientation := dglGetProcAddress('gluQuadricOrientation', GLU_LibHandle);
-    gluQuadricTexture := dglGetProcAddress('gluQuadricTexture', GLU_LibHandle);
-    gluScaleImage := dglGetProcAddress('gluScaleImage', GLU_LibHandle);
-    gluSphere := dglGetProcAddress('gluSphere', GLU_LibHandle);
-    gluTessBeginContour := dglGetProcAddress('gluTessBeginContour', GLU_LibHandle);
-    gluTessBeginPolygon := dglGetProcAddress('gluTessBeginPolygon', GLU_LibHandle);
-    gluTessCallback := dglGetProcAddress('gluTessCallback', GLU_LibHandle);
-    gluTessEndContour := dglGetProcAddress('gluTessEndContour', GLU_LibHandle);
-    gluTessEndPolygon := dglGetProcAddress('gluTessEndPolygon', GLU_LibHandle);
-    gluTessNormal := dglGetProcAddress('gluTessNormal', GLU_LibHandle);
-    gluTessProperty := dglGetProcAddress('gluTessProperty', GLU_LibHandle);
-    gluTessVertex := dglGetProcAddress('gluTessVertex', GLU_LibHandle);
-    gluUnProject := dglGetProcAddress('gluUnProject', GLU_LibHandle);
-  end;
-end;
-
-procedure ReadOpenGLCore;
-begin
-  // GL_VERSION_1_0
-  glCullFace := dglGetProcAddress('glCullFace');
-  glFrontFace := dglGetProcAddress('glFrontFace');
-  glHint := dglGetProcAddress('glHint');
-  glLineWidth := dglGetProcAddress('glLineWidth');
-  glPointSize := dglGetProcAddress('glPointSize');
-  glPolygonMode := dglGetProcAddress('glPolygonMode');
-  glScissor := dglGetProcAddress('glScissor');
-  glTexParameterf := dglGetProcAddress('glTexParameterf');
-  glTexParameterfv := dglGetProcAddress('glTexParameterfv');
-  glTexParameteri := dglGetProcAddress('glTexParameteri');
-  glTexParameteriv := dglGetProcAddress('glTexParameteriv');
-  glTexImage1D := dglGetProcAddress('glTexImage1D');
-  glTexImage2D := dglGetProcAddress('glTexImage2D');
-  glDrawBuffer := dglGetProcAddress('glDrawBuffer');
-  glClear := dglGetProcAddress('glClear');
-  glClearColor := dglGetProcAddress('glClearColor');
-  glClearStencil := dglGetProcAddress('glClearStencil');
-  glClearDepth := dglGetProcAddress('glClearDepth');
-  glStencilMask := dglGetProcAddress('glStencilMask');
-  glColorMask := dglGetProcAddress('glColorMask');
-  glDepthMask := dglGetProcAddress('glDepthMask');
-  glDisable := dglGetProcAddress('glDisable');
-  glEnable := dglGetProcAddress('glEnable');
-  glFinish := dglGetProcAddress('glFinish');
-  glFlush := dglGetProcAddress('glFlush');
-  glBlendFunc := dglGetProcAddress('glBlendFunc');
-  glLogicOp := dglGetProcAddress('glLogicOp');
-  glStencilFunc := dglGetProcAddress('glStencilFunc');
-  glStencilOp := dglGetProcAddress('glStencilOp');
-  glDepthFunc := dglGetProcAddress('glDepthFunc');
-  glPixelStoref := dglGetProcAddress('glPixelStoref');
-  glPixelStorei := dglGetProcAddress('glPixelStorei');
-  glReadBuffer := dglGetProcAddress('glReadBuffer');
-  glReadPixels := dglGetProcAddress('glReadPixels');
-  glGetBooleanv := dglGetProcAddress('glGetBooleanv');
-  glGetDoublev := dglGetProcAddress('glGetDoublev');
-  glGetError := dglGetProcAddress('glGetError');
-  glGetFloatv := dglGetProcAddress('glGetFloatv');
-  glGetIntegerv := dglGetProcAddress('glGetIntegerv');
-  glGetString := dglGetProcAddress('glGetString');
-  glGetTexImage := dglGetProcAddress('glGetTexImage');
-  glGetTexParameteriv := dglGetProcAddress('glGetTexParameteriv');
-  glGetTexParameterfv := dglGetProcAddress('glGetTexParameterfv');
-  glGetTexLevelParameterfv := dglGetProcAddress('glGetTexLevelParameterfv');
-  glGetTexLevelParameteriv := dglGetProcAddress('glGetTexLevelParameteriv');
-  glIsEnabled := dglGetProcAddress('glIsEnabled');
-  glDepthRange := dglGetProcAddress('glDepthRange');
-  glViewport := dglGetProcAddress('glViewport');
-
-  // GL_VERSION_1_1
-  glDrawArrays := dglGetProcAddress('glDrawArrays');
-  glDrawElements := dglGetProcAddress('glDrawElements');
-  glGetPointerv := dglGetProcAddress('glGetPointerv');
-  glPolygonOffset := dglGetProcAddress('glPolygonOffset');
-  glCopyTexImage1D := dglGetProcAddress('glCopyTexImage1D');
-  glCopyTexImage2D := dglGetProcAddress('glCopyTexImage2D');
-  glCopyTexSubImage1D := dglGetProcAddress('glCopyTexSubImage1D');
-  glCopyTexSubImage2D := dglGetProcAddress('glCopyTexSubImage2D');
-  glTexSubImage1D := dglGetProcAddress('glTexSubImage1D');
-  glTexSubImage2D := dglGetProcAddress('glTexSubImage2D');
-  glBindTexture := dglGetProcAddress('glBindTexture');
-  glDeleteTextures := dglGetProcAddress('glDeleteTextures');
-  glGenTextures := dglGetProcAddress('glGenTextures');
-
-{$ifdef DGL_DEPRECATED}
-  glAccum := dglGetProcAddress('glAccum');
-  glAlphaFunc := dglGetProcAddress('glAlphaFunc');
-  glAreTexturesResident := dglGetProcAddress('glAreTexturesResident');
-  glArrayElement := dglGetProcAddress('glArrayElement');
-  glBegin := dglGetProcAddress('glBegin');
-  glBitmap := dglGetProcAddress('glBitmap');
-  glCallList := dglGetProcAddress('glCallList');
-  glCallLists := dglGetProcAddress('glCallLists');
-  glClearAccum := dglGetProcAddress('glClearAccum');
-  glClearIndex := dglGetProcAddress('glClearIndex');
-  glClipPlane := dglGetProcAddress('glClipPlane');
-  glColor3b := dglGetProcAddress('glColor3b');
-  glColor3bv := dglGetProcAddress('glColor3bv');
-  glColor3d := dglGetProcAddress('glColor3d');
-  glColor3dv := dglGetProcAddress('glColor3dv');
-  glColor3f := dglGetProcAddress('glColor3f');
-  glColor3fv := dglGetProcAddress('glColor3fv');
-  glColor3i := dglGetProcAddress('glColor3i');
-  glColor3iv := dglGetProcAddress('glColor3iv');
-  glColor3s := dglGetProcAddress('glColor3s');
-  glColor3sv := dglGetProcAddress('glColor3sv');
-  glColor3ub := dglGetProcAddress('glColor3ub');
-  glColor3ubv := dglGetProcAddress('glColor3ubv');
-  glColor3ui := dglGetProcAddress('glColor3ui');
-  glColor3uiv := dglGetProcAddress('glColor3uiv');
-  glColor3us := dglGetProcAddress('glColor3us');
-  glColor3usv := dglGetProcAddress('glColor3usv');
-  glColor4b := dglGetProcAddress('glColor4b');
-  glColor4bv := dglGetProcAddress('glColor4bv');
-  glColor4d := dglGetProcAddress('glColor4d');
-  glColor4dv := dglGetProcAddress('glColor4dv');
-  glColor4f := dglGetProcAddress('glColor4f');
-  glColor4fv := dglGetProcAddress('glColor4fv');
-  glColor4i := dglGetProcAddress('glColor4i');
-  glColor4iv := dglGetProcAddress('glColor4iv');
-  glColor4s := dglGetProcAddress('glColor4s');
-  glColor4sv := dglGetProcAddress('glColor4sv');
-  glColor4ub := dglGetProcAddress('glColor4ub');
-  glColor4ubv := dglGetProcAddress('glColor4ubv');
-  glColor4ui := dglGetProcAddress('glColor4ui');
-  glColor4uiv := dglGetProcAddress('glColor4uiv');
-  glColor4us := dglGetProcAddress('glColor4us');
-  glColor4usv := dglGetProcAddress('glColor4usv');
-  glColorMaterial := dglGetProcAddress('glColorMaterial');
-  glColorPointer := dglGetProcAddress('glColorPointer');
-  glCopyPixels := dglGetProcAddress('glCopyPixels');
-  glDeleteLists := dglGetProcAddress('glDeleteLists');
-  glDisableClientState := dglGetProcAddress('glDisableClientState');
-  glDrawPixels := dglGetProcAddress('glDrawPixels');
-  glEdgeFlag := dglGetProcAddress('glEdgeFlag');
-  glEdgeFlagPointer := dglGetProcAddress('glEdgeFlagPointer');
-  glEdgeFlagv := dglGetProcAddress('glEdgeFlagv');
-  glEnableClientState := dglGetProcAddress('glEnableClientState');
-  glEnd := dglGetProcAddress('glEnd');
-  glEndList := dglGetProcAddress('glEndList');
-  glEvalCoord1d := dglGetProcAddress('glEvalCoord1d');
-  glEvalCoord1dv := dglGetProcAddress('glEvalCoord1dv');
-  glEvalCoord1f := dglGetProcAddress('glEvalCoord1f');
-  glEvalCoord1fv := dglGetProcAddress('glEvalCoord1fv');
-  glEvalCoord2d := dglGetProcAddress('glEvalCoord2d');
-  glEvalCoord2dv := dglGetProcAddress('glEvalCoord2dv');
-  glEvalCoord2f := dglGetProcAddress('glEvalCoord2f');
-  glEvalCoord2fv := dglGetProcAddress('glEvalCoord2fv');
-  glEvalMesh1 := dglGetProcAddress('glEvalMesh1');
-  glEvalMesh2 := dglGetProcAddress('glEvalMesh2');
-  glEvalPoint1 := dglGetProcAddress('glEvalPoint1');
-  glEvalPoint2 := dglGetProcAddress('glEvalPoint2');
-  glFeedbackBuffer := dglGetProcAddress('glFeedbackBuffer');
-  glFogf := dglGetProcAddress('glFogf');
-  glFogfv := dglGetProcAddress('glFogfv');
-  glFogi := dglGetProcAddress('glFogi');
-  glFogiv := dglGetProcAddress('glFogiv');
-  glFrustum := dglGetProcAddress('glFrustum');
-  glGenLists := dglGetProcAddress('glGenLists');
-  glGetClipPlane := dglGetProcAddress('glGetClipPlane');
-  glGetLightfv := dglGetProcAddress('glGetLightfv');
-  glGetLightiv := dglGetProcAddress('glGetLightiv');
-  glGetMapdv := dglGetProcAddress('glGetMapdv');
-  glGetMapfv := dglGetProcAddress('glGetMapfv');
-  glGetMapiv := dglGetProcAddress('glGetMapiv');
-  glGetMaterialfv := dglGetProcAddress('glGetMaterialfv');
-  glGetMaterialiv := dglGetProcAddress('glGetMaterialiv');
-  glGetPixelMapfv := dglGetProcAddress('glGetPixelMapfv');
-  glGetPixelMapuiv := dglGetProcAddress('glGetPixelMapuiv');
-  glGetPixelMapusv := dglGetProcAddress('glGetPixelMapusv');
-  glGetPolygonStipple := dglGetProcAddress('glGetPolygonStipple');
-  glGetTexEnvfv := dglGetProcAddress('glGetTexEnvfv');
-  glGetTexEnviv := dglGetProcAddress('glGetTexEnviv');
-  glGetTexGendv := dglGetProcAddress('glGetTexGendv');
-  glGetTexGenfv := dglGetProcAddress('glGetTexGenfv');
-  glGetTexGeniv := dglGetProcAddress('glGetTexGeniv');
-  glIndexMask := dglGetProcAddress('glIndexMask');
-  glIndexPointer := dglGetProcAddress('glIndexPointer');
-  glIndexd := dglGetProcAddress('glIndexd');
-  glIndexdv := dglGetProcAddress('glIndexdv');
-  glIndexf := dglGetProcAddress('glIndexf');
-  glIndexfv := dglGetProcAddress('glIndexfv');
-  glIndexi := dglGetProcAddress('glIndexi');
-  glIndexiv := dglGetProcAddress('glIndexiv');
-  glIndexs := dglGetProcAddress('glIndexs');
-  glIndexsv := dglGetProcAddress('glIndexsv');
-  glIndexub := dglGetProcAddress('glIndexub');
-  glIndexubv := dglGetProcAddress('glIndexubv');
-  glInitNames := dglGetProcAddress('glInitNames');
-  glInterleavedArrays := dglGetProcAddress('glInterleavedArrays');
-  glIsList := dglGetProcAddress('glIsList');
-  glIsTexture := dglGetProcAddress('glIsTexture');
-  glLightModelf := dglGetProcAddress('glLightModelf');
-  glLightModelfv := dglGetProcAddress('glLightModelfv');
-  glLightModeli := dglGetProcAddress('glLightModeli');
-  glLightModeliv := dglGetProcAddress('glLightModeliv');
-  glLightf := dglGetProcAddress('glLightf');
-  glLightfv := dglGetProcAddress('glLightfv');
-  glLighti := dglGetProcAddress('glLighti');
-  glLightiv := dglGetProcAddress('glLightiv');
-  glLineStipple := dglGetProcAddress('glLineStipple');
-  glListBase := dglGetProcAddress('glListBase');
-  glLoadIdentity := dglGetProcAddress('glLoadIdentity');
-  glLoadMatrixd := dglGetProcAddress('glLoadMatrixd');
-  glLoadMatrixf := dglGetProcAddress('glLoadMatrixf');
-  glLoadName := dglGetProcAddress('glLoadName');
-  glMap1d := dglGetProcAddress('glMap1d');
-  glMap1f := dglGetProcAddress('glMap1f');
-  glMap2d := dglGetProcAddress('glMap2d');
-  glMap2f := dglGetProcAddress('glMap2f');
-  glMapGrid1d := dglGetProcAddress('glMapGrid1d');
-  glMapGrid1f := dglGetProcAddress('glMapGrid1f');
-  glMapGrid2d := dglGetProcAddress('glMapGrid2d');
-  glMapGrid2f := dglGetProcAddress('glMapGrid2f');
-  glMaterialf := dglGetProcAddress('glMaterialf');
-  glMaterialfv := dglGetProcAddress('glMaterialfv');
-  glMateriali := dglGetProcAddress('glMateriali');
-  glMaterialiv := dglGetProcAddress('glMaterialiv');
-  glMatrixMode := dglGetProcAddress('glMatrixMode');
-  glMultMatrixd := dglGetProcAddress('glMultMatrixd');
-  glMultMatrixf := dglGetProcAddress('glMultMatrixf');
-  glNewList := dglGetProcAddress('glNewList');
-  glNormal3b := dglGetProcAddress('glNormal3b');
-  glNormal3bv := dglGetProcAddress('glNormal3bv');
-  glNormal3d := dglGetProcAddress('glNormal3d');
-  glNormal3dv := dglGetProcAddress('glNormal3dv');
-  glNormal3f := dglGetProcAddress('glNormal3f');
-  glNormal3fv := dglGetProcAddress('glNormal3fv');
-  glNormal3i := dglGetProcAddress('glNormal3i');
-  glNormal3iv := dglGetProcAddress('glNormal3iv');
-  glNormal3s := dglGetProcAddress('glNormal3s');
-  glNormal3sv := dglGetProcAddress('glNormal3sv');
-  glNormalPointer := dglGetProcAddress('glNormalPointer');
-  glOrtho := dglGetProcAddress('glOrtho');
-  glPassThrough := dglGetProcAddress('glPassThrough');
-  glPixelMapfv := dglGetProcAddress('glPixelMapfv');
-  glPixelMapuiv := dglGetProcAddress('glPixelMapuiv');
-  glPixelMapusv := dglGetProcAddress('glPixelMapusv');
-  glPixelTransferf := dglGetProcAddress('glPixelTransferf');
-  glPixelTransferi := dglGetProcAddress('glPixelTransferi');
-  glPixelZoom := dglGetProcAddress('glPixelZoom');
-  glPolygonStipple := dglGetProcAddress('glPolygonStipple');
-  glPopAttrib := dglGetProcAddress('glPopAttrib');
-  glPopClientAttrib := dglGetProcAddress('glPopClientAttrib');
-  glPopMatrix := dglGetProcAddress('glPopMatrix');
-  glPopName := dglGetProcAddress('glPopName');
-  glPrioritizeTextures := dglGetProcAddress('glPrioritizeTextures');
-  glPushAttrib := dglGetProcAddress('glPushAttrib');
-  glPushClientAttrib := dglGetProcAddress('glPushClientAttrib');
-  glPushMatrix := dglGetProcAddress('glPushMatrix');
-  glPushName := dglGetProcAddress('glPushName');
-  glRasterPos2d := dglGetProcAddress('glRasterPos2d');
-  glRasterPos2dv := dglGetProcAddress('glRasterPos2dv');
-  glRasterPos2f := dglGetProcAddress('glRasterPos2f');
-  glRasterPos2fv := dglGetProcAddress('glRasterPos2fv');
-  glRasterPos2i := dglGetProcAddress('glRasterPos2i');
-  glRasterPos2iv := dglGetProcAddress('glRasterPos2iv');
-  glRasterPos2s := dglGetProcAddress('glRasterPos2s');
-  glRasterPos2sv := dglGetProcAddress('glRasterPos2sv');
-  glRasterPos3d := dglGetProcAddress('glRasterPos3d');
-  glRasterPos3dv := dglGetProcAddress('glRasterPos3dv');
-  glRasterPos3f := dglGetProcAddress('glRasterPos3f');
-  glRasterPos3fv := dglGetProcAddress('glRasterPos3fv');
-  glRasterPos3i := dglGetProcAddress('glRasterPos3i');
-  glRasterPos3iv := dglGetProcAddress('glRasterPos3iv');
-  glRasterPos3s := dglGetProcAddress('glRasterPos3s');
-  glRasterPos3sv := dglGetProcAddress('glRasterPos3sv');
-  glRasterPos4d := dglGetProcAddress('glRasterPos4d');
-  glRasterPos4dv := dglGetProcAddress('glRasterPos4dv');
-  glRasterPos4f := dglGetProcAddress('glRasterPos4f');
-  glRasterPos4fv := dglGetProcAddress('glRasterPos4fv');
-  glRasterPos4i := dglGetProcAddress('glRasterPos4i');
-  glRasterPos4iv := dglGetProcAddress('glRasterPos4iv');
-  glRasterPos4s := dglGetProcAddress('glRasterPos4s');
-  glRasterPos4sv := dglGetProcAddress('glRasterPos4sv');
-  glRectd := dglGetProcAddress('glRectd');
-  glRectdv := dglGetProcAddress('glRectdv');
-  glRectf := dglGetProcAddress('glRectf');
-  glRectfv := dglGetProcAddress('glRectfv');
-  glRecti := dglGetProcAddress('glRecti');
-  glRectiv := dglGetProcAddress('glRectiv');
-  glRects := dglGetProcAddress('glRects');
-  glRectsv := dglGetProcAddress('glRectsv');
-  glRenderMode := dglGetProcAddress('glRenderMode');
-  glRotated := dglGetProcAddress('glRotated');
-  glRotatef := dglGetProcAddress('glRotatef');
-  glScaled := dglGetProcAddress('glScaled');
-  glScalef := dglGetProcAddress('glScalef');
-  glSelectBuffer := dglGetProcAddress('glSelectBuffer');
-  glShadeModel := dglGetProcAddress('glShadeModel');
-  glTexCoord1d := dglGetProcAddress('glTexCoord1d');
-  glTexCoord1dv := dglGetProcAddress('glTexCoord1dv');
-  glTexCoord1f := dglGetProcAddress('glTexCoord1f');
-  glTexCoord1fv := dglGetProcAddress('glTexCoord1fv');
-  glTexCoord1i := dglGetProcAddress('glTexCoord1i');
-  glTexCoord1iv := dglGetProcAddress('glTexCoord1iv');
-  glTexCoord1s := dglGetProcAddress('glTexCoord1s');
-  glTexCoord1sv := dglGetProcAddress('glTexCoord1sv');
-  glTexCoord2d := dglGetProcAddress('glTexCoord2d');
-  glTexCoord2dv := dglGetProcAddress('glTexCoord2dv');
-  glTexCoord2f := dglGetProcAddress('glTexCoord2f');
-  glTexCoord2fv := dglGetProcAddress('glTexCoord2fv');
-  glTexCoord2i := dglGetProcAddress('glTexCoord2i');
-  glTexCoord2iv := dglGetProcAddress('glTexCoord2iv');
-  glTexCoord2s := dglGetProcAddress('glTexCoord2s');
-  glTexCoord2sv := dglGetProcAddress('glTexCoord2sv');
-  glTexCoord3d := dglGetProcAddress('glTexCoord3d');
-  glTexCoord3dv := dglGetProcAddress('glTexCoord3dv');
-  glTexCoord3f := dglGetProcAddress('glTexCoord3f');
-  glTexCoord3fv := dglGetProcAddress('glTexCoord3fv');
-  glTexCoord3i := dglGetProcAddress('glTexCoord3i');
-  glTexCoord3iv := dglGetProcAddress('glTexCoord3iv');
-  glTexCoord3s := dglGetProcAddress('glTexCoord3s');
-  glTexCoord3sv := dglGetProcAddress('glTexCoord3sv');
-  glTexCoord4d := dglGetProcAddress('glTexCoord4d');
-  glTexCoord4dv := dglGetProcAddress('glTexCoord4dv');
-  glTexCoord4f := dglGetProcAddress('glTexCoord4f');
-  glTexCoord4fv := dglGetProcAddress('glTexCoord4fv');
-  glTexCoord4i := dglGetProcAddress('glTexCoord4i');
-  glTexCoord4iv := dglGetProcAddress('glTexCoord4iv');
-  glTexCoord4s := dglGetProcAddress('glTexCoord4s');
-  glTexCoord4sv := dglGetProcAddress('glTexCoord4sv');
-  glTexCoordPointer := dglGetProcAddress('glTexCoordPointer');
-  glTexEnvf := dglGetProcAddress('glTexEnvf');
-  glTexEnvfv := dglGetProcAddress('glTexEnvfv');
-  glTexEnvi := dglGetProcAddress('glTexEnvi');
-  glTexEnviv := dglGetProcAddress('glTexEnviv');
-  glTexGend := dglGetProcAddress('glTexGend');
-  glTexGendv := dglGetProcAddress('glTexGendv');
-  glTexGenf := dglGetProcAddress('glTexGenf');
-  glTexGenfv := dglGetProcAddress('glTexGenfv');
-  glTexGeni := dglGetProcAddress('glTexGeni');
-  glTexGeniv := dglGetProcAddress('glTexGeniv');
-  glTranslated := dglGetProcAddress('glTranslated');
-  glTranslatef := dglGetProcAddress('glTranslatef');
-  glVertex2d := dglGetProcAddress('glVertex2d');
-  glVertex2dv := dglGetProcAddress('glVertex2dv');
-  glVertex2f := dglGetProcAddress('glVertex2f');
-  glVertex2fv := dglGetProcAddress('glVertex2fv');
-  glVertex2i := dglGetProcAddress('glVertex2i');
-  glVertex2iv := dglGetProcAddress('glVertex2iv');
-  glVertex2s := dglGetProcAddress('glVertex2s');
-  glVertex2sv := dglGetProcAddress('glVertex2sv');
-  glVertex3d := dglGetProcAddress('glVertex3d');
-  glVertex3dv := dglGetProcAddress('glVertex3dv');
-  glVertex3f := dglGetProcAddress('glVertex3f');
-  glVertex3fv := dglGetProcAddress('glVertex3fv');
-  glVertex3i := dglGetProcAddress('glVertex3i');
-  glVertex3iv := dglGetProcAddress('glVertex3iv');
-  glVertex3s := dglGetProcAddress('glVertex3s');
-  glVertex3sv := dglGetProcAddress('glVertex3sv');
-  glVertex4d := dglGetProcAddress('glVertex4d');
-  glVertex4dv := dglGetProcAddress('glVertex4dv');
-  glVertex4f := dglGetProcAddress('glVertex4f');
-  glVertex4fv := dglGetProcAddress('glVertex4fv');
-  glVertex4i := dglGetProcAddress('glVertex4i');
-  glVertex4iv := dglGetProcAddress('glVertex4iv');
-  glVertex4s := dglGetProcAddress('glVertex4s');
-  glVertex4sv := dglGetProcAddress('glVertex4sv');
-  glVertexPointer := dglGetProcAddress('glVertexPointer');
-{$endif}
-
-  // GL_VERSION_1_2
-  glBlendColor := dglGetProcAddress('glBlendColor');
-  glBlendEquation := dglGetProcAddress('glBlendEquation');
-  glDrawRangeElements := dglGetProcAddress('glDrawRangeElements');
-  glTexImage3D := dglGetProcAddress('glTexImage3D');
-  glTexSubImage3D := dglGetProcAddress('glTexSubImage3D');
-  glCopyTexSubImage3D := dglGetProcAddress('glCopyTexSubImage3D');
-{$ifdef DGL_DEPRECATED}
-  glColorTable := dglGetProcAddress('glColorTable');
-  glColorTableParameterfv := dglGetProcAddress('glColorTableParameterfv');
-  glColorTableParameteriv := dglGetProcAddress('glColorTableParameteriv');
-  glCopyColorTable := dglGetProcAddress('glCopyColorTable');
-  glGetColorTable := dglGetProcAddress('glGetColorTable');
-  glGetColorTableParameterfv := dglGetProcAddress('glGetColorTableParameterfv');
-  glGetColorTableParameteriv := dglGetProcAddress('glGetColorTableParameteriv');
-  glColorSubTable := dglGetProcAddress('glColorSubTable');
-  glCopyColorSubTable := dglGetProcAddress('glCopyColorSubTable');
-  glConvolutionFilter1D := dglGetProcAddress('glConvolutionFilter1D');
-  glConvolutionFilter2D := dglGetProcAddress('glConvolutionFilter2D');
-  glConvolutionParameterf := dglGetProcAddress('glConvolutionParameterf');
-  glConvolutionParameterfv := dglGetProcAddress('glConvolutionParameterfv');
-  glConvolutionParameteri := dglGetProcAddress('glConvolutionParameteri');
-  glConvolutionParameteriv := dglGetProcAddress('glConvolutionParameteriv');
-  glCopyConvolutionFilter1D := dglGetProcAddress('glCopyConvolutionFilter1D');
-  glCopyConvolutionFilter2D := dglGetProcAddress('glCopyConvolutionFilter2D');
-  glGetConvolutionFilter := dglGetProcAddress('glGetConvolutionFilter');
-  glGetConvolutionParameterfv := dglGetProcAddress('glGetConvolutionParameterfv');
-  glGetConvolutionParameteriv := dglGetProcAddress('glGetConvolutionParameteriv');
-  glGetSeparableFilter := dglGetProcAddress('glGetSeparableFilter');
-  glSeparableFilter2D := dglGetProcAddress('glSeparableFilter2D');
-  glGetHistogram := dglGetProcAddress('glGetHistogram');
-  glGetHistogramParameterfv := dglGetProcAddress('glGetHistogramParameterfv');
-  glGetHistogramParameteriv := dglGetProcAddress('glGetHistogramParameteriv');
-  glGetMinmax := dglGetProcAddress('glGetMinmax');
-  glGetMinmaxParameterfv := dglGetProcAddress('glGetMinmaxParameterfv');
-  glGetMinmaxParameteriv := dglGetProcAddress('glGetMinmaxParameteriv');
-  glHistogram := dglGetProcAddress('glHistogram');
-  glMinmax := dglGetProcAddress('glMinmax');
-  glResetHistogram := dglGetProcAddress('glResetHistogram');
-  glResetMinmax := dglGetProcAddress('glResetMinmax');
-{$endif}
-
-  // GL_VERSION_1_3
-  glActiveTexture := dglGetProcAddress('glActiveTexture');
-  glSampleCoverage := dglGetProcAddress('glSampleCoverage');
-  glCompressedTexImage3D := dglGetProcAddress('glCompressedTexImage3D');
-  glCompressedTexImage2D := dglGetProcAddress('glCompressedTexImage2D');
-  glCompressedTexImage1D := dglGetProcAddress('glCompressedTexImage1D');
-  glCompressedTexSubImage3D := dglGetProcAddress('glCompressedTexSubImage3D');
-  glCompressedTexSubImage2D := dglGetProcAddress('glCompressedTexSubImage2D');
-  glCompressedTexSubImage1D := dglGetProcAddress('glCompressedTexSubImage1D');
-  glGetCompressedTexImage := dglGetProcAddress('glGetCompressedTexImage');
-{$ifdef DGL_DEPRECATED}
-  glClientActiveTexture := dglGetProcAddress('glClientActiveTexture');
-  glMultiTexCoord1d := dglGetProcAddress('glMultiTexCoord1d');
-  glMultiTexCoord1dv := dglGetProcAddress('glMultiTexCoord1dv');
-  glMultiTexCoord1f := dglGetProcAddress('glMultiTexCoord1f');
-  glMultiTexCoord1fv := dglGetProcAddress('glMultiTexCoord1fv');
-  glMultiTexCoord1i := dglGetProcAddress('glMultiTexCoord1i');
-  glMultiTexCoord1iv := dglGetProcAddress('glMultiTexCoord1iv');
-  glMultiTexCoord1s := dglGetProcAddress('glMultiTexCoord1s');
-  glMultiTexCoord1sv := dglGetProcAddress('glMultiTexCoord1sv');
-  glMultiTexCoord2d := dglGetProcAddress('glMultiTexCoord2d');
-  glMultiTexCoord2dv := dglGetProcAddress('glMultiTexCoord2dv');
-  glMultiTexCoord2f := dglGetProcAddress('glMultiTexCoord2f');
-  glMultiTexCoord2fv := dglGetProcAddress('glMultiTexCoord2fv');
-  glMultiTexCoord2i := dglGetProcAddress('glMultiTexCoord2i');
-  glMultiTexCoord2iv := dglGetProcAddress('glMultiTexCoord2iv');
-  glMultiTexCoord2s := dglGetProcAddress('glMultiTexCoord2s');
-  glMultiTexCoord2sv := dglGetProcAddress('glMultiTexCoord2sv');
-  glMultiTexCoord3d := dglGetProcAddress('glMultiTexCoord3d');
-  glMultiTexCoord3dv := dglGetProcAddress('glMultiTexCoord3dv');
-  glMultiTexCoord3f := dglGetProcAddress('glMultiTexCoord3f');
-  glMultiTexCoord3fv := dglGetProcAddress('glMultiTexCoord3fv');
-  glMultiTexCoord3i := dglGetProcAddress('glMultiTexCoord3i');
-  glMultiTexCoord3iv := dglGetProcAddress('glMultiTexCoord3iv');
-  glMultiTexCoord3s := dglGetProcAddress('glMultiTexCoord3s');
-  glMultiTexCoord3sv := dglGetProcAddress('glMultiTexCoord3sv');
-  glMultiTexCoord4d := dglGetProcAddress('glMultiTexCoord4d');
-  glMultiTexCoord4dv := dglGetProcAddress('glMultiTexCoord4dv');
-  glMultiTexCoord4f := dglGetProcAddress('glMultiTexCoord4f');
-  glMultiTexCoord4fv := dglGetProcAddress('glMultiTexCoord4fv');
-  glMultiTexCoord4i := dglGetProcAddress('glMultiTexCoord4i');
-  glMultiTexCoord4iv := dglGetProcAddress('glMultiTexCoord4iv');
-  glMultiTexCoord4s := dglGetProcAddress('glMultiTexCoord4s');
-  glMultiTexCoord4sv := dglGetProcAddress('glMultiTexCoord4sv');
-  glLoadTransposeMatrixf := dglGetProcAddress('glLoadTransposeMatrixf');
-  glLoadTransposeMatrixd := dglGetProcAddress('glLoadTransposeMatrixd');
-  glMultTransposeMatrixf := dglGetProcAddress('glMultTransposeMatrixf');
-  glMultTransposeMatrixd := dglGetProcAddress('glMultTransposeMatrixd');
-{$endif}
-
-  // GL_VERSION_1_4
-  glBlendFuncSeparate := dglGetProcAddress('glBlendFuncSeparate');
-  glMultiDrawArrays := dglGetProcAddress('glMultiDrawArrays');
-  glMultiDrawElements := dglGetProcAddress('glMultiDrawElements');
-  glPointParameterf := dglGetProcAddress('glPointParameterf');
-  glPointParameterfv := dglGetProcAddress('glPointParameterfv');
-  glPointParameteri := dglGetProcAddress('glPointParameteri');
-  glPointParameteriv := dglGetProcAddress('glPointParameteriv');
-{$ifdef DGL_DEPRECATED}
-  glFogCoordf := dglGetProcAddress('glFogCoordf');
-  glFogCoordfv := dglGetProcAddress('glFogCoordfv');
-  glFogCoordd := dglGetProcAddress('glFogCoordd');
-  glFogCoorddv := dglGetProcAddress('glFogCoorddv');
-  glFogCoordPointer := dglGetProcAddress('glFogCoordPointer');
-  glSecondaryColor3b := dglGetProcAddress('glSecondaryColor3b');
-  glSecondaryColor3bv := dglGetProcAddress('glSecondaryColor3bv');
-  glSecondaryColor3d := dglGetProcAddress('glSecondaryColor3d');
-  glSecondaryColor3dv := dglGetProcAddress('glSecondaryColor3dv');
-  glSecondaryColor3f := dglGetProcAddress('glSecondaryColor3f');
-  glSecondaryColor3fv := dglGetProcAddress('glSecondaryColor3fv');
-  glSecondaryColor3i := dglGetProcAddress('glSecondaryColor3i');
-  glSecondaryColor3iv := dglGetProcAddress('glSecondaryColor3iv');
-  glSecondaryColor3s := dglGetProcAddress('glSecondaryColor3s');
-  glSecondaryColor3sv := dglGetProcAddress('glSecondaryColor3sv');
-  glSecondaryColor3ub := dglGetProcAddress('glSecondaryColor3ub');
-  glSecondaryColor3ubv := dglGetProcAddress('glSecondaryColor3ubv');
-  glSecondaryColor3ui := dglGetProcAddress('glSecondaryColor3ui');
-  glSecondaryColor3uiv := dglGetProcAddress('glSecondaryColor3uiv');
-  glSecondaryColor3us := dglGetProcAddress('glSecondaryColor3us');
-  glSecondaryColor3usv := dglGetProcAddress('glSecondaryColor3usv');
-  glSecondaryColorPointer := dglGetProcAddress('glSecondaryColorPointer');
-  glWindowPos2d := dglGetProcAddress('glWindowPos2d');
-  glWindowPos2dv := dglGetProcAddress('glWindowPos2dv');
-  glWindowPos2f := dglGetProcAddress('glWindowPos2f');
-  glWindowPos2fv := dglGetProcAddress('glWindowPos2fv');
-  glWindowPos2i := dglGetProcAddress('glWindowPos2i');
-  glWindowPos2iv := dglGetProcAddress('glWindowPos2iv');
-  glWindowPos2s := dglGetProcAddress('glWindowPos2s');
-  glWindowPos2sv := dglGetProcAddress('glWindowPos2sv');
-  glWindowPos3d := dglGetProcAddress('glWindowPos3d');
-  glWindowPos3dv := dglGetProcAddress('glWindowPos3dv');
-  glWindowPos3f := dglGetProcAddress('glWindowPos3f');
-  glWindowPos3fv := dglGetProcAddress('glWindowPos3fv');
-  glWindowPos3i := dglGetProcAddress('glWindowPos3i');
-  glWindowPos3iv := dglGetProcAddress('glWindowPos3iv');
-  glWindowPos3s := dglGetProcAddress('glWindowPos3s');
-  glWindowPos3sv := dglGetProcAddress('glWindowPos3sv');
-{$endif}
-
-  // GL_VERSION_1_5
-  glGenQueries := dglGetProcAddress('glGenQueries');
-  glDeleteQueries := dglGetProcAddress('glDeleteQueries');
-  glIsQuery := dglGetProcAddress('glIsQuery');
-  glBeginQuery := dglGetProcAddress('glBeginQuery');
-  glEndQuery := dglGetProcAddress('glEndQuery');
-  glGetQueryiv := dglGetProcAddress('glGetQueryiv');
-  glGetQueryObjectiv := dglGetProcAddress('glGetQueryObjectiv');
-  glGetQueryObjectuiv := dglGetProcAddress('glGetQueryObjectuiv');
-  glBindBuffer := dglGetProcAddress('glBindBuffer');
-  glDeleteBuffers := dglGetProcAddress('glDeleteBuffers');
-  glGenBuffers := dglGetProcAddress('glGenBuffers');
-  glIsBuffer := dglGetProcAddress('glIsBuffer');
-  glBufferData := dglGetProcAddress('glBufferData');
-  glBufferSubData := dglGetProcAddress('glBufferSubData');
-  glGetBufferSubData := dglGetProcAddress('glGetBufferSubData');
-  glMapBuffer := dglGetProcAddress('glMapBuffer');
-  glUnmapBuffer := dglGetProcAddress('glUnmapBuffer');
-  glGetBufferParameteriv := dglGetProcAddress('glGetBufferParameteriv');
-  glGetBufferPointerv := dglGetProcAddress('glGetBufferPointerv');
-
-  // GL_VERSION_2_0
-  glBlendEquationSeparate := dglGetProcAddress('glBlendEquationSeparate');
-  glDrawBuffers := dglGetProcAddress('glDrawBuffers');
-  glStencilOpSeparate := dglGetProcAddress('glStencilOpSeparate');
-  glStencilFuncSeparate := dglGetProcAddress('glStencilFuncSeparate');
-  glStencilMaskSeparate := dglGetProcAddress('glStencilMaskSeparate');
-  glAttachShader := dglGetProcAddress('glAttachShader');
-  glBindAttribLocation := dglGetProcAddress('glBindAttribLocation');
-  glCompileShader := dglGetProcAddress('glCompileShader');
-  glCreateProgram := dglGetProcAddress('glCreateProgram');
-  glCreateShader := dglGetProcAddress('glCreateShader');
-  glDeleteProgram := dglGetProcAddress('glDeleteProgram');
-  glDeleteShader := dglGetProcAddress('glDeleteShader');
-  glDetachShader := dglGetProcAddress('glDetachShader');
-  glDisableVertexAttribArray := dglGetProcAddress('glDisableVertexAttribArray');
-  glEnableVertexAttribArray := dglGetProcAddress('glEnableVertexAttribArray');
-  glGetActiveAttrib := dglGetProcAddress('glGetActiveAttrib');
-  glGetActiveUniform := dglGetProcAddress('glGetActiveUniform');
-  glGetAttachedShaders := dglGetProcAddress('glGetAttachedShaders');
-  glGetAttribLocation := dglGetProcAddress('glGetAttribLocation');
-  glGetProgramiv := dglGetProcAddress('glGetProgramiv');
-  glGetProgramInfoLog := dglGetProcAddress('glGetProgramInfoLog');
-  glGetShaderiv := dglGetProcAddress('glGetShaderiv');
-  glGetShaderInfoLog := dglGetProcAddress('glGetShaderInfoLog');
-  glGetShaderSource := dglGetProcAddress('glGetShaderSource');
-  glGetUniformLocation := dglGetProcAddress('glGetUniformLocation');
-  glGetUniformfv := dglGetProcAddress('glGetUniformfv');
-  glGetUniformiv := dglGetProcAddress('glGetUniformiv');
-  glGetVertexAttribfv := dglGetProcAddress('glGetVertexAttribfv');
-  glGetVertexAttribiv := dglGetProcAddress('glGetVertexAttribiv');
-  glGetVertexAttribPointerv := dglGetProcAddress('glGetVertexAttribPointerv');
-  glIsProgram := dglGetProcAddress('glIsProgram');
-  glIsShader := dglGetProcAddress('glIsShader');
-  glLinkProgram := dglGetProcAddress('glLinkProgram');
-  glShaderSource := dglGetProcAddress('glShaderSource');
-  glUseProgram := dglGetProcAddress('glUseProgram');
-  glUniform1f := dglGetProcAddress('glUniform1f');
-  glUniform2f := dglGetProcAddress('glUniform2f');
-  glUniform3f := dglGetProcAddress('glUniform3f');
-  glUniform4f := dglGetProcAddress('glUniform4f');
-  glUniform1i := dglGetProcAddress('glUniform1i');
-  glUniform2i := dglGetProcAddress('glUniform2i');
-  glUniform3i := dglGetProcAddress('glUniform3i');
-  glUniform4i := dglGetProcAddress('glUniform4i');
-  glUniform1fv := dglGetProcAddress('glUniform1fv');
-  glUniform2fv := dglGetProcAddress('glUniform2fv');
-  glUniform3fv := dglGetProcAddress('glUniform3fv');
-  glUniform4fv := dglGetProcAddress('glUniform4fv');
-  glUniform1iv := dglGetProcAddress('glUniform1iv');
-  glUniform2iv := dglGetProcAddress('glUniform2iv');
-  glUniform3iv := dglGetProcAddress('glUniform3iv');
-  glUniform4iv := dglGetProcAddress('glUniform4iv');
-  glUniformMatrix2fv := dglGetProcAddress('glUniformMatrix2fv');
-  glUniformMatrix3fv := dglGetProcAddress('glUniformMatrix3fv');
-  glUniformMatrix4fv := dglGetProcAddress('glUniformMatrix4fv');
-  glValidateProgram := dglGetProcAddress('glValidateProgram');
-  glVertexAttrib1d := dglGetProcAddress('glVertexAttrib1d');
-  glVertexAttrib1dv := dglGetProcAddress('glVertexAttrib1dv');
-  glVertexAttrib1f := dglGetProcAddress('glVertexAttrib1f');
-  glVertexAttrib1fv := dglGetProcAddress('glVertexAttrib1fv');
-  glVertexAttrib1s := dglGetProcAddress('glVertexAttrib1s');
-  glVertexAttrib1sv := dglGetProcAddress('glVertexAttrib1sv');
-  glVertexAttrib2d := dglGetProcAddress('glVertexAttrib2d');
-  glVertexAttrib2dv := dglGetProcAddress('glVertexAttrib2dv');
-  glVertexAttrib2f := dglGetProcAddress('glVertexAttrib2f');
-  glVertexAttrib2fv := dglGetProcAddress('glVertexAttrib2fv');
-  glVertexAttrib2s := dglGetProcAddress('glVertexAttrib2s');
-  glVertexAttrib2sv := dglGetProcAddress('glVertexAttrib2sv');
-  glVertexAttrib3d := dglGetProcAddress('glVertexAttrib3d');
-  glVertexAttrib3dv := dglGetProcAddress('glVertexAttrib3dv');
-  glVertexAttrib3f := dglGetProcAddress('glVertexAttrib3f');
-  glVertexAttrib3fv := dglGetProcAddress('glVertexAttrib3fv');
-  glVertexAttrib3s := dglGetProcAddress('glVertexAttrib3s');
-  glVertexAttrib3sv := dglGetProcAddress('glVertexAttrib3sv');
-  glVertexAttrib4Nbv := dglGetProcAddress('glVertexAttrib4Nbv');
-  glVertexAttrib4Niv := dglGetProcAddress('glVertexAttrib4Niv');
-  glVertexAttrib4Nsv := dglGetProcAddress('glVertexAttrib4Nsv');
-  glVertexAttrib4Nub := dglGetProcAddress('glVertexAttrib4Nub');
-  glVertexAttrib4Nubv := dglGetProcAddress('glVertexAttrib4Nubv');
-  glVertexAttrib4Nuiv := dglGetProcAddress('glVertexAttrib4Nuiv');
-  glVertexAttrib4Nusv := dglGetProcAddress('glVertexAttrib4Nusv');
-  glVertexAttrib4bv := dglGetProcAddress('glVertexAttrib4bv');
-  glVertexAttrib4d := dglGetProcAddress('glVertexAttrib4d');
-  glVertexAttrib4dv := dglGetProcAddress('glVertexAttrib4dv');
-  glVertexAttrib4f := dglGetProcAddress('glVertexAttrib4f');
-  glVertexAttrib4fv := dglGetProcAddress('glVertexAttrib4fv');
-  glVertexAttrib4iv := dglGetProcAddress('glVertexAttrib4iv');
-  glVertexAttrib4s := dglGetProcAddress('glVertexAttrib4s');
-  glVertexAttrib4sv := dglGetProcAddress('glVertexAttrib4sv');
-  glVertexAttrib4ubv := dglGetProcAddress('glVertexAttrib4ubv');
-  glVertexAttrib4uiv := dglGetProcAddress('glVertexAttrib4uiv');
-  glVertexAttrib4usv := dglGetProcAddress('glVertexAttrib4usv');
-  glVertexAttribPointer := dglGetProcAddress('glVertexAttribPointer');
-
-  // GL_VERSION_2_1
-  glUniformMatrix2x3fv := dglGetProcAddress('glUniformMatrix2x3fv');
-  glUniformMatrix3x2fv := dglGetProcAddress('glUniformMatrix3x2fv');
-  glUniformMatrix2x4fv := dglGetProcAddress('glUniformMatrix2x4fv');
-  glUniformMatrix4x2fv := dglGetProcAddress('glUniformMatrix4x2fv');
-  glUniformMatrix3x4fv := dglGetProcAddress('glUniformMatrix3x4fv');
-  glUniformMatrix4x3fv := dglGetProcAddress('glUniformMatrix4x3fv');
-  
-  // GL_VERSION_3_0
-  { OpenGL 3.0 also reuses entry points from these extensions: }
-  Read_GL_ARB_framebuffer_object;
-  Read_GL_ARB_map_buffer_range;
-  Read_GL_ARB_vertex_array_object;
-
-  glColorMaski := dglGetProcAddress('glColorMaski');
-  glGetBooleani_v := dglGetProcAddress('glGetBooleani_v');
-  glGetIntegeri_v := dglGetProcAddress('glGetIntegeri_v');
-  glEnablei := dglGetProcAddress('glEnablei');
-  glDisablei := dglGetProcAddress('glDisablei');
-  glIsEnabledi := dglGetProcAddress('glIsEnabledi');
-  glBeginTransformFeedback := dglGetProcAddress('glBeginTransformFeedback');
-  glEndTransformFeedback := dglGetProcAddress('glEndTransformFeedback');
-  glBindBufferRange := dglGetProcAddress('glBindBufferRange');
-  glBindBufferBase := dglGetProcAddress('glBindBufferBase');
-  glTransformFeedbackVaryings := dglGetProcAddress('glTransformFeedbackVaryings');
-  glGetTransformFeedbackVarying := dglGetProcAddress('glGetTransformFeedbackVarying');
-  glClampColor := dglGetProcAddress('glClampColor');
-  glBeginConditionalRender := dglGetProcAddress('glBeginConditionalRender');
-  glEndConditionalRender := dglGetProcAddress('glEndConditionalRender');
-  glVertexAttribI1i := dglGetProcAddress('glVertexAttribI1i');
-  glVertexAttribI2i := dglGetProcAddress('glVertexAttribI2i');
-  glVertexAttribI3i := dglGetProcAddress('glVertexAttribI3i');
-  glVertexAttribI4i := dglGetProcAddress('glVertexAttribI4i');
-  glVertexAttribI1ui := dglGetProcAddress('glVertexAttribI1ui');
-  glVertexAttribI2ui := dglGetProcAddress('glVertexAttribI2ui');
-  glVertexAttribI3ui := dglGetProcAddress('glVertexAttribI3ui');
-  glVertexAttribI4ui := dglGetProcAddress('glVertexAttribI4ui');
-  glVertexAttribI1iv := dglGetProcAddress('glVertexAttribI1iv');
-  glVertexAttribI2iv := dglGetProcAddress('glVertexAttribI2iv');
-  glVertexAttribI3iv := dglGetProcAddress('glVertexAttribI3iv');
-  glVertexAttribI4iv := dglGetProcAddress('glVertexAttribI4iv');
-  glVertexAttribI1uiv := dglGetProcAddress('glVertexAttribI1uiv');
-  glVertexAttribI2uiv := dglGetProcAddress('glVertexAttribI2uiv');
-  glVertexAttribI3uiv := dglGetProcAddress('glVertexAttribI3uiv');
-  glVertexAttribI4uiv := dglGetProcAddress('glVertexAttribI4uiv');
-  glVertexAttribI4bv := dglGetProcAddress('glVertexAttribI4bv');
-  glVertexAttribI4sv := dglGetProcAddress('glVertexAttribI4sv');
-  glVertexAttribI4ubv := dglGetProcAddress('glVertexAttribI4ubv');
-  glVertexAttribI4usv := dglGetProcAddress('glVertexAttribI4usv');
-  glVertexAttribIPointer := dglGetProcAddress('glVertexAttribIPointer');
-  glGetVertexAttribIiv := dglGetProcAddress('glGetVertexAttribIiv');
-  glGetVertexAttribIuiv := dglGetProcAddress('glGetVertexAttribIuiv');
-  glGetUniformuiv := dglGetProcAddress('glGetUniformuiv');
-  glBindFragDataLocation := dglGetProcAddress('glBindFragDataLocation');
-  glGetFragDataLocation := dglGetProcAddress('glGetFragDataLocation');
-  glUniform1ui := dglGetProcAddress('glUniform1ui');
-  glUniform2ui := dglGetProcAddress('glUniform2ui');
-  glUniform3ui := dglGetProcAddress('glUniform3ui');
-  glUniform4ui := dglGetProcAddress('glUniform4ui');
-  glUniform1uiv := dglGetProcAddress('glUniform1uiv');
-  glUniform2uiv := dglGetProcAddress('glUniform2uiv');
-  glUniform3uiv := dglGetProcAddress('glUniform3uiv');
-  glUniform4uiv := dglGetProcAddress('glUniform4uiv');
-  glTexParameterIiv := dglGetProcAddress('glTexParameterIiv');
-  glTexParameterIuiv := dglGetProcAddress('glTexParameterIuiv');
-  glGetTexParameterIiv := dglGetProcAddress('glGetTexParameterIiv');
-  glGetTexParameterIuiv := dglGetProcAddress('glGetTexParameterIuiv');
-  glClearBufferiv := dglGetProcAddress('glClearBufferiv');
-  glClearBufferuiv := dglGetProcAddress('glClearBufferuiv');
-  glClearBufferfv := dglGetProcAddress('glClearBufferfv');
-  glClearBufferfi := dglGetProcAddress('glClearBufferfi');
-  glGetStringi := dglGetProcAddress('glGetStringi');
-
-  // GL_VERSION_3_1
-  { OpenGL 3.1 also reuses entry points from these extensions: }
-  Read_GL_ARB_copy_buffer;
-  Read_GL_ARB_uniform_buffer_object;
-
-  glDrawArraysInstanced := dglGetProcAddress('glDrawArraysInstanced');
-  glDrawElementsInstanced := dglGetProcAddress('glDrawElementsInstanced');
-  glTexBuffer := dglGetProcAddress('glTexBuffer');
-  glPrimitiveRestartIndex := dglGetProcAddress('glPrimitiveRestartIndex');
-
-  // GL_VERSION_3_2
-  { OpenGL 3.2 also reuses entry points from these extensions: }
-  Read_GL_ARB_draw_elements_base_vertex;
-  Read_GL_ARB_provoking_vertex;
-  Read_GL_ARB_sync;
-  Read_GL_ARB_texture_multisample;
-
-  glGetInteger64i_v := dglGetProcAddress('glGetInteger64i_v');
-  glGetBufferParameteri64v := dglGetProcAddress('glGetBufferParameteri64v');
-  glProgramParameteri := dglGetProcAddress('glProgramParameteri');
-  glFramebufferTexture := dglGetProcAddress('glFramebufferTexture');
-  glFramebufferTextureFace := dglGetProcAddress('glFramebufferTextureFace');
-end;
-
-procedure Read_GL_3DFX_tbuffer;
-begin
-  glTbufferMask3DFX := dglGetProcAddress('glTbufferMask3DFX');
-end;
-
-procedure Read_GL_APPLE_element_array;
-begin
-  glElementPointerAPPLE := dglGetProcAddress('glElementPointerAPPLE');
-  glDrawElementArrayAPPLE := dglGetProcAddress('glDrawElementArrayAPPLE');
-  glDrawRangeElementArrayAPPLE := dglGetProcAddress('glDrawRangeElementArrayAPPLE');
-  glMultiDrawElementArrayAPPLE := dglGetProcAddress('glMultiDrawElementArrayAPPLE');
-  glMultiDrawRangeElementArrayAPPLE := dglGetProcAddress('glMultiDrawRangeElementArrayAPPLE');
-end;
-
-procedure Read_GL_APPLE_fence;
-begin
-  glGenFencesAPPLE := dglGetProcAddress('glGenFencesAPPLE');
-  glDeleteFencesAPPLE := dglGetProcAddress('glDeleteFencesAPPLE');
-  glSetFenceAPPLE := dglGetProcAddress('glSetFenceAPPLE');
-  glIsFenceAPPLE := dglGetProcAddress('glIsFenceAPPLE');
-  glTestFenceAPPLE := dglGetProcAddress('glTestFenceAPPLE');
-  glFinishFenceAPPLE := dglGetProcAddress('glFinishFenceAPPLE');
-  glTestObjectAPPLE := dglGetProcAddress('glTestObjectAPPLE');
-  glFinishObjectAPPLE := dglGetProcAddress('glFinishObjectAPPLE');
-end;
-
-procedure Read_GL_APPLE_vertex_array_object;
-begin
-  glBindVertexArrayAPPLE := dglGetProcAddress('glBindVertexArrayAPPLE');
-  glDeleteVertexArraysAPPLE := dglGetProcAddress('glDeleteVertexArraysAPPLE');
-  glGenVertexArraysAPPLE := dglGetProcAddress('glGenVertexArraysAPPLE');
-  glIsVertexArrayAPPLE := dglGetProcAddress('glIsVertexArrayAPPLE');
-end;
-
-procedure Read_GL_APPLE_vertex_array_range;
-begin
-  glVertexArrayRangeAPPLE := dglGetProcAddress('glVertexArrayRangeAPPLE');
-  glFlushVertexArrayRangeAPPLE := dglGetProcAddress('glFlushVertexArrayRangeAPPLE');
-  glVertexArrayParameteriAPPLE := dglGetProcAddress('glVertexArrayParameteriAPPLE');
-end;
-
-procedure Read_GL_APPLE_texture_range;
-begin
-  glTextureRangeAPPLE := dglGetProcAddress('glTextureRangeAPPLE');
-  glGetTexParameterPointervAPPLE := dglGetProcAddress('glGetTexParameterPointervAPPLE');
-end;
-
-procedure Read_GL_APPLE_vertex_program_evaluators;
-begin
-  glEnableVertexAttribAPPLE := dglGetProcAddress('glEnableVertexAttribAPPLE');
-  glDisableVertexAttribAPPLE := dglGetProcAddress('glDisableVertexAttribAPPLE');
-  glIsVertexAttribEnabledAPPLE := dglGetProcAddress('glIsVertexAttribEnabledAPPLE');
-  glMapVertexAttrib1dAPPLE := dglGetProcAddress('glMapVertexAttrib1dAPPLE');
-  glMapVertexAttrib1fAPPLE := dglGetProcAddress('glMapVertexAttrib1fAPPLE');
-  glMapVertexAttrib2dAPPLE := dglGetProcAddress('glMapVertexAttrib2dAPPLE');
-  glMapVertexAttrib2fAPPLE := dglGetProcAddress('glMapVertexAttrib2fAPPLE');
-end;
-
-procedure Read_GL_APPLE_object_purgeable;
-begin
-  glObjectPurgeableAPPLE := dglGetProcAddress('glObjectPurgeableAPPLE');
-  glObjectUnpurgeableAPPLE := dglGetProcAddress('glObjectUnpurgeableAPPLE');
-  glGetObjectParameterivAPPLE := dglGetProcAddress('glGetObjectParameterivAPPLE');
-end;
-
-procedure Read_GL_ARB_matrix_palette;
-begin
-  glCurrentPaletteMatrixARB := dglGetProcAddress('glCurrentPaletteMatrixARB');
-  glMatrixIndexubvARB := dglGetProcAddress('glMatrixIndexubvARB');
-  glMatrixIndexusvARB := dglGetProcAddress('glMatrixIndexusvARB');
-  glMatrixIndexuivARB := dglGetProcAddress('glMatrixIndexuivARB');
-  glMatrixIndexPointerARB := dglGetProcAddress('glMatrixIndexPointerARB');
-end;
-
-procedure Read_GL_ARB_multisample;
-begin
-  glSampleCoverageARB := dglGetProcAddress('glSampleCoverageARB');
-end;
-
-procedure Read_GL_ARB_multitexture;
-begin
-  glActiveTextureARB := dglGetProcAddress('glActiveTextureARB');
-  glClientActiveTextureARB := dglGetProcAddress('glClientActiveTextureARB');
-  glMultiTexCoord1dARB := dglGetProcAddress('glMultiTexCoord1dARB');
-  glMultiTexCoord1dvARB := dglGetProcAddress('glMultiTexCoord1dvARB');
-  glMultiTexCoord1fARB := dglGetProcAddress('glMultiTexCoord1fARB');
-  glMultiTexCoord1fvARB := dglGetProcAddress('glMultiTexCoord1fvARB');
-  glMultiTexCoord1iARB := dglGetProcAddress('glMultiTexCoord1iARB');
-  glMultiTexCoord1ivARB := dglGetProcAddress('glMultiTexCoord1ivARB');
-  glMultiTexCoord1sARB := dglGetProcAddress('glMultiTexCoord1sARB');
-  glMultiTexCoord1svARB := dglGetProcAddress('glMultiTexCoord1svARB');
-  glMultiTexCoord2dARB := dglGetProcAddress('glMultiTexCoord2dARB');
-  glMultiTexCoord2dvARB := dglGetProcAddress('glMultiTexCoord2dvARB');
-  glMultiTexCoord2fARB := dglGetProcAddress('glMultiTexCoord2fARB');
-  glMultiTexCoord2fvARB := dglGetProcAddress('glMultiTexCoord2fvARB');
-  glMultiTexCoord2iARB := dglGetProcAddress('glMultiTexCoord2iARB');
-  glMultiTexCoord2ivARB := dglGetProcAddress('glMultiTexCoord2ivARB');
-  glMultiTexCoord2sARB := dglGetProcAddress('glMultiTexCoord2sARB');
-  glMultiTexCoord2svARB := dglGetProcAddress('glMultiTexCoord2svARB');
-  glMultiTexCoord3dARB := dglGetProcAddress('glMultiTexCoord3dARB');
-  glMultiTexCoord3dvARB := dglGetProcAddress('glMultiTexCoord3dvARB');
-  glMultiTexCoord3fARB := dglGetProcAddress('glMultiTexCoord3fARB');
-  glMultiTexCoord3fvARB := dglGetProcAddress('glMultiTexCoord3fvARB');
-  glMultiTexCoord3iARB := dglGetProcAddress('glMultiTexCoord3iARB');
-  glMultiTexCoord3ivARB := dglGetProcAddress('glMultiTexCoord3ivARB');
-  glMultiTexCoord3sARB := dglGetProcAddress('glMultiTexCoord3sARB');
-  glMultiTexCoord3svARB := dglGetProcAddress('glMultiTexCoord3svARB');
-  glMultiTexCoord4dARB := dglGetProcAddress('glMultiTexCoord4dARB');
-  glMultiTexCoord4dvARB := dglGetProcAddress('glMultiTexCoord4dvARB');
-  glMultiTexCoord4fARB := dglGetProcAddress('glMultiTexCoord4fARB');
-  glMultiTexCoord4fvARB := dglGetProcAddress('glMultiTexCoord4fvARB');
-  glMultiTexCoord4iARB := dglGetProcAddress('glMultiTexCoord4iARB');
-  glMultiTexCoord4ivARB := dglGetProcAddress('glMultiTexCoord4ivARB');
-  glMultiTexCoord4sARB := dglGetProcAddress('glMultiTexCoord4sARB');
-  glMultiTexCoord4svARB := dglGetProcAddress('glMultiTexCoord4svARB');
-end;
-
-procedure Read_GL_ARB_point_parameters;
-begin
-  glPointParameterfARB := dglGetProcAddress('glPointParameterfARB');
-  glPointParameterfvARB := dglGetProcAddress('glPointParameterfvARB');
-end;
-
-procedure Read_GL_ARB_texture_compression;
-begin
-  glCompressedTexImage3DARB := dglGetProcAddress('glCompressedTexImage3DARB');
-  glCompressedTexImage2DARB := dglGetProcAddress('glCompressedTexImage2DARB');
-  glCompressedTexImage1DARB := dglGetProcAddress('glCompressedTexImage1DARB');
-  glCompressedTexSubImage3DARB := dglGetProcAddress('glCompressedTexSubImage3DARB');
-  glCompressedTexSubImage2DARB := dglGetProcAddress('glCompressedTexSubImage2DARB');
-  glCompressedTexSubImage1DARB := dglGetProcAddress('glCompressedTexSubImage1DARB');
-  glGetCompressedTexImageARB := dglGetProcAddress('glGetCompressedTexImageARB');
-end;
-
-procedure Read_GL_ARB_transpose_matrix;
-begin
-  glLoadTransposeMatrixfARB := dglGetProcAddress('glLoadTransposeMatrixfARB');
-  glLoadTransposeMatrixdARB := dglGetProcAddress('glLoadTransposeMatrixdARB');
-  glMultTransposeMatrixfARB := dglGetProcAddress('glMultTransposeMatrixfARB');
-  glMultTransposeMatrixdARB := dglGetProcAddress('glMultTransposeMatrixdARB');
-end;
-
-procedure Read_GL_ARB_vertex_blend;
-begin
-  glWeightbvARB := dglGetProcAddress('glWeightbvARB');
-  glWeightsvARB := dglGetProcAddress('glWeightsvARB');
-  glWeightivARB := dglGetProcAddress('glWeightivARB');
-  glWeightfvARB := dglGetProcAddress('glWeightfvARB');
-  glWeightdvARB := dglGetProcAddress('glWeightdvARB');
-  glWeightubvARB := dglGetProcAddress('glWeightubvARB');
-  glWeightusvARB := dglGetProcAddress('glWeightusvARB');
-  glWeightuivARB := dglGetProcAddress('glWeightuivARB');
-  glWeightPointerARB := dglGetProcAddress('glWeightPointerARB');
-  glVertexBlendARB := dglGetProcAddress('glVertexBlendARB');
-end;
-
-procedure Read_GL_ARB_vertex_buffer_object;
-begin
-  glBindBufferARB := dglGetProcAddress('glBindBufferARB');
-  glDeleteBuffersARB := dglGetProcAddress('glDeleteBuffersARB');
-  glGenBuffersARB := dglGetProcAddress('glGenBuffersARB');
-  glIsBufferARB := dglGetProcAddress('glIsBufferARB');
-  glBufferDataARB := dglGetProcAddress('glBufferDataARB');
-  glBufferSubDataARB := dglGetProcAddress('glBufferSubDataARB');
-  glGetBufferSubDataARB := dglGetProcAddress('glGetBufferSubDataARB');
-  glMapBufferARB := dglGetProcAddress('glMapBufferARB');
-  glUnmapBufferARB := dglGetProcAddress('glUnmapBufferARB');
-  glGetBufferParameterivARB := dglGetProcAddress('glGetBufferParameterivARB');
-  glGetBufferPointervARB := dglGetProcAddress('glGetBufferPointervARB');
-end;
-
-procedure Read_GL_ARB_vertex_program;
-begin
-  glVertexAttrib1dARB := dglGetProcAddress('glVertexAttrib1dARB');
-  glVertexAttrib1dvARB := dglGetProcAddress('glVertexAttrib1dvARB');
-  glVertexAttrib1fARB := dglGetProcAddress('glVertexAttrib1fARB');
-  glVertexAttrib1fvARB := dglGetProcAddress('glVertexAttrib1fvARB');
-  glVertexAttrib1sARB := dglGetProcAddress('glVertexAttrib1sARB');
-  glVertexAttrib1svARB := dglGetProcAddress('glVertexAttrib1svARB');
-  glVertexAttrib2dARB := dglGetProcAddress('glVertexAttrib2dARB');
-  glVertexAttrib2dvARB := dglGetProcAddress('glVertexAttrib2dvARB');
-  glVertexAttrib2fARB := dglGetProcAddress('glVertexAttrib2fARB');
-  glVertexAttrib2fvARB := dglGetProcAddress('glVertexAttrib2fvARB');
-  glVertexAttrib2sARB := dglGetProcAddress('glVertexAttrib2sARB');
-  glVertexAttrib2svARB := dglGetProcAddress('glVertexAttrib2svARB');
-  glVertexAttrib3dARB := dglGetProcAddress('glVertexAttrib3dARB');
-  glVertexAttrib3dvARB := dglGetProcAddress('glVertexAttrib3dvARB');
-  glVertexAttrib3fARB := dglGetProcAddress('glVertexAttrib3fARB');
-  glVertexAttrib3fvARB := dglGetProcAddress('glVertexAttrib3fvARB');
-  glVertexAttrib3sARB := dglGetProcAddress('glVertexAttrib3sARB');
-  glVertexAttrib3svARB := dglGetProcAddress('glVertexAttrib3svARB');
-  glVertexAttrib4NbvARB := dglGetProcAddress('glVertexAttrib4NbvARB');
-  glVertexAttrib4NivARB := dglGetProcAddress('glVertexAttrib4NivARB');
-  glVertexAttrib4NsvARB := dglGetProcAddress('glVertexAttrib4NsvARB');
-  glVertexAttrib4NubARB := dglGetProcAddress('glVertexAttrib4NubARB');
-  glVertexAttrib4NubvARB := dglGetProcAddress('glVertexAttrib4NubvARB');
-  glVertexAttrib4NuivARB := dglGetProcAddress('glVertexAttrib4NuivARB');
-  glVertexAttrib4NusvARB := dglGetProcAddress('glVertexAttrib4NusvARB');
-  glVertexAttrib4bvARB := dglGetProcAddress('glVertexAttrib4bvARB');
-  glVertexAttrib4dARB := dglGetProcAddress('glVertexAttrib4dARB');
-  glVertexAttrib4dvARB := dglGetProcAddress('glVertexAttrib4dvARB');
-  glVertexAttrib4fARB := dglGetProcAddress('glVertexAttrib4fARB');
-  glVertexAttrib4fvARB := dglGetProcAddress('glVertexAttrib4fvARB');
-  glVertexAttrib4ivARB := dglGetProcAddress('glVertexAttrib4ivARB');
-  glVertexAttrib4sARB := dglGetProcAddress('glVertexAttrib4sARB');
-  glVertexAttrib4svARB := dglGetProcAddress('glVertexAttrib4svARB');
-  glVertexAttrib4ubvARB := dglGetProcAddress('glVertexAttrib4ubvARB');
-  glVertexAttrib4uivARB := dglGetProcAddress('glVertexAttrib4uivARB');
-  glVertexAttrib4usvARB := dglGetProcAddress('glVertexAttrib4usvARB');
-  glVertexAttribPointerARB := dglGetProcAddress('glVertexAttribPointerARB');
-  glEnableVertexAttribArrayARB := dglGetProcAddress('glEnableVertexAttribArrayARB');
-  glDisableVertexAttribArrayARB := dglGetProcAddress('glDisableVertexAttribArrayARB');
-  glProgramStringARB := dglGetProcAddress('glProgramStringARB');
-  glBindProgramARB := dglGetProcAddress('glBindProgramARB');
-  glDeleteProgramsARB := dglGetProcAddress('glDeleteProgramsARB');
-  glGenProgramsARB := dglGetProcAddress('glGenProgramsARB');
-  glProgramEnvParameter4dARB := dglGetProcAddress('glProgramEnvParameter4dARB');
-  glProgramEnvParameter4dvARB := dglGetProcAddress('glProgramEnvParameter4dvARB');
-  glProgramEnvParameter4fARB := dglGetProcAddress('glProgramEnvParameter4fARB');
-  glProgramEnvParameter4fvARB := dglGetProcAddress('glProgramEnvParameter4fvARB');
-  glProgramLocalParameter4dARB := dglGetProcAddress('glProgramLocalParameter4dARB');
-  glProgramLocalParameter4dvARB := dglGetProcAddress('glProgramLocalParameter4dvARB');
-  glProgramLocalParameter4fARB := dglGetProcAddress('glProgramLocalParameter4fARB');
-  glProgramLocalParameter4fvARB := dglGetProcAddress('glProgramLocalParameter4fvARB');
-  glGetProgramEnvParameterdvARB := dglGetProcAddress('glGetProgramEnvParameterdvARB');
-  glGetProgramEnvParameterfvARB := dglGetProcAddress('glGetProgramEnvParameterfvARB');
-  glGetProgramLocalParameterdvARB := dglGetProcAddress('glGetProgramLocalParameterdvARB');
-  glGetProgramLocalParameterfvARB := dglGetProcAddress('glGetProgramLocalParameterfvARB');
-  glGetProgramivARB := dglGetProcAddress('glGetProgramivARB');
-  glGetProgramStringARB := dglGetProcAddress('glGetProgramStringARB');
-  glGetVertexAttribdvARB := dglGetProcAddress('glGetVertexAttribdvARB');
-  glGetVertexAttribfvARB := dglGetProcAddress('glGetVertexAttribfvARB');
-  glGetVertexAttribivARB := dglGetProcAddress('glGetVertexAttribivARB');
-  glGetVertexAttribPointervARB := dglGetProcAddress('glGetVertexAttribPointervARB');
-  glIsProgramARB := dglGetProcAddress('glIsProgramARB');
-end;
-
-procedure Read_GL_ARB_window_pos;
-begin
-  glWindowPos2dARB := dglGetProcAddress('glWindowPos2dARB');
-  glWindowPos2dvARB := dglGetProcAddress('glWindowPos2dvARB');
-  glWindowPos2fARB := dglGetProcAddress('glWindowPos2fARB');
-  glWindowPos2fvARB := dglGetProcAddress('glWindowPos2fvARB');
-  glWindowPos2iARB := dglGetProcAddress('glWindowPos2iARB');
-  glWindowPos2ivARB := dglGetProcAddress('glWindowPos2ivARB');
-  glWindowPos2sARB := dglGetProcAddress('glWindowPos2sARB');
-  glWindowPos2svARB := dglGetProcAddress('glWindowPos2svARB');
-  glWindowPos3dARB := dglGetProcAddress('glWindowPos3dARB');
-  glWindowPos3dvARB := dglGetProcAddress('glWindowPos3dvARB');
-  glWindowPos3fARB := dglGetProcAddress('glWindowPos3fARB');
-  glWindowPos3fvARB := dglGetProcAddress('glWindowPos3fvARB');
-  glWindowPos3iARB := dglGetProcAddress('glWindowPos3iARB');
-  glWindowPos3ivARB := dglGetProcAddress('glWindowPos3ivARB');
-  glWindowPos3sARB := dglGetProcAddress('glWindowPos3sARB');
-  glWindowPos3svARB := dglGetProcAddress('glWindowPos3svARB');
-end;
-
-procedure Read_GL_ARB_draw_buffers;
-begin
-  glDrawBuffersARB := dglGetProcAddress('glDrawBuffersARB');
-end;
-
-procedure Read_GL_ARB_color_buffer_float;
-begin
-  glClampColorARB := dglGetProcAddress('glClampColorARB');
-end;
-
-procedure Read_GL_ARB_Shader_Objects;
-begin
-  // GL_ARB_Shader_Objects
-  glCreateShaderObjectARB := dglGetProcAddress('glCreateShaderObjectARB');
-  glShaderSourceARB := dglGetProcAddress('glShaderSourceARB');
-  glCompileShaderARB := dglGetProcAddress('glCompileShaderARB');
-  glDeleteObjectARB := dglGetProcAddress('glDeleteObjectARB');
-  glGetHandleARB := dglGetProcAddress('glGetHandleARB');
-  glDetachObjectARB := dglGetProcAddress('glDetachObjectARB');
-  glCreateProgramObjectARB := dglGetProcAddress('glCreateProgramObjectARB');
-  glAttachObjectARB := dglGetProcAddress('glAttachObjectARB');
-  glLinkProgramARB := dglGetProcAddress('glLinkProgramARB');
-  glUseProgramObjectARB := dglGetProcAddress('glUseProgramObjectARB');
-  glValidateProgramARB := dglGetProcAddress('glValidateProgramARB');
-  glGetObjectParameterfvARB := dglGetProcAddress('glGetObjectParameterfvARB');
-  glGetObjectParameterivARB := dglGetProcAddress('glGetObjectParameterivARB');
-  glGetActiveUniformARB := dglGetProcAddress('glGetActiveUniformARB');
-  glGetAttachedObjectsARB := dglGetProcAddress('glGetAttachedObjectsARB');
-  glGetShaderSourceARB := dglGetProcAddress('glGetShaderSourceARB');
-  glGetUniformfvARB := dglGetProcAddress('glGetUniformfvARB');
-  glGetUniformivARB := dglGetProcAddress('glGetUniformivARB');
-  glGetUniformLocationARB := dglGetProcAddress('glGetUniformLocationARB');
-  glGetInfoLogARB := dglGetProcAddress('glGetInfoLogARB');
-  glUniform1fARB := dglGetProcAddress('glUniform1fARB');
-  glUniform2fARB := dglGetProcAddress('glUniform2fARB');
-  glUniform3fARB := dglGetProcAddress('glUniform3fARB');
-  glUniform4fARB := dglGetProcAddress('glUniform4fARB');
-  glUniform1iARB := dglGetProcAddress('glUniform1iARB');
-  glUniform2iARB := dglGetProcAddress('glUniform2iARB');
-  glUniform3iARB := dglGetProcAddress('glUniform3iARB');
-  glUniform4iARB := dglGetProcAddress('glUniform4iARB');
-  glUniform1fvARB := dglGetProcAddress('glUniform1fvARB');
-  glUniform2fvARB := dglGetProcAddress('glUniform2fvARB');
-  glUniform3fvARB := dglGetProcAddress('glUniform3fvARB');
-  glUniform4fvARB := dglGetProcAddress('glUniform4fvARB');
-  glUniform1ivARB := dglGetProcAddress('glUniform1ivARB');
-  glUniform2ivARB := dglGetProcAddress('glUniform2ivARB');
-  glUniform3ivARB := dglGetProcAddress('glUniform3ivARB');
-  glUniform4ivARB := dglGetProcAddress('glUniform4ivARB');
-  glUniformMatrix2fvARB := dglGetProcAddress('glUniformMatrix2fvARB');
-  glUniformMatrix3fvARB := dglGetProcAddress('glUniformMatrix3fvARB');
-  glUniformMatrix4fvARB := dglGetProcAddress('glUniformMatrix4fvARB');
-
-  // GL_ARB_vertex_shader
-  glGetActiveAttribARB := dglGetProcAddress('glGetActiveAttribARB');
-  glGetAttribLocationARB := dglGetProcAddress('glGetAttribLocationARB');
-  glBindAttribLocationARB := dglGetProcAddress('glBindAttribLocationARB');
-  glGetVertexAttribPointervARB := dglGetProcAddress('glGetVertexAttribPointervARB');
-end;
-
-procedure Read_GL_ARB_occlusion_query;
-begin
-  glGenQueriesARB := dglGetProcAddress('glGenQueriesARB');
-  glDeleteQueriesARB := dglGetProcAddress('glDeleteQueriesARB');
-  glIsQueryARB := dglGetProcAddress('glIsQueryARB');
-  glBeginQueryARB := dglGetProcAddress('glBeginQueryARB');
-  glEndQueryARB := dglGetProcAddress('glEndQueryARB');
-  glGetQueryivARB := dglGetProcAddress('glGetQueryivARB');
-  glGetQueryObjectivARB := dglGetProcAddress('glGetQueryObjectivARB');
-  glGetQueryObjectuivARB := dglGetProcAddress('glGetQueryObjectuivARB');
-end;
-
-procedure Read_GL_ARB_draw_instanced;
-begin
-  glDrawArraysInstancedARB := dglGetProcAddress('glDrawArraysInstancedARB');
-  glDrawElementsInstancedARB := dglGetProcAddress('glDrawElementsInstancedARB');
-end;
-
-procedure Read_GL_ARB_framebuffer_object;
-begin
-  glIsRenderbuffer := dglGetProcAddress('glIsRenderbuffer');
-  glBindRenderbuffer := dglGetProcAddress('glBindRenderbuffer');
-  glDeleteRenderbuffers := dglGetProcAddress('glDeleteRenderbuffers');
-  glGenRenderbuffers := dglGetProcAddress('glGenRenderbuffers');
-  glRenderbufferStorage := dglGetProcAddress('glRenderbufferStorage');
-  glGetRenderbufferParameteriv := dglGetProcAddress('glGetRenderbufferParameteriv');
-  glIsFramebuffer := dglGetProcAddress('glIsFramebuffer');
-  glBindFramebuffer := dglGetProcAddress('glBindFramebuffer');
-  glDeleteFramebuffers := dglGetProcAddress('glDeleteFramebuffers');
-  glGenFramebuffers := dglGetProcAddress('glGenFramebuffers');
-  glCheckFramebufferStatus := dglGetProcAddress('glCheckFramebufferStatus');
-  glFramebufferTexture1D := dglGetProcAddress('glFramebufferTexture1D');
-  glFramebufferTexture2D := dglGetProcAddress('glFramebufferTexture2D');
-  glFramebufferTexture3D := dglGetProcAddress('glFramebufferTexture3D');
-  glFramebufferRenderbuffer := dglGetProcAddress('glFramebufferRenderbuffer');
-  glGetFramebufferAttachmentParameteriv := dglGetProcAddress('glGetFramebufferAttachmentParameteriv');
-  glGenerateMipmap := dglGetProcAddress('glGenerateMipmap');
-  glBlitFramebuffer := dglGetProcAddress('glBlitFramebuffer');
-  glRenderbufferStorageMultisample := dglGetProcAddress('glRenderbufferStorageMultisample');
-  glFramebufferTextureLayer := dglGetProcAddress('glFramebufferTextureLayer');
-end;
-
-procedure Read_GL_ARB_geometry_shader4;
-begin
-  glProgramParameteriARB := dglGetProcAddress('glProgramParameteriARB');
-  glFramebufferTextureARB := dglGetProcAddress('glFramebufferTextureARB');
-  glFramebufferTextureLayerARB := dglGetProcAddress('glFramebufferTextureLayerARB');
-  glFramebufferTextureFaceARB := dglGetProcAddress('glFramebufferTextureFaceARB');
-end;
-
-procedure Read_GL_ARB_instanced_arrays;
-begin
-  glVertexAttribDivisorARB := dglGetProcAddress('glVertexAttribDivisorARB');
-end;
-
-procedure Read_GL_ARB_map_buffer_range;
-begin
-  glMapBufferRange := dglGetProcAddress('glMapBufferRange');
-  glFlushMappedBufferRange := dglGetProcAddress('glFlushMappedBufferRange');
-end;
-
-procedure Read_GL_ARB_texture_buffer_object;
-begin
-  glTexBufferARB := dglGetProcAddress('glTexBufferARB');
-end;
-
-procedure Read_GL_ARB_vertex_array_object;
-begin
-  glBindVertexArray := dglGetProcAddress('glBindVertexArray');
-  glDeleteVertexArrays := dglGetProcAddress('glDeleteVertexArrays');
-  glGenVertexArrays := dglGetProcAddress('glGenVertexArrays');
-  glIsVertexArray := dglGetProcAddress('glIsVertexArray');
-end;
-
-procedure Read_GL_ARB_uniform_buffer_object;
-begin
-  glGetUniformIndices := dglGetProcAddress('glGetUniformIndices');
-  glGetActiveUniformsiv := dglGetProcAddress('glGetActiveUniformsiv');
-  glGetActiveUniformName := dglGetProcAddress('glGetActiveUniformName');
-  glGetUniformBlockIndex := dglGetProcAddress('glGetUniformBlockIndex');
-  glGetActiveUniformBlockiv := dglGetProcAddress('glGetActiveUniformBlockiv');
-  glGetActiveUniformBlockName := dglGetProcAddress('glGetActiveUniformBlockName');
-  glUniformBlockBinding := dglGetProcAddress('glUniformBlockBinding');
-end;
-
-procedure Read_GL_ARB_copy_buffer;
-begin
-  glCopyBufferSubData := dglGetProcAddress('glCopyBufferSubData');
-end;
-
-procedure Read_GL_ARB_draw_elements_base_vertex;
-begin
-  glDrawElementsBaseVertex := dglGetProcAddress('glDrawElementsBaseVertex');
-  glDrawRangeElementsBaseVertex := dglGetProcAddress('glDrawRangeElementsBaseVertex');
-  glDrawElementsInstancedBaseVertex := dglGetProcAddress('glDrawElementsInstancedBaseVertex');
-  glMultiDrawElementsBaseVertex := dglGetProcAddress('glMultiDrawElementsBaseVertex');
-end;
-
-procedure Read_GL_ARB_provoking_vertex;
-begin
-  glProvokingVertex := dglGetProcAddress('glProvokingVertex');
-end;
-
-procedure Read_GL_ARB_sync;
-begin
-  glFenceSync := dglGetProcAddress('glFenceSync');
-  glIsSync := dglGetProcAddress('glIsSync');
-  glDeleteSync := dglGetProcAddress('glDeleteSync');
-  glClientWaitSync := dglGetProcAddress('glClientWaitSync');
-  glWaitSync := dglGetProcAddress('glWaitSync');
-  glGetInteger64v := dglGetProcAddress('glGetInteger64v');
-  glGetSynciv := dglGetProcAddress('glGetSynciv');
-end;
-
-procedure Read_GL_ARB_texture_multisample;
-begin
-  glTexImage2DMultisample := dglGetProcAddress('glTexImage2DMultisample');
-  glTexImage3DMultisample := dglGetProcAddress('glTexImage3DMultisample');
-  glGetMultisamplefv := dglGetProcAddress('glGetMultisamplefv');
-  glSampleMaski := dglGetProcAddress('glSampleMaski');
-end;
-
-procedure Read_GL_ARB_draw_buffers_blend;
-begin
-  glBlendEquationi := dglGetProcAddress('glBlendEquationi');
-  glBlendEquationSeparatei := dglGetProcAddress('glBlendEquationSeparatei');
-  glBlendFunci := dglGetProcAddress('glBlendFunci');
-  glBlendFuncSeparatei := dglGetProcAddress('glBlendFuncSeparatei');
-end;
-
-procedure Read_GL_ARB_sample_shading;
-begin
-  glMinSampleShading := dglGetProcAddress('glMinSampleShading');;
-end;
-
-procedure Read_GL_ATI_draw_buffers;
-begin
-  glDrawBuffersATI := dglGetProcAddress('glDrawBuffersATI');
-end;
-
-procedure Read_GL_ATI_element_array;
-begin
-  glElementPointerATI := dglGetProcAddress('glElementPointerATI');
-  glDrawElementArrayATI := dglGetProcAddress('glDrawElementArrayATI');
-  glDrawRangeElementArrayATI := dglGetProcAddress('glDrawRangeElementArrayATI');
-end;
-
-procedure Read_GL_ATI_envmap_bumpmap;
-begin
-  glTexBumpParameterivATI := dglGetProcAddress('glTexBumpParameterivATI');
-  glTexBumpParameterfvATI := dglGetProcAddress('glTexBumpParameterfvATI');
-  glGetTexBumpParameterivATI := dglGetProcAddress('glGetTexBumpParameterivATI');
-  glGetTexBumpParameterfvATI := dglGetProcAddress('glGetTexBumpParameterfvATI');
-end;
-
-procedure Read_GL_ATI_fragment_shader;
-begin
-  glGenFragmentShadersATI := dglGetProcAddress('glGenFragmentShadersATI');
-  glBindFragmentShaderATI := dglGetProcAddress('glBindFragmentShaderATI');
-  glDeleteFragmentShaderATI := dglGetProcAddress('glDeleteFragmentShaderATI');
-  glBeginFragmentShaderATI := dglGetProcAddress('glBeginFragmentShaderATI');
-  glEndFragmentShaderATI := dglGetProcAddress('glEndFragmentShaderATI');
-  glPassTexCoordATI := dglGetProcAddress('glPassTexCoordATI');
-  glSampleMapATI := dglGetProcAddress('glSampleMapATI');
-  glColorFragmentOp1ATI := dglGetProcAddress('glColorFragmentOp1ATI');
-  glColorFragmentOp2ATI := dglGetProcAddress('glColorFragmentOp2ATI');
-  glColorFragmentOp3ATI := dglGetProcAddress('glColorFragmentOp3ATI');
-  glAlphaFragmentOp1ATI := dglGetProcAddress('glAlphaFragmentOp1ATI');
-  glAlphaFragmentOp2ATI := dglGetProcAddress('glAlphaFragmentOp2ATI');
-  glAlphaFragmentOp3ATI := dglGetProcAddress('glAlphaFragmentOp3ATI');
-  glSetFragmentShaderConstantATI := dglGetProcAddress('glSetFragmentShaderConstantATI');
-end;
-
-procedure Read_GL_ATI_map_object_buffer;
-begin
-  glMapObjectBufferATI := dglGetProcAddress('glMapObjectBufferATI');
-  glUnmapObjectBufferATI := dglGetProcAddress('glUnmapObjectBufferATI');
-end;
-
-procedure Read_GL_ATI_pn_triangles;
-begin
-  glPNTrianglesiATI := dglGetProcAddress('glPNTrianglesiATI');
-  glPNTrianglesfATI := dglGetProcAddress('glPNTrianglesfATI');
-end;
-
-procedure Read_GL_ATI_separate_stencil;
-begin
-  glStencilOpSeparateATI := dglGetProcAddress('glStencilOpSeparateATI');
-  glStencilFuncSeparateATI := dglGetProcAddress('glStencilFuncSeparateATI');
-end;
-
-procedure Read_GL_ATI_vertex_array_object;
-begin
-  glNewObjectBufferATI := dglGetProcAddress('glNewObjectBufferATI');
-  glIsObjectBufferATI := dglGetProcAddress('glIsObjectBufferATI');
-  glUpdateObjectBufferATI := dglGetProcAddress('glUpdateObjectBufferATI');
-  glGetObjectBufferfvATI := dglGetProcAddress('glGetObjectBufferfvATI');
-  glGetObjectBufferivATI := dglGetProcAddress('glGetObjectBufferivATI');
-  glFreeObjectBufferATI := dglGetProcAddress('glFreeObjectBufferATI');
-  glArrayObjectATI := dglGetProcAddress('glArrayObjectATI');
-  glGetArrayObjectfvATI := dglGetProcAddress('glGetArrayObjectfvATI');
-  glGetArrayObjectivATI := dglGetProcAddress('glGetArrayObjectivATI');
-  glVariantArrayObjectATI := dglGetProcAddress('glVariantArrayObjectATI');
-  glGetVariantArrayObjectfvATI := dglGetProcAddress('glGetVariantArrayObjectfvATI');
-  glGetVariantArrayObjectivATI := dglGetProcAddress('glGetVariantArrayObjectivATI');
-
-end;
-
-procedure Read_GL_ATI_vertex_attrib_array_object;
-begin
-  glVertexAttribArrayObjectATI := dglGetProcAddress('glVertexAttribArrayObjectATI');
-  glGetVertexAttribArrayObjectfvATI := dglGetProcAddress('glGetVertexAttribArrayObjectfvATI');
-  glGetVertexAttribArrayObjectivATI := dglGetProcAddress('glGetVertexAttribArrayObjectivATI');
-end;
-
-procedure Read_GL_ATI_vertex_streams;
-begin
-  glVertexStream1sATI := dglGetProcAddress('glVertexStream1sATI');
-  glVertexStream1svATI := dglGetProcAddress('glVertexStream1svATI');
-  glVertexStream1iATI := dglGetProcAddress('glVertexStream1iATI');
-  glVertexStream1ivATI := dglGetProcAddress('glVertexStream1ivATI');
-  glVertexStream1fATI := dglGetProcAddress('glVertexStream1fATI');
-  glVertexStream1fvATI := dglGetProcAddress('glVertexStream1fvATI');
-  glVertexStream1dATI := dglGetProcAddress('glVertexStream1dATI');
-  glVertexStream1dvATI := dglGetProcAddress('glVertexStream1dvATI');
-  glVertexStream2sATI := dglGetProcAddress('glVertexStream2sATI');
-  glVertexStream2svATI := dglGetProcAddress('glVertexStream2svATI');
-  glVertexStream2iATI := dglGetProcAddress('glVertexStream2iATI');
-  glVertexStream2ivATI := dglGetProcAddress('glVertexStream2ivATI');
-  glVertexStream2fATI := dglGetProcAddress('glVertexStream2fATI');
-  glVertexStream2fvATI := dglGetProcAddress('glVertexStream2fvATI');
-  glVertexStream2dATI := dglGetProcAddress('glVertexStream2dATI');
-  glVertexStream2dvATI := dglGetProcAddress('glVertexStream2dvATI');
-  glVertexStream3sATI := dglGetProcAddress('glVertexStream3sATI');
-  glVertexStream3svATI := dglGetProcAddress('glVertexStream3svATI');
-  glVertexStream3iATI := dglGetProcAddress('glVertexStream3iATI');
-  glVertexStream3ivATI := dglGetProcAddress('glVertexStream3ivATI');
-  glVertexStream3fATI := dglGetProcAddress('glVertexStream3fATI');
-  glVertexStream3fvATI := dglGetProcAddress('glVertexStream3fvATI');
-  glVertexStream3dATI := dglGetProcAddress('glVertexStream3dATI');
-  glVertexStream3dvATI := dglGetProcAddress('glVertexStream3dvATI');
-  glVertexStream4sATI := dglGetProcAddress('glVertexStream4sATI');
-  glVertexStream4svATI := dglGetProcAddress('glVertexStream4svATI');
-  glVertexStream4iATI := dglGetProcAddress('glVertexStream4iATI');
-  glVertexStream4ivATI := dglGetProcAddress('glVertexStream4ivATI');
-  glVertexStream4fATI := dglGetProcAddress('glVertexStream4fATI');
-  glVertexStream4fvATI := dglGetProcAddress('glVertexStream4fvATI');
-  glVertexStream4dATI := dglGetProcAddress('glVertexStream4dATI');
-  glVertexStream4dvATI := dglGetProcAddress('glVertexStream4dvATI');
-  glNormalStream3bATI := dglGetProcAddress('glNormalStream3bATI');
-  glNormalStream3bvATI := dglGetProcAddress('glNormalStream3bvATI');
-  glNormalStream3sATI := dglGetProcAddress('glNormalStream3sATI');
-  glNormalStream3svATI := dglGetProcAddress('glNormalStream3svATI');
-  glNormalStream3iATI := dglGetProcAddress('glNormalStream3iATI');
-  glNormalStream3ivATI := dglGetProcAddress('glNormalStream3ivATI');
-  glNormalStream3fATI := dglGetProcAddress('glNormalStream3fATI');
-  glNormalStream3fvATI := dglGetProcAddress('glNormalStream3fvATI');
-  glNormalStream3dATI := dglGetProcAddress('glNormalStream3dATI');
-  glNormalStream3dvATI := dglGetProcAddress('glNormalStream3dvATI');
-  glClientActiveVertexStreamATI := dglGetProcAddress('glClientActiveVertexStreamATI');
-  glVertexBlendEnviATI := dglGetProcAddress('glVertexBlendEnviATI');
-  glVertexBlendEnvfATI := dglGetProcAddress('glVertexBlendEnvfATI');
-end;
-
-procedure Read_GL_AMD_performance_monitor;
-begin
-  glGetPerfMonitorGroupsAMD := dglGetProcAddress('glGetPerfMonitorGroupsAMD');
-  glGetPerfMonitorCountersAMD := dglGetProcAddress('glGetPerfMonitorCountersAMD');
-  glGetPerfMonitorGroupStringAMD := dglGetProcAddress('glGetPerfMonitorGroupStringAMD');
-  glGetPerfMonitorCounterStringAMD := dglGetProcAddress('glGetPerfMonitorCounterStringAMD');
-  glGetPerfMonitorCounterInfoAMD := dglGetProcAddress('glGetPerfMonitorCounterInfoAMD');
-  glGenPerfMonitorsAMD := dglGetProcAddress('glGenPerfMonitorsAMD');
-  glDeletePerfMonitorsAMD := dglGetProcAddress('glDeletePerfMonitorsAMD');
-  glSelectPerfMonitorCountersAMD := dglGetProcAddress('glSelectPerfMonitorCountersAMD');
-  glBeginPerfMonitorAMD := dglGetProcAddress('glBeginPerfMonitorAMD');
-  glEndPerfMonitorAMD := dglGetProcAddress('glEndPerfMonitorAMD');
-  glGetPerfMonitorCounterDataAMD := dglGetProcAddress('glGetPerfMonitorCounterDataAMD');
-end;
-
-procedure Read_GL_EXT_blend_color;
-begin
-  glBlendColorEXT := dglGetProcAddress('glBlendColorEXT');
-end;
-
-procedure Read_GL_EXT_blend_func_separate;
-begin
-  glBlendFuncSeparateEXT := dglGetProcAddress('glBlendFuncSeparateEXT');
-end;
-
-procedure Read_GL_EXT_blend_minmax;
-begin
-  glBlendEquationEXT := dglGetProcAddress('glBlendEquationEXT');
-end;
-
-procedure Read_GL_EXT_color_subtable;
-begin
-  glColorSubTableEXT := dglGetProcAddress('glColorSubTableEXT');
-  glCopyColorSubTableEXT := dglGetProcAddress('glCopyColorSubTableEXT');
-end;
-
-procedure Read_GL_EXT_compiled_vertex_array;
-begin
-  glLockArraysEXT := dglGetProcAddress('glLockArraysEXT');
-  glUnlockArraysEXT := dglGetProcAddress('glUnlockArraysEXT');
-end;
-
-procedure Read_GL_EXT_convolution;
-begin
-  glConvolutionFilter1DEXT := dglGetProcAddress('glConvolutionFilter1DEXT');
-  glConvolutionFilter2DEXT := dglGetProcAddress('glConvolutionFilter2DEXT');
-  glConvolutionParameterfEXT := dglGetProcAddress('glConvolutionParameterfEXT');
-  glConvolutionParameterfvEXT := dglGetProcAddress('glConvolutionParameterfvEXT');
-  glConvolutionParameteriEXT := dglGetProcAddress('glConvolutionParameteriEXT');
-  glConvolutionParameterivEXT := dglGetProcAddress('glConvolutionParameterivEXT');
-  glCopyConvolutionFilter1DEXT := dglGetProcAddress('glCopyConvolutionFilter1DEXT');
-  glCopyConvolutionFilter2DEXT := dglGetProcAddress('glCopyConvolutionFilter2DEXT');
-  glGetConvolutionFilterEXT := dglGetProcAddress('glGetConvolutionFilterEXT');
-  glGetConvolutionParameterfvEXT := dglGetProcAddress('glGetConvolutionParameterfvEXT');
-  glGetConvolutionParameterivEXT := dglGetProcAddress('glGetConvolutionParameterivEXT');
-  glGetSeparableFilterEXT := dglGetProcAddress('glGetSeparableFilterEXT');
-  glSeparableFilter2DEXT := dglGetProcAddress('glSeparableFilter2DEXT');
-end;
-
-procedure Read_GL_EXT_coordinate_frame;
-begin
-  glTangent3bEXT := dglGetProcAddress('glTangent3bEXT');
-  glTangent3bvEXT := dglGetProcAddress('glTangent3bvEXT');
-  glTangent3dEXT := dglGetProcAddress('glTangent3dEXT');
-  glTangent3dvEXT := dglGetProcAddress('glTangent3dvEXT');
-  glTangent3fEXT := dglGetProcAddress('glTangent3fEXT');
-  glTangent3fvEXT := dglGetProcAddress('glTangent3fvEXT');
-  glTangent3iEXT := dglGetProcAddress('glTangent3iEXT');
-  glTangent3ivEXT := dglGetProcAddress('glTangent3ivEXT');
-  glTangent3sEXT := dglGetProcAddress('glTangent3sEXT');
-  glTangent3svEXT := dglGetProcAddress('glTangent3svEXT');
-  glBinormal3bEXT := dglGetProcAddress('glBinormal3bEXT');
-  glBinormal3bvEXT := dglGetProcAddress('glBinormal3bvEXT');
-  glBinormal3dEXT := dglGetProcAddress('glBinormal3dEXT');
-  glBinormal3dvEXT := dglGetProcAddress('glBinormal3dvEXT');
-  glBinormal3fEXT := dglGetProcAddress('glBinormal3fEXT');
-  glBinormal3fvEXT := dglGetProcAddress('glBinormal3fvEXT');
-  glBinormal3iEXT := dglGetProcAddress('glBinormal3iEXT');
-  glBinormal3ivEXT := dglGetProcAddress('glBinormal3ivEXT');
-  glBinormal3sEXT := dglGetProcAddress('glBinormal3sEXT');
-  glBinormal3svEXT := dglGetProcAddress('glBinormal3svEXT');
-  glTangentPointerEXT := dglGetProcAddress('glTangentPointerEXT');
-  glBinormalPointerEXT := dglGetProcAddress('glBinormalPointerEXT');
-end;
-
-procedure Read_GL_EXT_copy_texture;
-begin
-  glCopyTexImage1DEXT := dglGetProcAddress('glCopyTexImage1DEXT');
-  glCopyTexImage2DEXT := dglGetProcAddress('glCopyTexImage2DEXT');
-  glCopyTexSubImage1DEXT := dglGetProcAddress('glCopyTexSubImage1DEXT');
-  glCopyTexSubImage2DEXT := dglGetProcAddress('glCopyTexSubImage2DEXT');
-  glCopyTexSubImage3DEXT := dglGetProcAddress('glCopyTexSubImage3DEXT');
-end;
-
-procedure Read_GL_EXT_cull_vertex;
-begin
-  glCullParameterdvEXT := dglGetProcAddress('glCullParameterdvEXT');
-  glCullParameterfvEXT := dglGetProcAddress('glCullParameterfvEXT');
-end;
-
-procedure Read_GL_EXT_draw_range_elements;
-begin
-  glDrawRangeElementsEXT := dglGetProcAddress('glDrawRangeElementsEXT');
-end;
-
-procedure Read_GL_EXT_fog_coord;
-begin
-  glFogCoordfEXT := dglGetProcAddress('glFogCoordfEXT');
-  glFogCoordfvEXT := dglGetProcAddress('glFogCoordfvEXT');
-  glFogCoorddEXT := dglGetProcAddress('glFogCoorddEXT');
-  glFogCoorddvEXT := dglGetProcAddress('glFogCoorddvEXT');
-  glFogCoordPointerEXT := dglGetProcAddress('glFogCoordPointerEXT');
-end;
-
-procedure Read_GL_EXT_framebuffer_object;
-begin
-  glIsRenderbufferEXT := dglGetProcAddress('glIsRenderbufferEXT');
-  glBindRenderbufferEXT := dglGetProcAddress('glBindRenderbufferEXT');
-  glDeleteRenderbuffersEXT := dglGetProcAddress('glDeleteRenderbuffersEXT');
-  glGenRenderbuffersEXT := dglGetProcAddress('glGenRenderbuffersEXT');
-  glRenderbufferStorageEXT := dglGetProcAddress('glRenderbufferStorageEXT');
-  glGetRenderbufferParameterivEXT := dglGetProcAddress('glGetRenderbufferParameterivEXT');
-  glIsFramebufferEXT := dglGetProcAddress('glIsFramebufferEXT');
-  glBindFramebufferEXT := dglGetProcAddress('glBindFramebufferEXT');
-  glDeleteFramebuffersEXT := dglGetProcAddress('glDeleteFramebuffersEXT');
-  glGenFramebuffersEXT := dglGetProcAddress('glGenFramebuffersEXT');
-  glCheckFramebufferStatusEXT := dglGetProcAddress('glCheckFramebufferStatusEXT');
-  glFramebufferTexture1DEXT := dglGetProcAddress('glFramebufferTexture1DEXT');
-  glFramebufferTexture2DEXT := dglGetProcAddress('glFramebufferTexture2DEXT');
-  glFramebufferTexture3DEXT := dglGetProcAddress('glFramebufferTexture3DEXT');
-  glFramebufferRenderbufferEXT := dglGetProcAddress('glFramebufferRenderbufferEXT');
-  glGetFramebufferAttachmentParameterivEXT := dglGetProcAddress('glGetFramebufferAttachmentParameterivEXT');
-  glGenerateMipmapEXT := dglGetProcAddress('glGenerateMipmapEXT');
-end;
-
-procedure Read_GL_EXT_histogram;
-begin
-  glGetHistogramEXT := dglGetProcAddress('glGetHistogramEXT');
-  glGetHistogramParameterfvEXT := dglGetProcAddress('glGetHistogramParameterfvEXT');
-  glGetHistogramParameterivEXT := dglGetProcAddress('glGetHistogramParameterivEXT');
-  glGetMinmaxEXT := dglGetProcAddress('glGetMinmaxEXT');
-  glGetMinmaxParameterfvEXT := dglGetProcAddress('glGetMinmaxParameterfvEXT');
-  glGetMinmaxParameterivEXT := dglGetProcAddress('glGetMinmaxParameterivEXT');
-  glHistogramEXT := dglGetProcAddress('glHistogramEXT');
-  glMinmaxEXT := dglGetProcAddress('glMinmaxEXT');
-  glResetHistogramEXT := dglGetProcAddress('glResetHistogramEXT');
-  glResetMinmaxEXT := dglGetProcAddress('glResetMinmaxEXT');
-end;
-
-procedure Read_GL_EXT_index_func;
-begin
-  glIndexFuncEXT := dglGetProcAddress('glIndexFuncEXT');
-end;
-
-procedure Read_GL_EXT_index_material;
-begin
-  glIndexMaterialEXT := dglGetProcAddress('glIndexMaterialEXT');
-end;
-
-procedure Read_GL_EXT_light_texture;
-begin
-  glApplyTextureEXT := dglGetProcAddress('glApplyTextureEXT');
-  glTextureLightEXT := dglGetProcAddress('glTextureLightEXT');
-  glTextureMaterialEXT := dglGetProcAddress('glTextureMaterialEXT');
-end;
-
-procedure Read_GL_EXT_multi_draw_arrays;
-begin
-  glMultiDrawArraysEXT := dglGetProcAddress('glMultiDrawArraysEXT');
-  glMultiDrawElementsEXT := dglGetProcAddress('glMultiDrawElementsEXT');
-end;
-
-procedure Read_GL_EXT_multisample;
-begin
-  glSampleMaskEXT := dglGetProcAddress('glSampleMaskEXT');
-  glSamplePatternEXT := dglGetProcAddress('glSamplePatternEXT');
-end;
-
-procedure Read_GL_EXT_paletted_texture;
-begin
-  glColorTableEXT := dglGetProcAddress('glColorTableEXT');
-  glGetColorTableEXT := dglGetProcAddress('glGetColorTableEXT');
-  glGetColorTableParameterivEXT := dglGetProcAddress('glGetColorTableParameterivEXT');
-  glGetColorTableParameterfvEXT := dglGetProcAddress('glGetColorTableParameterfvEXT');
-end;
-
-procedure Read_GL_EXT_pixel_transform;
-begin
-  glPixelTransformParameteriEXT := dglGetProcAddress('glPixelTransformParameteriEXT');
-  glPixelTransformParameterfEXT := dglGetProcAddress('glPixelTransformParameterfEXT');
-  glPixelTransformParameterivEXT := dglGetProcAddress('glPixelTransformParameterivEXT');
-  glPixelTransformParameterfvEXT := dglGetProcAddress('glPixelTransformParameterfvEXT');
-end;
-
-procedure Read_GL_EXT_point_parameters;
-begin
-  glPointParameterfEXT := dglGetProcAddress('glPointParameterfEXT');
-  glPointParameterfvEXT := dglGetProcAddress('glPointParameterfvEXT');
-end;
-
-procedure Read_GL_EXT_polygon_offset;
-begin
-  glPolygonOffsetEXT := dglGetProcAddress('glPolygonOffsetEXT');
-end;
-
-procedure Read_GL_EXT_secondary_color;
-begin
-  glSecondaryColor3bEXT := dglGetProcAddress('glSecondaryColor3bEXT');
-  glSecondaryColor3bvEXT := dglGetProcAddress('glSecondaryColor3bvEXT');
-  glSecondaryColor3dEXT := dglGetProcAddress('glSecondaryColor3dEXT');
-  glSecondaryColor3dvEXT := dglGetProcAddress('glSecondaryColor3dvEXT');
-  glSecondaryColor3fEXT := dglGetProcAddress('glSecondaryColor3fEXT');
-  glSecondaryColor3fvEXT := dglGetProcAddress('glSecondaryColor3fvEXT');
-  glSecondaryColor3iEXT := dglGetProcAddress('glSecondaryColor3iEXT');
-  glSecondaryColor3ivEXT := dglGetProcAddress('glSecondaryColor3ivEXT');
-  glSecondaryColor3sEXT := dglGetProcAddress('glSecondaryColor3sEXT');
-  glSecondaryColor3svEXT := dglGetProcAddress('glSecondaryColor3svEXT');
-  glSecondaryColor3ubEXT := dglGetProcAddress('glSecondaryColor3ubEXT');
-  glSecondaryColor3ubvEXT := dglGetProcAddress('glSecondaryColor3ubvEXT');
-  glSecondaryColor3uiEXT := dglGetProcAddress('glSecondaryColor3uiEXT');
-  glSecondaryColor3uivEXT := dglGetProcAddress('glSecondaryColor3uivEXT');
-  glSecondaryColor3usEXT := dglGetProcAddress('glSecondaryColor3usEXT');
-  glSecondaryColor3usvEXT := dglGetProcAddress('glSecondaryColor3usvEXT');
-  glSecondaryColorPointerEXT := dglGetProcAddress('glSecondaryColorPointerEXT');
-end;
-
-procedure Read_GL_EXT_stencil_two_side;
-begin
-  glActiveStencilFaceEXT := dglGetProcAddress('glActiveStencilFaceEXT');
-end;
-
-procedure Read_GL_EXT_subtexture;
-begin
-  glTexSubImage1DEXT := dglGetProcAddress('glTexSubImage1DEXT');
-  glTexSubImage2DEXT := dglGetProcAddress('glTexSubImage2DEXT');
-end;
-
-procedure Read_GL_EXT_texture3D;
-begin
-  glTexImage3DEXT := dglGetProcAddress('glTexImage3DEXT');
-  glTexSubImage3DEXT := dglGetProcAddress('glTexSubImage3DEXT');
-end;
-
-procedure Read_GL_EXT_texture_object;
-begin
-  glAreTexturesResidentEXT := dglGetProcAddress('glAreTexturesResidentEXT');
-  glBindTextureEXT := dglGetProcAddress('glBindTextureEXT');
-  glDeleteTexturesEXT := dglGetProcAddress('glDeleteTexturesEXT');
-  glGenTexturesEXT := dglGetProcAddress('glGenTexturesEXT');
-  glIsTextureEXT := dglGetProcAddress('glIsTextureEXT');
-  glPrioritizeTexturesEXT := dglGetProcAddress('glPrioritizeTexturesEXT');
-end;
-
-procedure Read_GL_EXT_texture_perturb_normal;
-begin
-  glTextureNormalEXT := dglGetProcAddress('glTextureNormalEXT');
-end;
-
-procedure Read_GL_EXT_vertex_array;
-begin
-  glArrayElementEXT := dglGetProcAddress('glArrayElementEXT');
-  glColorPointerEXT := dglGetProcAddress('glColorPointerEXT');
-  glDrawArraysEXT := dglGetProcAddress('glDrawArraysEXT');
-  glEdgeFlagPointerEXT := dglGetProcAddress('glEdgeFlagPointerEXT');
-  glGetPointervEXT := dglGetProcAddress('glGetPointervEXT');
-  glIndexPointerEXT := dglGetProcAddress('glIndexPointerEXT');
-  glNormalPointerEXT := dglGetProcAddress('glNormalPointerEXT');
-  glTexCoordPointerEXT := dglGetProcAddress('glTexCoordPointerEXT');
-  glVertexPointerEXT := dglGetProcAddress('glVertexPointerEXT');
-end;
-
-procedure Read_GL_EXT_vertex_shader;
-begin
-  glBeginVertexShaderEXT := dglGetProcAddress('glBeginVertexShaderEXT');
-  glEndVertexShaderEXT := dglGetProcAddress('glEndVertexShaderEXT');
-  glBindVertexShaderEXT := dglGetProcAddress('glBindVertexShaderEXT');
-  glGenVertexShadersEXT := dglGetProcAddress('glGenVertexShadersEXT');
-  glDeleteVertexShaderEXT := dglGetProcAddress('glDeleteVertexShaderEXT');
-  glShaderOp1EXT := dglGetProcAddress('glShaderOp1EXT');
-  glShaderOp2EXT := dglGetProcAddress('glShaderOp2EXT');
-  glShaderOp3EXT := dglGetProcAddress('glShaderOp3EXT');
-  glSwizzleEXT := dglGetProcAddress('glSwizzleEXT');
-  glWriteMaskEXT := dglGetProcAddress('glWriteMaskEXT');
-  glInsertComponentEXT := dglGetProcAddress('glInsertComponentEXT');
-  glExtractComponentEXT := dglGetProcAddress('glExtractComponentEXT');
-  glGenSymbolsEXT := dglGetProcAddress('glGenSymbolsEXT');
-  glSetInvariantEXT := dglGetProcAddress('glSetInvariantEXT');
-  glSetLocalConstantEXT := dglGetProcAddress('glSetLocalConstantEXT');
-  glVariantbvEXT := dglGetProcAddress('glVariantbvEXT');
-  glVariantsvEXT := dglGetProcAddress('glVariantsvEXT');
-  glVariantivEXT := dglGetProcAddress('glVariantivEXT');
-  glVariantfvEXT := dglGetProcAddress('glVariantfvEXT');
-  glVariantdvEXT := dglGetProcAddress('glVariantdvEXT');
-  glVariantubvEXT := dglGetProcAddress('glVariantubvEXT');
-  glVariantusvEXT := dglGetProcAddress('glVariantusvEXT');
-  glVariantuivEXT := dglGetProcAddress('glVariantuivEXT');
-  glVariantPointerEXT := dglGetProcAddress('glVariantPointerEXT');
-  glEnableVariantClientStateEXT := dglGetProcAddress('glEnableVariantClientStateEXT');
-  glDisableVariantClientStateEXT := dglGetProcAddress('glDisableVariantClientStateEXT');
-  glBindLightParameterEXT := dglGetProcAddress('glBindLightParameterEXT');
-  glBindMaterialParameterEXT := dglGetProcAddress('glBindMaterialParameterEXT');
-  glBindTexGenParameterEXT := dglGetProcAddress('glBindTexGenParameterEXT');
-  glBindTextureUnitParameterEXT := dglGetProcAddress('glBindTextureUnitParameterEXT');
-  glBindParameterEXT := dglGetProcAddress('glBindParameterEXT');
-  glIsVariantEnabledEXT := dglGetProcAddress('glIsVariantEnabledEXT');
-  glGetVariantBooleanvEXT := dglGetProcAddress('glGetVariantBooleanvEXT');
-  glGetVariantIntegervEXT := dglGetProcAddress('glGetVariantIntegervEXT');
-  glGetVariantFloatvEXT := dglGetProcAddress('glGetVariantFloatvEXT');
-  glGetVariantPointervEXT := dglGetProcAddress('glGetVariantPointervEXT');
-  glGetInvariantBooleanvEXT := dglGetProcAddress('glGetInvariantBooleanvEXT');
-  glGetInvariantIntegervEXT := dglGetProcAddress('glGetInvariantIntegervEXT');
-  glGetInvariantFloatvEXT := dglGetProcAddress('glGetInvariantFloatvEXT');
-  glGetLocalConstantBooleanvEXT := dglGetProcAddress('glGetLocalConstantBooleanvEXT');
-  glGetLocalConstantIntegervEXT := dglGetProcAddress('glGetLocalConstantIntegervEXT');
-  glGetLocalConstantFloatvEXT := dglGetProcAddress('glGetLocalConstantFloatvEXT');
-end;
-
-procedure Read_GL_EXT_vertex_weighting;
-begin
-  glVertexWeightfEXT := dglGetProcAddress('glVertexWeightfEXT');
-  glVertexWeightfvEXT := dglGetProcAddress('glVertexWeightfvEXT');
-  glVertexWeightPointerEXT := dglGetProcAddress('glVertexWeightPointerEXT');
-end;
-
-procedure Read_GL_EXT_depth_bounds_test;
-begin
-  glImageTransformParameteriHP := dglGetProcAddress('glImageTransformParameteriHP');
-  glDepthBoundsEXT := dglGetProcAddress('glDepthBoundsEXT');
-end;
-
-procedure Read_GL_EXT_blend_equation_separate;
-begin
-  glBlendEquationSeparateEXT := dglGetProcAddress('glBlendEquationSeparateEXT');
-end;
-
-procedure Read_GL_EXT_stencil_clear_tag;
-begin
-  glStencilClearTagEXT := dglGetProcAddress('glStencilClearTagEXT');
-end;
-
-procedure Read_GL_EXT_framebuffer_blit;
-begin
-  glBlitFramebufferEXT := dglGetProcAddress('glBlitFramebufferEXT');
-end;
-
-procedure Read_GL_EXT_framebuffer_multisample;
-begin
-  glRenderbufferStorageMultisampleEXT := dglGetProcAddress('glRenderbufferStorageMultisampleEXT');
-end;
-
-procedure Read_GL_EXT_timer_query;
-begin
-  glGetQueryObjecti64vEXT := dglGetProcAddress('glGetQueryObjecti64vEXT');
-  glGetQueryObjectui64vEXT := dglGetProcAddress('glGetQueryObjectui64vEXT');
-end;
-
-procedure Read_GL_EXT_gpu_program_parameters;
-begin
-  glProgramEnvParameters4fvEXT := dglGetProcAddress('glProgramEnvParameters4fvEXT');
-  glProgramLocalParameters4fvEXT := dglGetProcAddress('glProgramLocalParameters4fvEXT');
-end;
-
-procedure Read_GL_EXT_bindable_uniform;
-begin
-  glUniformBufferEXT := dglGetProcAddress('glUniformBufferEXT');
-  glGetUniformBufferSizeEXT := dglGetProcAddress('glGetUniformBufferSizeEXT');
-  glGetUniformOffsetEXT := dglGetProcAddress('glGetUniformOffsetEXT');
-end;
-
-procedure Read_GL_EXT_draw_buffers2;
-begin
-  glColorMaskIndexedEXT := dglGetProcAddress('glColorMaskIndexedEXT');
-  glGetBooleanIndexedvEXT := dglGetProcAddress('glGetBooleanIndexedvEXT');
-  glGetIntegerIndexedvEXT := dglGetProcAddress('glGetIntegerIndexedvEXT');
-  glEnableIndexedEXT := dglGetProcAddress('glEnableIndexedEXT');
-  glDisableIndexedEXT := dglGetProcAddress('glDisableIndexedEXT');
-  glIsEnabledIndexedEXT := dglGetProcAddress('glIsEnabledIndexedEXT');
-end;
-
-procedure Read_GL_EXT_draw_instanced;
-begin
-  glDrawArraysInstancedEXT := dglGetProcAddress('glDrawArraysInstancedEXT');
-  glDrawElementsInstancedEXT := dglGetProcAddress('glDrawElementsInstancedEXT');
-end;
-
-procedure Read_GL_EXT_geometry_shader4;
-begin
-  glProgramParameteriEXT := dglGetProcAddress('glProgramParameteriEXT');
-  glFramebufferTextureEXT := dglGetProcAddress('glFramebufferTextureEXT');
-//  glFramebufferTextureLayerEXT := dglGetProcAddress('glFramebufferTextureLayerEXT');
-  glFramebufferTextureFaceEXT := dglGetProcAddress('glFramebufferTextureFaceEXT');
-end;
-
-procedure Read_GL_EXT_gpu_shader4;
-begin
-  glVertexAttribI1iEXT := dglGetProcAddress('glVertexAttribI1iEXT');
-  glVertexAttribI2iEXT := dglGetProcAddress('glVertexAttribI2iEXT');
-  glVertexAttribI3iEXT := dglGetProcAddress('glVertexAttribI3iEXT');
-  glVertexAttribI4iEXT := dglGetProcAddress('glVertexAttribI4iEXT');
-  glVertexAttribI1uiEXT := dglGetProcAddress('glVertexAttribI1uiEXT');
-  glVertexAttribI2uiEXT := dglGetProcAddress('glVertexAttribI2uiEXT');
-  glVertexAttribI3uiEXT := dglGetProcAddress('glVertexAttribI3uiEXT');
-  glVertexAttribI4uiEXT := dglGetProcAddress('glVertexAttribI4uiEXT');
-  glVertexAttribI1ivEXT := dglGetProcAddress('glVertexAttribI1ivEXT');
-  glVertexAttribI2ivEXT := dglGetProcAddress('glVertexAttribI2ivEXT');
-  glVertexAttribI3ivEXT := dglGetProcAddress('glVertexAttribI3ivEXT');
-  glVertexAttribI4ivEXT := dglGetProcAddress('glVertexAttribI4ivEXT');
-  glVertexAttribI1uivEXT := dglGetProcAddress('glVertexAttribI1uivEXT');
-  glVertexAttribI2uivEXT := dglGetProcAddress('glVertexAttribI2uivEXT');
-  glVertexAttribI3uivEXT := dglGetProcAddress('glVertexAttribI3uivEXT');
-  glVertexAttribI4uivEXT := dglGetProcAddress('glVertexAttribI4uivEXT');
-  glVertexAttribI4bvEXT := dglGetProcAddress('glVertexAttribI4bvEXT');
-  glVertexAttribI4svEXT := dglGetProcAddress('glVertexAttribI4svEXT');
-  glVertexAttribI4ubvEXT := dglGetProcAddress('glVertexAttribI4ubvEXT');
-  glVertexAttribI4usvEXT := dglGetProcAddress('glVertexAttribI4usvEXT');
-  glVertexAttribIPointerEXT := dglGetProcAddress('glVertexAttribIPointerEXT');
-  glGetVertexAttribIivEXT := dglGetProcAddress('glGetVertexAttribIivEXT');
-  glGetVertexAttribIuivEXT := dglGetProcAddress('glGetVertexAttribIuivEXT');
-  glUniform1uiEXT := dglGetProcAddress('glUniform1uiEXT');
-  glUniform2uiEXT := dglGetProcAddress('glUniform2uiEXT');
-  glUniform3uiEXT := dglGetProcAddress('glUniform3uiEXT');
-  glUniform4uiEXT := dglGetProcAddress('glUniform4uiEXT');
-  glUniform1uivEXT := dglGetProcAddress('glUniform1uivEXT');
-  glUniform2uivEXT := dglGetProcAddress('glUniform2uivEXT');
-  glUniform3uivEXT := dglGetProcAddress('glUniform3uivEXT');
-  glUniform4uivEXT := dglGetProcAddress('glUniform4uivEXT');
-  glGetUniformuivEXT := dglGetProcAddress('glGetUniformuivEXT');
-  glBindFragDataLocationEXT := dglGetProcAddress('glBindFragDataLocationEXT');
-  glGetFragDataLocationEXT := dglGetProcAddress('glGetFragDataLocationEXT');
-end;
-
-procedure Read_GL_EXT_texture_array;
-begin
-  glFramebufferTextureLayerEXT := dglGetProcAddress('glFramebufferTextureLayerEXT');
-end;
-
-procedure Read_GL_EXT_texture_buffer_object;
-begin
-  glTexBufferEXT := dglGetProcAddress('glTexBufferEXT');
-end;
-
-procedure Read_GL_EXT_texture_integer;
-begin
-  glClearColorIiEXT := dglGetProcAddress('glClearColorIiEXT');
-  glClearColorIuiEXT := dglGetProcAddress('glClearColorIuiEXT');
-  glTexParameterIivEXT := dglGetProcAddress('glTexParameterIivEXT');
-  glTexParameterIuivEXT := dglGetProcAddress('glTexParameterIuivEXT');
-  glGetTexParameterIivEXT := dglGetProcAddress('glGetTexParameterIivEXT');
-  glGetTexParameterIiuvEXT := dglGetProcAddress('glGetTexParameterIiuvEXT');
-end;
-
-procedure Read_GL_EXT_transform_feedback;
-begin
-  glBeginTransformFeedbackEXT := dglGetProcAddress('lBeginTransformFeedbackEXT');
-  glEndTransformFeedbackEXT := dglGetProcAddress('glEndTransformFeedbackEXT');
-  glBindBufferRangeEXT := dglGetProcAddress('glBindBufferRangeEXT');
-  glBindBufferOffsetEXT := dglGetProcAddress('glBindBufferOffsetEXT');
-  glBindBufferBaseEXT := dglGetProcAddress('glBindBufferBaseEXT');
-  glTransformFeedbackVaryingsEXT := dglGetProcAddress('glTransformFeedbackVaryingsEXT');
-  glGetTransformFeedbackVaryingEXT := dglGetProcAddress('glGetTransformFeedbackVaryingEXT');
-end;
-
-procedure Read_GL_EXT_direct_state_access;
-begin
-  glClientAttribDefaultEXT := dglGetProcAddress('glClientAttribDefaultEXT');
-  glPushClientAttribDefaultEXT := dglGetProcAddress('glPushClientAttribDefaultEXT');
-  glMatrixLoadfEXT := dglGetProcAddress('glMatrixLoadfEXT');
-  glMatrixLoaddEXT := dglGetProcAddress('glMatrixLoaddEXT');
-  glMatrixMultfEXT := dglGetProcAddress('glMatrixMultfEXT');
-  glMatrixMultdEXT := dglGetProcAddress('glMatrixMultdEXT');
-  glMatrixLoadIdentityEXT := dglGetProcAddress('glMatrixLoadIdentityEXT');
-  glMatrixRotatefEXT := dglGetProcAddress('glMatrixRotatefEXT');
-  glMatrixRotatedEXT := dglGetProcAddress('glMatrixRotatedEXT');
-  glMatrixScalefEXT := dglGetProcAddress('glMatrixScalefEXT');
-  glMatrixScaledEXT := dglGetProcAddress('glMatrixScaledEXT');
-  glMatrixTranslatefEXT := dglGetProcAddress('glMatrixTranslatefEXT');
-  glMatrixTranslatedEXT := dglGetProcAddress('glMatrixTranslatedEXT');
-  glMatrixFrustumEXT := dglGetProcAddress('glMatrixFrustumEXT');
-  glMatrixOrthoEXT := dglGetProcAddress('glMatrixOrthoEXT');
-  glMatrixPopEXT := dglGetProcAddress('glMatrixPopEXT');
-  glMatrixPushEXT := dglGetProcAddress('glMatrixPushEXT');
-  glMatrixLoadTransposefEXT := dglGetProcAddress('glMatrixLoadTransposefEXT');
-  glMatrixLoadTransposedEXT := dglGetProcAddress('glMatrixLoadTransposedEXT');
-  glMatrixMultTransposefEXT := dglGetProcAddress('glMatrixMultTransposefEXT');
-  glMatrixMultTransposedEXT := dglGetProcAddress('glMatrixMultTransposedEXT');
-  glTextureParameterfEXT := dglGetProcAddress('glTextureParameterfEXT');
-  glTextureParameterfvEXT := dglGetProcAddress('glTextureParameterfvEXT');
-  glTextureParameteriEXT := dglGetProcAddress('glTextureParameteriEXT');
-  glTextureParameterivEXT := dglGetProcAddress('glTextureParameterivEXT');
-  glTextureImage1DEXT := dglGetProcAddress('glTextureImage1DEXT');
-  glTextureImage2DEXT := dglGetProcAddress('glTextureImage2DEXT');
-  glTextureSubImage1DEXT := dglGetProcAddress('glTextureSubImage1DEXT');
-  glTextureSubImage2DEXT := dglGetProcAddress('glTextureSubImage2DEXT');
-  glCopyTextureImage1DEXT := dglGetProcAddress('glCopyTextureImage1DEXT');
-  glCopyTextureImage2DEXT := dglGetProcAddress('glCopyTextureImage2DEXT');
-  glCopyTextureSubImage1DEXT := dglGetProcAddress('glCopyTextureSubImage1DEXT');
-  glCopyTextureSubImage2DEXT := dglGetProcAddress('glCopyTextureSubImage2DEXT');
-  glGetTextureImageEXT := dglGetProcAddress('glGetTextureImageEXT');
-  glGetTextureParameterfvEXT := dglGetProcAddress('glGetTextureParameterfvEXT');
-  glGetTextureParameterivEXT := dglGetProcAddress('glGetTextureParameterivEXT');
-  glGetTextureLevelParameterfvEXT := dglGetProcAddress('glGetTextureLevelParameterfvEXT');
-  glGetTextureLevelParameterivEXT := dglGetProcAddress('glGetTextureLevelParameterivEXT');
-  glTextureImage3DEXT := dglGetProcAddress('glTextureImage3DEXT');
-  glTextureSubImage3DEXT := dglGetProcAddress('glTextureSubImage3DEXT');
-  glCopyTextureSubImage3DEXT := dglGetProcAddress('glCopyTextureSubImage3DEXT');
-  glMultiTexParameterfEXT := dglGetProcAddress('glMultiTexParameterfEXT');
-  glMultiTexParameterfvEXT := dglGetProcAddress('glMultiTexParameterfvEXT');
-  glMultiTexParameteriEXT := dglGetProcAddress('glMultiTexParameteriEXT');
-  glMultiTexParameterivEXT := dglGetProcAddress('glMultiTexParameterivEXT');
-  glMultiTexImage1DEXT := dglGetProcAddress('glMultiTexImage1DEXT');
-  glMultiTexImage2DEXT := dglGetProcAddress('glMultiTexImage2DEXT');
-  glMultiTexSubImage1DEXT := dglGetProcAddress('glMultiTexSubImage1DEXT');
-  glMultiTexSubImage2DEXT := dglGetProcAddress('glMultiTexSubImage2DEXT');
-  glCopyMultiTexImage1DEXT := dglGetProcAddress('glCopyMultiTexImage1DEXT');
-  glCopyMultiTexImage2DEXT := dglGetProcAddress('glCopyMultiTexImage2DEXT');
-  glCopyMultiTexSubImage1DEXT := dglGetProcAddress('glCopyMultiTexSubImage1DEXT');
-  glCopyMultiTexSubImage2DEXT := dglGetProcAddress('glCopyMultiTexSubImage2DEXT');
-  glGetMultiTexImageEXT := dglGetProcAddress('glGetMultiTexImageEXT');
-  glGetMultiTexParameterfvEXT := dglGetProcAddress('glGetMultiTexParameterfvEXT');
-  glGetMultiTexParameterivEXT := dglGetProcAddress('glGetMultiTexParameterivEXT');
-  glGetMultiTexLevelParameterfvEXT := dglGetProcAddress('glGetMultiTexLevelParameterfvEXT');
-  glGetMultiTexLevelParameterivEXT := dglGetProcAddress('glGetMultiTexLevelParameterivEXT');
-  glMultiTexImage3DEXT := dglGetProcAddress('glMultiTexImage3DEXT');
-  glMultiTexSubImage3DEXT := dglGetProcAddress('glMultiTexSubImage3DEXT');
-  glCopyMultiTexSubImage3DEXT := dglGetProcAddress('glCopyMultiTexSubImage3DEXT');
-  glBindMultiTextureEXT := dglGetProcAddress('glBindMultiTextureEXT');
-  glEnableClientStateIndexedEXT := dglGetProcAddress('glEnableClientStateIndexedEXT');
-  glDisableClientStateIndexedEXT := dglGetProcAddress('glDisableClientStateIndexedEXT');
-  glMultiTexCoordPointerEXT := dglGetProcAddress('glMultiTexCoordPointerEXT');
-  glMultiTexEnvfEXT := dglGetProcAddress('glMultiTexEnvfEXT');
-  glMultiTexEnvfvEXT := dglGetProcAddress('glMultiTexEnvfvEXT');
-  glMultiTexEnviEXT := dglGetProcAddress('glMultiTexEnviEXT');
-  glMultiTexEnvivEXT := dglGetProcAddress('glMultiTexEnvivEXT');
-  glMultiTexGendEXT := dglGetProcAddress('glMultiTexGendEXT');
-  glMultiTexGendvEXT := dglGetProcAddress('glMultiTexGendvEXT');
-  glMultiTexGenfEXT := dglGetProcAddress('glMultiTexGenfEXT');
-  glMultiTexGenfvEXT := dglGetProcAddress('glMultiTexGenfvEXT');
-  glMultiTexGeniEXT := dglGetProcAddress('glMultiTexGeniEXT');
-  glMultiTexGenivEXT := dglGetProcAddress('glMultiTexGenivEXT');
-  glGetMultiTexEnvfvEXT := dglGetProcAddress('glGetMultiTexEnvfvEXT');
-  glGetMultiTexEnvivEXT := dglGetProcAddress('glGetMultiTexEnvivEXT');
-  glGetMultiTexGendvEXT := dglGetProcAddress('glGetMultiTexGendvEXT');
-  glGetMultiTexGenfvEXT := dglGetProcAddress('glGetMultiTexGenfvEXT');
-  glGetMultiTexGenivEXT := dglGetProcAddress('glGetMultiTexGenivEXT');
-  glGetFloatIndexedvEXT := dglGetProcAddress('glGetFloatIndexedvEXT');
-  glGetDoubleIndexedvEXT := dglGetProcAddress('glGetDoubleIndexedvEXT');
-  glGetPointerIndexedvEXT := dglGetProcAddress('glGetPointerIndexedvEXT');
-  glCompressedTextureImage3DEXT := dglGetProcAddress('glCompressedTextureImage3DEXT');
-  glCompressedTextureImage2DEXT := dglGetProcAddress('glCompressedTextureImage2DEXT');
-  glCompressedTextureImage1DEXT := dglGetProcAddress('glCompressedTextureImage1DEXT');
-  glCompressedTextureSubImage3DEXT := dglGetProcAddress('glCompressedTextureSubImage3DEXT');
-  glCompressedTextureSubImage2DEXT := dglGetProcAddress('glCompressedTextureSubImage2DEXT');
-  glCompressedTextureSubImage1DEXT := dglGetProcAddress('glCompressedTextureSubImage1DEXT');
-  glGetCompressedTextureImageEXT := dglGetProcAddress('glGetCompressedTextureImageEXT');
-  glCompressedMultiTexImage3DEXT := dglGetProcAddress('glCompressedMultiTexImage3DEXT');
-  glCompressedMultiTexImage2DEXT := dglGetProcAddress('glCompressedMultiTexImage2DEXT');
-  glCompressedMultiTexImage1DEXT := dglGetProcAddress('glCompressedMultiTexImage1DEXT');
-  glCompressedMultiTexSubImage3DEXT := dglGetProcAddress('glCompressedMultiTexSubImage3DEXT');
-  glCompressedMultiTexSubImage2DEXT := dglGetProcAddress('glCompressedMultiTexSubImage2DEXT');
-  glCompressedMultiTexSubImage1DEXT := dglGetProcAddress('glCompressedMultiTexSubImage1DEXT');
-  glGetCompressedMultiTexImageEXT := dglGetProcAddress('glGetCompressedMultiTexImageEXT');
-  glNamedProgramStringEXT := dglGetProcAddress('glNamedProgramStringEXT');
-  glNamedProgramLocalParameter4dEXT := dglGetProcAddress('glNamedProgramLocalParameter4dEXT');
-  glNamedProgramLocalParameter4dvEXT := dglGetProcAddress('glNamedProgramLocalParameter4dvEXT');
-  glNamedProgramLocalParameter4fEXT := dglGetProcAddress('glNamedProgramLocalParameter4fEXT');
-  glNamedProgramLocalParameter4fvEXT := dglGetProcAddress('glNamedProgramLocalParameter4fvEXT');
-  glGetNamedProgramLocalParameterdvEXT := dglGetProcAddress('glGetNamedProgramLocalParameterdvEXT');
-  glGetNamedProgramLocalParameterfvEXT := dglGetProcAddress('glGetNamedProgramLocalParameterfvEXT');
-  glGetNamedProgramivEXT := dglGetProcAddress('glGetNamedProgramivEXT');
-  glGetNamedProgramStringEXT := dglGetProcAddress('glGetNamedProgramStringEXT');
-  glNamedProgramLocalParameters4fvEXT := dglGetProcAddress('glNamedProgramLocalParameters4fvEXT');
-  glNamedProgramLocalParameterI4iEXT := dglGetProcAddress('glNamedProgramLocalParameterI4iEXT');
-  glNamedProgramLocalParameterI4ivEXT := dglGetProcAddress('glNamedProgramLocalParameterI4ivEXT');
-  glNamedProgramLocalParametersI4ivEXT := dglGetProcAddress('glNamedProgramLocalParametersI4ivEXT');
-  glNamedProgramLocalParameterI4uiEXT := dglGetProcAddress('glNamedProgramLocalParameterI4uiEXT');
-  glNamedProgramLocalParameterI4uivEXT := dglGetProcAddress('glNamedProgramLocalParameterI4uivEXT');
-  glNamedProgramLocalParametersI4uivEXT := dglGetProcAddress('glNamedProgramLocalParametersI4uivEXT');
-  glGetNamedProgramLocalParameterIivEXT := dglGetProcAddress('glGetNamedProgramLocalParameterIivEXT');
-  glGetNamedProgramLocalParameterIuivEXT := dglGetProcAddress('glGetNamedProgramLocalParameterIuivEXT');
-  glTextureParameterIivEXT := dglGetProcAddress('glTextureParameterIivEXT');
-  glTextureParameterIuivEXT := dglGetProcAddress('glTextureParameterIuivEXT');
-  glGetTextureParameterIivEXT := dglGetProcAddress('glGetTextureParameterIivEXT');
-  glGetTextureParameterIuivEXT := dglGetProcAddress('glGetTextureParameterIuivEXT');
-  glMultiTexParameterIivEXT := dglGetProcAddress('glMultiTexParameterIivEXT');
-  glMultiTexParameterIuivEXT := dglGetProcAddress('glMultiTexParameterIuivEXT');
-  glGetMultiTexParameterIivEXT := dglGetProcAddress('glGetMultiTexParameterIivEXT');
-  glGetMultiTexParameterIuivEXT := dglGetProcAddress('glGetMultiTexParameterIuivEXT');
-  glProgramUniform1fEXT := dglGetProcAddress('glProgramUniform1fEXT');
-  glProgramUniform2fEXT := dglGetProcAddress('glProgramUniform2fEXT');
-  glProgramUniform3fEXT := dglGetProcAddress('glProgramUniform3fEXT');
-  glProgramUniform4fEXT := dglGetProcAddress('glProgramUniform4fEXT');
-  glProgramUniform1iEXT := dglGetProcAddress('glProgramUniform1iEXT');
-  glProgramUniform2iEXT := dglGetProcAddress('glProgramUniform2iEXT');
-  glProgramUniform3iEXT := dglGetProcAddress('glProgramUniform3iEXT');
-  glProgramUniform4iEXT := dglGetProcAddress('glProgramUniform4iEXT');
-  glProgramUniform1fvEXT := dglGetProcAddress('glProgramUniform1fvEXT');
-  glProgramUniform2fvEXT := dglGetProcAddress('glProgramUniform2fvEXT');
-  glProgramUniform3fvEXT := dglGetProcAddress('glProgramUniform3fvEXT');
-  glProgramUniform4fvEXT := dglGetProcAddress('glProgramUniform4fvEXT');
-  glProgramUniform1ivEXT := dglGetProcAddress('glProgramUniform1ivEXT');
-  glProgramUniform2ivEXT := dglGetProcAddress('glProgramUniform2ivEXT');
-  glProgramUniform3ivEXT := dglGetProcAddress('glProgramUniform3ivEXT');
-  glProgramUniform4ivEXT := dglGetProcAddress('glProgramUniform4ivEXT');
-  glProgramUniformMatrix2fvEXT := dglGetProcAddress('glProgramUniformMatrix2fvEXT');
-  glProgramUniformMatrix3fvEXT := dglGetProcAddress('glProgramUniformMatrix3fvEXT');
-  glProgramUniformMatrix4fvEXT := dglGetProcAddress('glProgramUniformMatrix4fvEXT');
-  glProgramUniformMatrix2x3fvEXT := dglGetProcAddress('glProgramUniformMatrix2x3fvEXT');
-  glProgramUniformMatrix3x2fvEXT := dglGetProcAddress('glProgramUniformMatrix3x2fvEXT');
-  glProgramUniformMatrix2x4fvEXT := dglGetProcAddress('glProgramUniformMatrix2x4fvEXT');
-  glProgramUniformMatrix4x2fvEXT := dglGetProcAddress('glProgramUniformMatrix4x2fvEXT');
-  glProgramUniformMatrix3x4fvEXT := dglGetProcAddress('glProgramUniformMatrix3x4fvEXT');
-  glProgramUniformMatrix4x3fvEXT := dglGetProcAddress('glProgramUniformMatrix4x3fvEXT');
-  glProgramUniform1uiEXT := dglGetProcAddress('glProgramUniform1uiEXT');
-  glProgramUniform2uiEXT := dglGetProcAddress('glProgramUniform2uiEXT');
-  glProgramUniform3uiEXT := dglGetProcAddress('glProgramUniform3uiEXT');
-  glProgramUniform4uiEXT := dglGetProcAddress('glProgramUniform4uiEXT');
-  glProgramUniform1uivEXT := dglGetProcAddress('glProgramUniform1uivEXT');
-  glProgramUniform2uivEXT := dglGetProcAddress('glProgramUniform2uivEXT');
-  glProgramUniform3uivEXT := dglGetProcAddress('glProgramUniform3uivEXT');
-  glProgramUniform4uivEXT := dglGetProcAddress('glProgramUniform4uivEXT');
-  glNamedBufferDataEXT := dglGetProcAddress('glNamedBufferDataEXT');
-  glNamedBufferSubDataEXT := dglGetProcAddress('glNamedBufferSubDataEXT');
-  glMapNamedBufferEXT := dglGetProcAddress('glMapNamedBufferEXT');
-  glUnmapNamedBufferEXT := dglGetProcAddress('glUnmapNamedBufferEXT');
-  glGetNamedBufferParameterivEXT := dglGetProcAddress('glGetNamedBufferParameterivEXT');
-  glGetNamedBufferPointervEXT := dglGetProcAddress('glGetNamedBufferPointervEXT');
-  glGetNamedBufferSubDataEXT := dglGetProcAddress('glGetNamedBufferSubDataEXT');
-  glTextureBufferEXT := dglGetProcAddress('glTextureBufferEXT');
-  glMultiTexBufferEXT := dglGetProcAddress('glMultiTexBufferEXT');
-  glNamedRenderbufferStorageEXT := dglGetProcAddress('glNamedRenderbufferStorageEXT');
-  glGetNamedRenderbufferParameterivEXT := dglGetProcAddress('glGetNamedRenderbufferParameterivEXT');
-  glCheckNamedFramebufferStatusEXT := dglGetProcAddress('glCheckNamedFramebufferStatusEXT');
-  glNamedFramebufferTexture1DEXT := dglGetProcAddress('glNamedFramebufferTexture1DEXT');
-  glNamedFramebufferTexture2DEXT := dglGetProcAddress('glNamedFramebufferTexture2DEXT');
-  glNamedFramebufferTexture3DEXT := dglGetProcAddress('glNamedFramebufferTexture3DEXT');
-  glNamedFramebufferRenderbufferEXT := dglGetProcAddress('glNamedFramebufferRenderbufferEXT');
-  glGetNamedFramebufferAttachmentParameterivEXT := dglGetProcAddress('glGetNamedFramebufferAttachmentParameterivEXT');
-  glGenerateTextureMipmapEXT := dglGetProcAddress('glGenerateTextureMipmapEXT');
-  glGenerateMultiTexMipmapEXT := dglGetProcAddress('glGenerateMultiTexMipmapEXT');
-  glFramebufferDrawBufferEXT := dglGetProcAddress('glFramebufferDrawBufferEXT');
-  glFramebufferDrawBuffersEXT := dglGetProcAddress('glFramebufferDrawBuffersEXT');
-  glFramebufferReadBufferEXT := dglGetProcAddress('glFramebufferReadBufferEXT');
-  glGetFramebufferParameterivEXT := dglGetProcAddress('glGetFramebufferParameterivEXT');
-  glNamedRenderbufferStorageMultisampleEXT := dglGetProcAddress('glNamedRenderbufferStorageMultisampleEXT');
-  glNamedRenderbufferStorageMultisampleCoverageEXT := dglGetProcAddress('glNamedRenderbufferStorageMultisampleCoverageEXT');
-  glNamedFramebufferTextureEXT := dglGetProcAddress('glNamedFramebufferTextureEXT');
-  glNamedFramebufferTextureLayerEXT := dglGetProcAddress('glNamedFramebufferTextureLayerEXT');
-  glNamedFramebufferTextureFaceEXT := dglGetProcAddress('glNamedFramebufferTextureFaceEXT');
-  glTextureRenderbufferEXT := dglGetProcAddress('glTextureRenderbufferEXT');
-  glMultiTexRenderbufferEXT := dglGetProcAddress('glMultiTexRenderbufferEXT');
-end;
-
-procedure Read_GL_HP_image_transform;
-begin
-  glImageTransformParameteriHP := dglGetProcAddress('glImageTransformParameteriHP');
-  glImageTransformParameterfHP := dglGetProcAddress('glImageTransformParameterfHP');
-  glImageTransformParameterivHP := dglGetProcAddress('glImageTransformParameterivHP');
-  glImageTransformParameterfvHP := dglGetProcAddress('glImageTransformParameterfvHP');
-  glGetImageTransformParameterivHP := dglGetProcAddress('glGetImageTransformParameterivHP');
-  glGetImageTransformParameterfvHP := dglGetProcAddress('glGetImageTransformParameterfvHP');
-end;
-
-procedure Read_GL_IBM_multimode_draw_arrays;
-begin
-  glMultiModeDrawArraysIBM := dglGetProcAddress('glMultiModeDrawArraysIBM');
-  glMultiModeDrawElementsIBM := dglGetProcAddress('glMultiModeDrawElementsIBM');
-end;
-
-procedure Read_GL_IBM_vertex_array_lists;
-begin
-  glColorPointerListIBM := dglGetProcAddress('glColorPointerListIBM');
-  glSecondaryColorPointerListIBM := dglGetProcAddress('glSecondaryColorPointerListIBM');
-  glEdgeFlagPointerListIBM := dglGetProcAddress('glEdgeFlagPointerListIBM');
-  glFogCoordPointerListIBM := dglGetProcAddress('glFogCoordPointerListIBM');
-  glIndexPointerListIBM := dglGetProcAddress('glIndexPointerListIBM');
-  glNormalPointerListIBM := dglGetProcAddress('glNormalPointerListIBM');
-  glTexCoordPointerListIBM := dglGetProcAddress('glTexCoordPointerListIBM');
-  glVertexPointerListIBM := dglGetProcAddress('glVertexPointerListIBM');
-end;
-
-procedure Read_GL_INGR_blend_func_separate;
-begin
-  glBlendFuncSeparateINGR := dglGetProcAddress('glBlendFuncSeparateINGR');
-end;
-
-procedure Read_GL_INTEL_parallel_arrays;
-begin
-  glVertexPointervINTEL := dglGetProcAddress('glVertexPointervINTEL');
-  glNormalPointervINTEL := dglGetProcAddress('glNormalPointervINTEL');
-  glColorPointervINTEL := dglGetProcAddress('glColorPointervINTEL');
-  glTexCoordPointervINTEL := dglGetProcAddress('glTexCoordPointervINTEL');
-end;
-
-procedure Read_GL_MESA_resize_buffers;
-begin
-  glResizeBuffersMESA := dglGetProcAddress('glResizeBuffersMESA');
-end;
-
-procedure Read_GL_MESA_window_pos;
-begin
-  glWindowPos2dMESA := dglGetProcAddress('glWindowPos2dMESA');
-  glWindowPos2dvMESA := dglGetProcAddress('glWindowPos2dvMESA');
-  glWindowPos2fMESA := dglGetProcAddress('glWindowPos2fMESA');
-  glWindowPos2fvMESA := dglGetProcAddress('glWindowPos2fvMESA');
-  glWindowPos2iMESA := dglGetProcAddress('glWindowPos2iMESA');
-  glWindowPos2ivMESA := dglGetProcAddress('glWindowPos2ivMESA');
-  glWindowPos2sMESA := dglGetProcAddress('glWindowPos2sMESA');
-  glWindowPos2svMESA := dglGetProcAddress('glWindowPos2svMESA');
-  glWindowPos3dMESA := dglGetProcAddress('glWindowPos3dMESA');
-  glWindowPos3dvMESA := dglGetProcAddress('glWindowPos3dvMESA');
-  glWindowPos3fMESA := dglGetProcAddress('glWindowPos3fMESA');
-  glWindowPos3fvMESA := dglGetProcAddress('glWindowPos3fvMESA');
-  glWindowPos3iMESA := dglGetProcAddress('glWindowPos3iMESA');
-  glWindowPos3ivMESA := dglGetProcAddress('glWindowPos3ivMESA');
-  glWindowPos3sMESA := dglGetProcAddress('glWindowPos3sMESA');
-  glWindowPos3svMESA := dglGetProcAddress('glWindowPos3svMESA');
-  glWindowPos4dMESA := dglGetProcAddress('glWindowPos4dMESA');
-  glWindowPos4dvMESA := dglGetProcAddress('glWindowPos4dvMESA');
-  glWindowPos4fMESA := dglGetProcAddress('glWindowPos4fMESA');
-  glWindowPos4fvMESA := dglGetProcAddress('glWindowPos4fvMESA');
-  glWindowPos4iMESA := dglGetProcAddress('glWindowPos4iMESA');
-  glWindowPos4ivMESA := dglGetProcAddress('glWindowPos4ivMESA');
-  glWindowPos4sMESA := dglGetProcAddress('glWindowPos4sMESA');
-  glWindowPos4svMESA := dglGetProcAddress('glWindowPos4svMESA');
-end;
-
-procedure Read_GL_NV_evaluators;
-begin
-  glMapControlPointsNV := dglGetProcAddress('glMapControlPointsNV');
-  glMapParameterivNV := dglGetProcAddress('glMapParameterivNV');
-  glMapParameterfvNV := dglGetProcAddress('glMapParameterfvNV');
-  glGetMapControlPointsNV := dglGetProcAddress('glGetMapControlPointsNV');
-  glGetMapParameterivNV := dglGetProcAddress('glGetMapParameterivNV');
-  glGetMapParameterfvNV := dglGetProcAddress('glGetMapParameterfvNV');
-  glGetMapAttribParameterivNV := dglGetProcAddress('glGetMapAttribParameterivNV');
-  glGetMapAttribParameterfvNV := dglGetProcAddress('glGetMapAttribParameterfvNV');
-  glEvalMapsNV := dglGetProcAddress('glEvalMapsNV');
-end;
-
-procedure Read_GL_NV_fence;
-begin
-  glDeleteFencesNV := dglGetProcAddress('glDeleteFencesNV');
-  glGenFencesNV := dglGetProcAddress('glGenFencesNV');
-  glIsFenceNV := dglGetProcAddress('glIsFenceNV');
-  glTestFenceNV := dglGetProcAddress('glTestFenceNV');
-  glGetFenceivNV := dglGetProcAddress('glGetFenceivNV');
-  glFinishFenceNV := dglGetProcAddress('glFinishFenceNV');
-  glSetFenceNV := dglGetProcAddress('glSetFenceNV');
-end;
-
-procedure Read_GL_NV_fragment_program;
-begin
-  glProgramNamedParameter4fNV := dglGetProcAddress('glProgramNamedParameter4fNV');
-  glProgramNamedParameter4dNV := dglGetProcAddress('glProgramNamedParameter4dNV');
-  glProgramNamedParameter4fvNV := dglGetProcAddress('glProgramNamedParameter4fvNV');
-  glProgramNamedParameter4dvNV := dglGetProcAddress('glProgramNamedParameter4dvNV');
-  glGetProgramNamedParameterfvNV := dglGetProcAddress('glGetProgramNamedParameterfvNV');
-  glGetProgramNamedParameterdvNV := dglGetProcAddress('glGetProgramNamedParameterdvNV');
-end;
-
-procedure Read_GL_NV_half_float;
-begin
-  glVertex2hNV := dglGetProcAddress('glVertex2hNV');
-  glVertex2hvNV := dglGetProcAddress('glVertex2hvNV');
-  glVertex3hNV := dglGetProcAddress('glVertex3hNV');
-  glVertex3hvNV := dglGetProcAddress('glVertex3hvNV');
-  glVertex4hNV := dglGetProcAddress('glVertex4hNV');
-  glVertex4hvNV := dglGetProcAddress('glVertex4hvNV');
-  glNormal3hNV := dglGetProcAddress('glNormal3hNV');
-  glNormal3hvNV := dglGetProcAddress('glNormal3hvNV');
-  glColor3hNV := dglGetProcAddress('glColor3hNV');
-  glColor3hvNV := dglGetProcAddress('glColor3hvNV');
-  glColor4hNV := dglGetProcAddress('glColor4hNV');
-  glColor4hvNV := dglGetProcAddress('glColor4hvNV');
-  glTexCoord1hNV := dglGetProcAddress('glTexCoord1hNV');
-  glTexCoord1hvNV := dglGetProcAddress('glTexCoord1hvNV');
-  glTexCoord2hNV := dglGetProcAddress('glTexCoord2hNV');
-  glTexCoord2hvNV := dglGetProcAddress('glTexCoord2hvNV');
-  glTexCoord3hNV := dglGetProcAddress('glTexCoord3hNV');
-  glTexCoord3hvNV := dglGetProcAddress('glTexCoord3hvNV');
-  glTexCoord4hNV := dglGetProcAddress('glTexCoord4hNV');
-  glTexCoord4hvNV := dglGetProcAddress('glTexCoord4hvNV');
-  glMultiTexCoord1hNV := dglGetProcAddress('glMultiTexCoord1hNV');
-  glMultiTexCoord1hvNV := dglGetProcAddress('glMultiTexCoord1hvNV');
-  glMultiTexCoord2hNV := dglGetProcAddress('glMultiTexCoord2hNV');
-  glMultiTexCoord2hvNV := dglGetProcAddress('glMultiTexCoord2hvNV');
-  glMultiTexCoord3hNV := dglGetProcAddress('glMultiTexCoord3hNV');
-  glMultiTexCoord3hvNV := dglGetProcAddress('glMultiTexCoord3hvNV');
-  glMultiTexCoord4hNV := dglGetProcAddress('glMultiTexCoord4hNV');
-  glMultiTexCoord4hvNV := dglGetProcAddress('glMultiTexCoord4hvNV');
-  glFogCoordhNV := dglGetProcAddress('glFogCoordhNV');
-  glFogCoordhvNV := dglGetProcAddress('glFogCoordhvNV');
-  glSecondaryColor3hNV := dglGetProcAddress('glSecondaryColor3hNV');
-  glSecondaryColor3hvNV := dglGetProcAddress('glSecondaryColor3hvNV');
-  glVertexWeighthNV := dglGetProcAddress('glVertexWeighthNV');
-  glVertexWeighthvNV := dglGetProcAddress('glVertexWeighthvNV');
-  glVertexAttrib1hNV := dglGetProcAddress('glVertexAttrib1hNV');
-  glVertexAttrib1hvNV := dglGetProcAddress('glVertexAttrib1hvNV');
-  glVertexAttrib2hNV := dglGetProcAddress('glVertexAttrib2hNV');
-  glVertexAttrib2hvNV := dglGetProcAddress('glVertexAttrib2hvNV');
-  glVertexAttrib3hNV := dglGetProcAddress('glVertexAttrib3hNV');
-  glVertexAttrib3hvNV := dglGetProcAddress('glVertexAttrib3hvNV');
-  glVertexAttrib4hNV := dglGetProcAddress('glVertexAttrib4hNV');
-  glVertexAttrib4hvNV := dglGetProcAddress('glVertexAttrib4hvNV');
-  glVertexAttribs1hvNV := dglGetProcAddress('glVertexAttribs1hvNV');
-  glVertexAttribs2hvNV := dglGetProcAddress('glVertexAttribs2hvNV');
-  glVertexAttribs3hvNV := dglGetProcAddress('glVertexAttribs3hvNV');
-  glVertexAttribs4hvNV := dglGetProcAddress('glVertexAttribs4hvNV');
-end;
-
-procedure Read_GL_NV_occlusion_query;
-begin
-  glGenOcclusionQueriesNV := dglGetProcAddress('glGenOcclusionQueriesNV');
-  glDeleteOcclusionQueriesNV := dglGetProcAddress('glDeleteOcclusionQueriesNV');
-  glIsOcclusionQueryNV := dglGetProcAddress('glIsOcclusionQueryNV');
-  glBeginOcclusionQueryNV := dglGetProcAddress('glBeginOcclusionQueryNV');
-  glEndOcclusionQueryNV := dglGetProcAddress('glEndOcclusionQueryNV');
-  glGetOcclusionQueryivNV := dglGetProcAddress('glGetOcclusionQueryivNV');
-  glGetOcclusionQueryuivNV := dglGetProcAddress('glGetOcclusionQueryuivNV');
-end;
-
-procedure Read_GL_NV_pixel_data_range;
-begin
-  glPixelDataRangeNV := dglGetProcAddress('glPixelDataRangeNV');
-  glFlushPixelDataRangeNV := dglGetProcAddress('glFlushPixelDataRangeNV');
-end;
-
-procedure Read_GL_NV_point_sprite;
-begin
-  glPointParameteriNV := dglGetProcAddress('glPointParameteriNV');
-  glPointParameterivNV := dglGetProcAddress('glPointParameterivNV');
-end;
-
-procedure Read_GL_NV_primitive_restart;
-begin
-  glPrimitiveRestartNV := dglGetProcAddress('glPrimitiveRestartNV');
-  glPrimitiveRestartIndexNV := dglGetProcAddress('glPrimitiveRestartIndexNV');
-end;
-
-procedure Read_GL_NV_register_combiners;
-begin
-  glCombinerParameterfvNV := dglGetProcAddress('glCombinerParameterfvNV');
-  glCombinerParameterfNV := dglGetProcAddress('glCombinerParameterfNV');
-  glCombinerParameterivNV := dglGetProcAddress('glCombinerParameterivNV');
-  glCombinerParameteriNV := dglGetProcAddress('glCombinerParameteriNV');
-  glCombinerInputNV := dglGetProcAddress('glCombinerInputNV');
-  glCombinerOutputNV := dglGetProcAddress('glCombinerOutputNV');
-  glFinalCombinerInputNV := dglGetProcAddress('glFinalCombinerInputNV');
-  glGetCombinerInputParameterfvNV := dglGetProcAddress('glGetCombinerInputParameterfvNV');
-  glGetCombinerInputParameterivNV := dglGetProcAddress('glGetCombinerInputParameterivNV');
-  glGetCombinerOutputParameterfvNV := dglGetProcAddress('glGetCombinerOutputParameterfvNV');
-  glGetCombinerOutputParameterivNV := dglGetProcAddress('glGetCombinerOutputParameterivNV');
-  glGetFinalCombinerInputParameterfvNV := dglGetProcAddress('glGetFinalCombinerInputParameterfvNV');
-  glGetFinalCombinerInputParameterivNV := dglGetProcAddress('glGetFinalCombinerInputParameterivNV');
-end;
-
-procedure Read_GL_NV_register_combiners2;
-begin
-  glCombinerStageParameterfvNV := dglGetProcAddress('glCombinerStageParameterfvNV');
-  glGetCombinerStageParameterfvNV := dglGetProcAddress('glGetCombinerStageParameterfvNV');
-end;
-
-procedure Read_GL_NV_vertex_array_range;
-begin
-  glFlushVertexArrayRangeNV := dglGetProcAddress('glFlushVertexArrayRangeNV');
-  glVertexArrayRangeNV := dglGetProcAddress('glVertexArrayRangeNV');
-end;
-
-procedure Read_GL_NV_vertex_program;
-begin
-  glAreProgramsResidentNV := dglGetProcAddress('glAreProgramsResidentNV');
-  glBindProgramNV := dglGetProcAddress('glBindProgramNV');
-  glDeleteProgramsNV := dglGetProcAddress('glDeleteProgramsNV');
-  glExecuteProgramNV := dglGetProcAddress('glExecuteProgramNV');
-  glGenProgramsNV := dglGetProcAddress('glGenProgramsNV');
-  glGetProgramParameterdvNV := dglGetProcAddress('glGetProgramParameterdvNV');
-  glGetProgramParameterfvNV := dglGetProcAddress('glGetProgramParameterfvNV');
-  glGetProgramivNV := dglGetProcAddress('glGetProgramivNV');
-  glGetProgramStringNV := dglGetProcAddress('glGetProgramStringNV');
-  glGetTrackMatrixivNV := dglGetProcAddress('glGetTrackMatrixivNV');
-  glGetVertexAttribdvNV := dglGetProcAddress('glGetVertexAttribdvNV');
-  glGetVertexAttribfvNV := dglGetProcAddress('glGetVertexAttribfvNV');
-  glGetVertexAttribivNV := dglGetProcAddress('glGetVertexAttribivNV');
-  glGetVertexAttribPointervNV := dglGetProcAddress('glGetVertexAttribPointervNV');
-  glIsProgramNV := dglGetProcAddress('glIsProgramNV');
-  glLoadProgramNV := dglGetProcAddress('glLoadProgramNV');
-  glProgramParameter4dNV := dglGetProcAddress('glProgramParameter4dNV');
-  glProgramParameter4dvNV := dglGetProcAddress('glProgramParameter4dvNV');
-  glProgramParameter4fNV := dglGetProcAddress('glProgramParameter4fNV');
-  glProgramParameter4fvNV := dglGetProcAddress('glProgramParameter4fvNV');
-  glProgramParameters4dvNV := dglGetProcAddress('glProgramParameters4dvNV');
-  glProgramParameters4fvNV := dglGetProcAddress('glProgramParameters4fvNV');
-  glRequestResidentProgramsNV := dglGetProcAddress('glRequestResidentProgramsNV');
-  glTrackMatrixNV := dglGetProcAddress('glTrackMatrixNV');
-  glVertexAttribPointerNV := dglGetProcAddress('glVertexAttribPointerNV');
-  glVertexAttrib1dNV := dglGetProcAddress('glVertexAttrib1dNV');
-  glVertexAttrib1dvNV := dglGetProcAddress('glVertexAttrib1dvNV');
-  glVertexAttrib1fNV := dglGetProcAddress('glVertexAttrib1fNV');
-  glVertexAttrib1fvNV := dglGetProcAddress('glVertexAttrib1fvNV');
-  glVertexAttrib1sNV := dglGetProcAddress('glVertexAttrib1sNV');
-  glVertexAttrib1svNV := dglGetProcAddress('glVertexAttrib1svNV');
-  glVertexAttrib2dNV := dglGetProcAddress('glVertexAttrib2dNV');
-  glVertexAttrib2dvNV := dglGetProcAddress('glVertexAttrib2dvNV');
-  glVertexAttrib2fNV := dglGetProcAddress('glVertexAttrib2fNV');
-  glVertexAttrib2fvNV := dglGetProcAddress('glVertexAttrib2fvNV');
-  glVertexAttrib2sNV := dglGetProcAddress('glVertexAttrib2sNV');
-  glVertexAttrib2svNV := dglGetProcAddress('glVertexAttrib2svNV');
-  glVertexAttrib3dNV := dglGetProcAddress('glVertexAttrib3dNV');
-  glVertexAttrib3dvNV := dglGetProcAddress('glVertexAttrib3dvNV');
-  glVertexAttrib3fNV := dglGetProcAddress('glVertexAttrib3fNV');
-  glVertexAttrib3fvNV := dglGetProcAddress('glVertexAttrib3fvNV');
-  glVertexAttrib3sNV := dglGetProcAddress('glVertexAttrib3sNV');
-  glVertexAttrib3svNV := dglGetProcAddress('glVertexAttrib3svNV');
-  glVertexAttrib4dNV := dglGetProcAddress('glVertexAttrib4dNV');
-  glVertexAttrib4dvNV := dglGetProcAddress('glVertexAttrib4dvNV');
-  glVertexAttrib4fNV := dglGetProcAddress('glVertexAttrib4fNV');
-  glVertexAttrib4fvNV := dglGetProcAddress('glVertexAttrib4fvNV');
-  glVertexAttrib4sNV := dglGetProcAddress('glVertexAttrib4sNV');
-  glVertexAttrib4svNV := dglGetProcAddress('glVertexAttrib4svNV');
-  glVertexAttrib4ubNV := dglGetProcAddress('glVertexAttrib4ubNV');
-  glVertexAttrib4ubvNV := dglGetProcAddress('glVertexAttrib4ubvNV');
-  glVertexAttribs1dvNV := dglGetProcAddress('glVertexAttribs1dvNV');
-  glVertexAttribs1fvNV := dglGetProcAddress('glVertexAttribs1fvNV');
-  glVertexAttribs1svNV := dglGetProcAddress('glVertexAttribs1svNV');
-  glVertexAttribs2dvNV := dglGetProcAddress('glVertexAttribs2dvNV');
-  glVertexAttribs2fvNV := dglGetProcAddress('glVertexAttribs2fvNV');
-  glVertexAttribs2svNV := dglGetProcAddress('glVertexAttribs2svNV');
-  glVertexAttribs3dvNV := dglGetProcAddress('glVertexAttribs3dvNV');
-  glVertexAttribs3fvNV := dglGetProcAddress('glVertexAttribs3fvNV');
-  glVertexAttribs3svNV := dglGetProcAddress('glVertexAttribs3svNV');
-  glVertexAttribs4dvNV := dglGetProcAddress('glVertexAttribs4dvNV');
-  glVertexAttribs4fvNV := dglGetProcAddress('glVertexAttribs4fvNV');
-  glVertexAttribs4svNV := dglGetProcAddress('glVertexAttribs4svNV');
-  glVertexAttribs4ubvNV := dglGetProcAddress('glVertexAttribs4ubvNV');
-end;
-
-procedure Read_GL_NV_depth_buffer_float;
-begin
-  glDepthRangedNV := dglGetProcAddress('glDepthRangedNV');
-  glClearDepthdNV := dglGetProcAddress('glClearDepthdNV');
-  glDepthBoundsdNV := dglGetProcAddress('glDepthBoundsdNV');
-end;
-
-procedure Read_GL_NV_framebuffer_multisample_coverage;
-begin
-  glRenderbufferStorageMultsampleCoverageNV := dglGetProcAddress('glRenderbufferStorageMultsampleCoverageNV');
-end;
-
-procedure Read_GL_NV_geometry_program4;
-begin
-  glProgramVertexLimitNV := dglGetProcAddress('glProgramVertexLimitNV');
-end;
-
-procedure Read_GL_NV_gpu_program4;
-begin
-  glProgramLocalParameterI4iNV := dglGetProcAddress('glProgramLocalParameterI4iNV');
-  glProgramLocalParameterI4ivNV := dglGetProcAddress('glProgramLocalParameterI4ivNV');
-  glProgramLocalParametersI4ivNV := dglGetProcAddress('glProgramLocalParametersI4ivNV');
-  glProgramLocalParameterI4uiNV := dglGetProcAddress('glProgramLocalParameterI4uiNV');
-  glProgramLocalParameterI4uivNV := dglGetProcAddress('glProgramLocalParameterI4uivNV');
-  glProgramLocalParametersI4uivNV := dglGetProcAddress('glProgramLocalParametersI4uivNV');
-  glProgramEnvParameterI4iNV := dglGetProcAddress('glProgramEnvParameterI4iNV');
-  glProgramEnvParameterI4ivNV := dglGetProcAddress('glProgramEnvParameterI4ivNV');
-  glProgramEnvParametersI4ivNV := dglGetProcAddress('glProgramEnvParametersI4ivNV');
-  glProgramEnvParameterI4uiNV := dglGetProcAddress('glProgramEnvParameterI4uiNV');
-  glProgramEnvParameterI4uivNV := dglGetProcAddress('glProgramEnvParameterI4uivNV');
-  glProgramEnvParametersI4uivNV := dglGetProcAddress('glProgramEnvParametersI4uivNV');
-  glGetProgramLocalParameterIivNV := dglGetProcAddress('glGetProgramLocalParameterIivNV');
-  glGetProgramLocalParameterIuivNV := dglGetProcAddress('glGetProgramLocalParameterIuivNV');
-  glGetProgramEnvParameterIivNV := dglGetProcAddress('glGetProgramEnvParameterIivNV');
-  glGetProgramEnvParameterIuivNV := dglGetProcAddress('glGetProgramEnvParameterIuivNV');
-end;
-
-procedure Read_GL_NV_parameter_buffer_object;
-begin
-  glProgramBufferParametersfvNV := dglGetProcAddress('glProgramBufferParametersfvNV');
-  glProgramBufferParametersIivNV := dglGetProcAddress('glProgramBufferParametersIivNV');
-  glProgramBufferParametersIuivNV := dglGetProcAddress('glProgramBufferParametersIuivNV');
-end;
-
-procedure Read_GL_NV_transform_feedback;
-begin
-  glBeginTransformFeedbackNV := dglGetProcAddress('glBeginTransformFeedbackNV');
-  glEndTransformFeedbackNV := dglGetProcAddress('glEndTransformFeedbackNV');
-  glTransformFeedbackAttribsNV := dglGetProcAddress('glTransformFeedbackAttribsNV');
-  glBindBufferRangeNV := dglGetProcAddress('glBindBufferRangeNV');
-  glBindBufferOffsetNV := dglGetProcAddress('glBindBufferOffsetNV');
-  glBindBufferBaseNV := dglGetProcAddress('glBindBufferBaseNV');
-  glTransformFeedbackVaryingsNV := dglGetProcAddress('glTransformFeedbackVaryingsNV');
-  glActiveVaryingNV := dglGetProcAddress('glActiveVaryingNV');
-  glGetVaryingLocationNV := dglGetProcAddress('glGetVaryingLocationNV');
-  glGetActiveVaryingNV := dglGetProcAddress('glGetActiveVaryingNV');
-  glGetTransformFeedbackVaryingNV := dglGetProcAddress('glGetTransformFeedbackVaryingNV');
-end;
-
-procedure Read_GL_NV_conditional_render;
-begin
-  glBeginConditionalRenderNV := dglGetProcAddress('glBeginConditionalRenderNV');
-  glEndConditionalRenderNV := dglGetProcAddress('glEndConditionalRenderNV');
-end;
-
-procedure Read_GL_NV_present_video;
-begin
-  glPresentFrameKeyedNV := dglGetProcAddress('glPresentFrameKeyedNV');
-  glPresentFrameDualFillNV := dglGetProcAddress('glPresentFrameDualFillNV');
-  glGetVideoivNV := dglGetProcAddress('glGetVideoivNV');
-  glGetVideouivNV := dglGetProcAddress('glGetVideouivNV');
-  glGetVideoi64vNV := dglGetProcAddress('glGetVideoi64vNV');
-  glGetVideoui64vNV := dglGetProcAddress('glGetVideoui64vNV');
-//  glVideoParameterivNV := dglGetProcAddress('glVideoParameterivNV');
-end;
-
-procedure Read_GL_NV_explicit_multisample;
-begin
-  glGetMultisamplefvNV := dglGetProcAddress('glGetMultisamplefvNV');
-  glSampleMaskIndexedNV := dglGetProcAddress('glSampleMaskIndexedNV');
-  glTexRenderbufferNV := dglGetProcAddress('glTexRenderbufferNV');
-end;
-
-procedure Read_GL_NV_transform_feedback2;
-begin
-  glBindTransformFeedbackNV := dglGetProcAddress('glBindTransformFeedbackNV');
-  glDeleteTransformFeedbacksNV := dglGetProcAddress('glDeleteTransformFeedbacksNV');
-  glGenTransformFeedbacksNV := dglGetProcAddress('glGenTransformFeedbacksNV');
-  glIsTransformFeedbackNV := dglGetProcAddress('glIsTransformFeedbackNV');
-  glPauseTransformFeedbackNV := dglGetProcAddress('glPauseTransformFeedbackNV');
-  glResumeTransformFeedbackNV := dglGetProcAddress('glResumeTransformFeedbackNV');
-  glDrawTransformFeedbackNV := dglGetProcAddress('glDrawTransformFeedbackNV');
-end;
-
-procedure Read_GL_PGI_misc_hints;
-begin
-  glHintPGI := dglGetProcAddress('glHintPGI');
-end;
-
-procedure Read_GL_SGIS_detail_texture;
-begin
-  glDetailTexFuncSGIS := dglGetProcAddress('glDetailTexFuncSGIS');
-  glGetDetailTexFuncSGIS := dglGetProcAddress('glGetDetailTexFuncSGIS');
-end;
-
-procedure Read_GL_SGIS_fog_function;
-begin
-  glFogFuncSGIS := dglGetProcAddress('glFogFuncSGIS');
-  glGetFogFuncSGIS := dglGetProcAddress('glGetFogFuncSGIS');
-end;
-
-procedure Read_GL_SGIS_multisample;
-begin
-  glSampleMaskSGIS := dglGetProcAddress('glSampleMaskSGIS');
-  glSamplePatternSGIS := dglGetProcAddress('glSamplePatternSGIS');
-end;
-
-procedure Read_GL_SGIS_pixel_texture;
-begin
-  glPixelTexGenParameteriSGIS := dglGetProcAddress('glPixelTexGenParameteriSGIS');
-  glPixelTexGenParameterivSGIS := dglGetProcAddress('glPixelTexGenParameterivSGIS');
-  glPixelTexGenParameterfSGIS := dglGetProcAddress('glPixelTexGenParameterfSGIS');
-  glPixelTexGenParameterfvSGIS := dglGetProcAddress('glPixelTexGenParameterfvSGIS');
-  glGetPixelTexGenParameterivSGIS := dglGetProcAddress('glGetPixelTexGenParameterivSGIS');
-  glGetPixelTexGenParameterfvSGIS := dglGetProcAddress('glGetPixelTexGenParameterfvSGIS');
-end;
-
-procedure Read_GL_SGIS_point_parameters;
-begin
-  glPointParameterfSGIS := dglGetProcAddress('glPointParameterfSGIS');
-  glPointParameterfvSGIS := dglGetProcAddress('glPointParameterfvSGIS');
-end;
-
-procedure Read_GL_SGIS_sharpen_texture;
-begin
-  glSharpenTexFuncSGIS := dglGetProcAddress('glSharpenTexFuncSGIS');
-  glGetSharpenTexFuncSGIS := dglGetProcAddress('glGetSharpenTexFuncSGIS');
-end;
-
-procedure Read_GL_SGIS_texture4D;
-begin
-  glTexImage4DSGIS := dglGetProcAddress('glTexImage4DSGIS');
-  glTexSubImage4DSGIS := dglGetProcAddress('glTexSubImage4DSGIS');
-end;
-
-procedure Read_GL_SGIS_texture_color_mask;
-begin
-  glTextureColorMaskSGIS := dglGetProcAddress('glTextureColorMaskSGIS');
-end;
-
-procedure Read_GL_SGIS_texture_filter4;
-begin
-  glGetTexFilterFuncSGIS := dglGetProcAddress('glGetTexFilterFuncSGIS');
-  glTexFilterFuncSGIS := dglGetProcAddress('glTexFilterFuncSGIS');
-end;
-
-procedure Read_GL_SGIX_async;
-begin
-  glAsyncMarkerSGIX := dglGetProcAddress('glAsyncMarkerSGIX');
-  glFinishAsyncSGIX := dglGetProcAddress('glFinishAsyncSGIX');
-  glPollAsyncSGIX := dglGetProcAddress('glPollAsyncSGIX');
-  glGenAsyncMarkersSGIX := dglGetProcAddress('glGenAsyncMarkersSGIX');
-  glDeleteAsyncMarkersSGIX := dglGetProcAddress('glDeleteAsyncMarkersSGIX');
-  glIsAsyncMarkerSGIX := dglGetProcAddress('glIsAsyncMarkerSGIX');
-end;
-
-procedure Read_GL_SGIX_flush_raster;
-begin
-  glFlushRasterSGIX := dglGetProcAddress('glFlushRasterSGIX');
-end;
-
-procedure Read_GL_SGIX_fragment_lighting;
-begin
-  glFragmentColorMaterialSGIX := dglGetProcAddress('glFragmentColorMaterialSGIX');
-  glFragmentLightfSGIX := dglGetProcAddress('glFragmentLightfSGIX');
-  glFragmentLightfvSGIX := dglGetProcAddress('glFragmentLightfvSGIX');
-  glFragmentLightiSGIX := dglGetProcAddress('glFragmentLightiSGIX');
-  glFragmentLightivSGIX := dglGetProcAddress('glFragmentLightivSGIX');
-  glFragmentLightModelfSGIX := dglGetProcAddress('glFragmentLightModelfSGIX');
-  glFragmentLightModelfvSGIX := dglGetProcAddress('glFragmentLightModelfvSGIX');
-  glFragmentLightModeliSGIX := dglGetProcAddress('glFragmentLightModeliSGIX');
-  glFragmentLightModelivSGIX := dglGetProcAddress('glFragmentLightModelivSGIX');
-  glFragmentMaterialfSGIX := dglGetProcAddress('glFragmentMaterialfSGIX');
-  glFragmentMaterialfvSGIX := dglGetProcAddress('glFragmentMaterialfvSGIX');
-  glFragmentMaterialiSGIX := dglGetProcAddress('glFragmentMaterialiSGIX');
-  glFragmentMaterialivSGIX := dglGetProcAddress('glFragmentMaterialivSGIX');
-  glGetFragmentLightfvSGIX := dglGetProcAddress('glGetFragmentLightfvSGIX');
-  glGetFragmentLightivSGIX := dglGetProcAddress('glGetFragmentLightivSGIX');
-  glGetFragmentMaterialfvSGIX := dglGetProcAddress('glGetFragmentMaterialfvSGIX');
-  glGetFragmentMaterialivSGIX := dglGetProcAddress('glGetFragmentMaterialivSGIX');
-  glLightEnviSGIX := dglGetProcAddress('glLightEnviSGIX');
-end;
-
-procedure Read_GL_SGIX_framezoom;
-begin
-  glFrameZoomSGIX := dglGetProcAddress('glFrameZoomSGIX');
-end;
-
-procedure Read_GL_SGIX_igloo_interface;
-begin
-  glIglooInterfaceSGIX := dglGetProcAddress('glIglooInterfaceSGIX');
-end;
-
-procedure Read_GL_SGIX_instruments;
-begin
-  glGetInstrumentsSGIX := dglGetProcAddress('glGetInstrumentsSGIX');
-  glInstrumentsBufferSGIX := dglGetProcAddress('glInstrumentsBufferSGIX');
-  glPollInstrumentsSGIX := dglGetProcAddress('glPollInstrumentsSGIX');
-  glReadInstrumentsSGIX := dglGetProcAddress('glReadInstrumentsSGIX');
-  glStartInstrumentsSGIX := dglGetProcAddress('glStartInstrumentsSGIX');
-  glStopInstrumentsSGIX := dglGetProcAddress('glStopInstrumentsSGIX');
-end;
-
-procedure Read_GL_SGIX_list_priority;
-begin
-  glGetListParameterfvSGIX := dglGetProcAddress('glGetListParameterfvSGIX');
-  glGetListParameterivSGIX := dglGetProcAddress('glGetListParameterivSGIX');
-  glListParameterfSGIX := dglGetProcAddress('glListParameterfSGIX');
-  glListParameterfvSGIX := dglGetProcAddress('glListParameterfvSGIX');
-  glListParameteriSGIX := dglGetProcAddress('glListParameteriSGIX');
-  glListParameterivSGIX := dglGetProcAddress('glListParameterivSGIX');
-end;
-
-procedure Read_GL_SGIX_pixel_texture;
-begin
-  glPixelTexGenSGIX := dglGetProcAddress('glPixelTexGenSGIX');
-end;
-
-procedure Read_GL_SGIX_polynomial_ffd;
-begin
-  glDeformationMap3dSGIX := dglGetProcAddress('glDeformationMap3dSGIX');
-  glDeformationMap3fSGIX := dglGetProcAddress('glDeformationMap3fSGIX');
-  glDeformSGIX := dglGetProcAddress('glDeformSGIX');
-  glLoadIdentityDeformationMapSGIX := dglGetProcAddress('glLoadIdentityDeformationMapSGIX');
-end;
-
-procedure Read_GL_SGIX_reference_plane;
-begin
-  glReferencePlaneSGIX := dglGetProcAddress('glReferencePlaneSGIX');
-end;
-
-procedure Read_GL_SGIX_sprite;
-begin
-  glSpriteParameterfSGIX := dglGetProcAddress('glSpriteParameterfSGIX');
-  glSpriteParameterfvSGIX := dglGetProcAddress('glSpriteParameterfvSGIX');
-  glSpriteParameteriSGIX := dglGetProcAddress('glSpriteParameteriSGIX');
-  glSpriteParameterivSGIX := dglGetProcAddress('glSpriteParameterivSGIX');
-end;
-
-procedure Read_GL_SGIX_tag_sample_buffer;
-begin
-  glTagSampleBufferSGIX := dglGetProcAddress('glTagSampleBufferSGIX');
-end;
-
-procedure Read_GL_SGI_color_table;
-begin
-  glColorTableSGI := dglGetProcAddress('glColorTableSGI');
-  glColorTableParameterfvSGI := dglGetProcAddress('glColorTableParameterfvSGI');
-  glColorTableParameterivSGI := dglGetProcAddress('glColorTableParameterivSGI');
-  glCopyColorTableSGI := dglGetProcAddress('glCopyColorTableSGI');
-  glGetColorTableSGI := dglGetProcAddress('glGetColorTableSGI');
-  glGetColorTableParameterfvSGI := dglGetProcAddress('glGetColorTableParameterfvSGI');
-  glGetColorTableParameterivSGI := dglGetProcAddress('glGetColorTableParameterivSGI');
-end;
-
-procedure Read_GL_SUNX_constant_data;
-begin
-  glFinishTextureSUNX := dglGetProcAddress('glFinishTextureSUNX');
-end;
-
-procedure Read_GL_SUN_global_alpha;
-begin
-  glGlobalAlphaFactorbSUN := dglGetProcAddress('glGlobalAlphaFactorbSUN');
-  glGlobalAlphaFactorsSUN := dglGetProcAddress('glGlobalAlphaFactorsSUN');
-  glGlobalAlphaFactoriSUN := dglGetProcAddress('glGlobalAlphaFactoriSUN');
-  glGlobalAlphaFactorfSUN := dglGetProcAddress('glGlobalAlphaFactorfSUN');
-  glGlobalAlphaFactordSUN := dglGetProcAddress('glGlobalAlphaFactordSUN');
-  glGlobalAlphaFactorubSUN := dglGetProcAddress('glGlobalAlphaFactorubSUN');
-  glGlobalAlphaFactorusSUN := dglGetProcAddress('glGlobalAlphaFactorusSUN');
-  glGlobalAlphaFactoruiSUN := dglGetProcAddress('glGlobalAlphaFactoruiSUN');
-end;
-
-procedure Read_GL_SUN_mesh_array;
-begin
-  glDrawMeshArraysSUN := dglGetProcAddress('glDrawMeshArraysSUN');
-end;
-
-procedure Read_GL_SUN_triangle_list;
-begin
-  glReplacementCodeuiSUN := dglGetProcAddress('glReplacementCodeuiSUN');
-  glReplacementCodeusSUN := dglGetProcAddress('glReplacementCodeusSUN');
-  glReplacementCodeubSUN := dglGetProcAddress('glReplacementCodeubSUN');
-  glReplacementCodeuivSUN := dglGetProcAddress('glReplacementCodeuivSUN');
-  glReplacementCodeusvSUN := dglGetProcAddress('glReplacementCodeusvSUN');
-  glReplacementCodeubvSUN := dglGetProcAddress('glReplacementCodeubvSUN');
-  glReplacementCodePointerSUN := dglGetProcAddress('glReplacementCodePointerSUN');
-end;
-
-procedure Read_GL_SUN_vertex;
-begin
-  glColor4ubVertex2fSUN := dglGetProcAddress('glColor4ubVertex2fSUN');
-  glColor4ubVertex2fvSUN := dglGetProcAddress('glColor4ubVertex2fvSUN');
-  glColor4ubVertex3fSUN := dglGetProcAddress('glColor4ubVertex3fSUN');
-  glColor4ubVertex3fvSUN := dglGetProcAddress('glColor4ubVertex3fvSUN');
-  glColor3fVertex3fSUN := dglGetProcAddress('glColor3fVertex3fSUN');
-  glColor3fVertex3fvSUN := dglGetProcAddress('glColor3fVertex3fvSUN');
-  glNormal3fVertex3fSUN := dglGetProcAddress('glNormal3fVertex3fSUN');
-  glNormal3fVertex3fvSUN := dglGetProcAddress('glNormal3fVertex3fvSUN');
-  glColor4fNormal3fVertex3fSUN := dglGetProcAddress('glColor4fNormal3fVertex3fSUN');
-  glColor4fNormal3fVertex3fvSUN := dglGetProcAddress('glColor4fNormal3fVertex3fvSUN');
-  glTexCoord2fVertex3fSUN := dglGetProcAddress('glTexCoord2fVertex3fSUN');
-  glTexCoord2fVertex3fvSUN := dglGetProcAddress('glTexCoord2fVertex3fvSUN');
-  glTexCoord4fVertex4fSUN := dglGetProcAddress('glTexCoord4fVertex4fSUN');
-  glTexCoord4fVertex4fvSUN := dglGetProcAddress('glTexCoord4fVertex4fvSUN');
-  glTexCoord2fColor4ubVertex3fSUN := dglGetProcAddress('glTexCoord2fColor4ubVertex3fSUN');
-  glTexCoord2fColor4ubVertex3fvSUN := dglGetProcAddress('glTexCoord2fColor4ubVertex3fvSUN');
-  glTexCoord2fColor3fVertex3fSUN := dglGetProcAddress('glTexCoord2fColor3fVertex3fSUN');
-  glTexCoord2fColor3fVertex3fvSUN := dglGetProcAddress('glTexCoord2fColor3fVertex3fvSUN');
-  glTexCoord2fNormal3fVertex3fSUN := dglGetProcAddress('glTexCoord2fNormal3fVertex3fSUN');
-  glTexCoord2fNormal3fVertex3fvSUN := dglGetProcAddress('glTexCoord2fNormal3fVertex3fvSUN');
-  glTexCoord2fColor4fNormal3fVertex3fSUN := dglGetProcAddress('glTexCoord2fColor4fNormal3fVertex3fSUN');
-  glTexCoord2fColor4fNormal3fVertex3fvSUN := dglGetProcAddress('glTexCoord2fColor4fNormal3fVertex3fvSUN');
-  glTexCoord4fColor4fNormal3fVertex4fSUN := dglGetProcAddress('glTexCoord4fColor4fNormal3fVertex4fSUN');
-  glTexCoord4fColor4fNormal3fVertex4fvSUN := dglGetProcAddress('glTexCoord4fColor4fNormal3fVertex4fvSUN');
-  glReplacementCodeuiVertex3fSUN := dglGetProcAddress('glReplacementCodeuiVertex3fSUN');
-  glReplacementCodeuiVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiVertex3fvSUN');
-  glReplacementCodeuiColor4ubVertex3fSUN := dglGetProcAddress('glReplacementCodeuiColor4ubVertex3fSUN');
-  glReplacementCodeuiColor4ubVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiColor4ubVertex3fvSUN');
-  glReplacementCodeuiColor3fVertex3fSUN := dglGetProcAddress('glReplacementCodeuiColor3fVertex3fSUN');
-  glReplacementCodeuiColor3fVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiColor3fVertex3fvSUN');
-  glReplacementCodeuiNormal3fVertex3fSUN := dglGetProcAddress('glReplacementCodeuiNormal3fVertex3fSUN');
-  glReplacementCodeuiNormal3fVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiNormal3fVertex3fvSUN');
-  glReplacementCodeuiColor4fNormal3fVertex3fSUN := dglGetProcAddress('glReplacementCodeuiColor4fNormal3fVertex3fSUN');
-  glReplacementCodeuiColor4fNormal3fVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiColor4fNormal3fVertex3fvSUN');
-  glReplacementCodeuiTexCoord2fVertex3fSUN := dglGetProcAddress('glReplacementCodeuiTexCoord2fVertex3fSUN');
-  glReplacementCodeuiTexCoord2fVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiTexCoord2fVertex3fvSUN');
-  glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN := dglGetProcAddress('glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN');
-  glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN');
-  glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN := dglGetProcAddress('glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN');
-  glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN := dglGetProcAddress('glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN');
-end;
-
-{$IFDEF DGL_WIN}
-procedure Read_WGL_ARB_buffer_region;
-begin
-  wglCreateBufferRegionARB := dglGetProcAddress('wglCreateBufferRegionARB');
-  wglDeleteBufferRegionARB := dglGetProcAddress('wglDeleteBufferRegionARB');
-  wglSaveBufferRegionARB := dglGetProcAddress('wglSaveBufferRegionARB');
-  wglRestoreBufferRegionARB := dglGetProcAddress('wglRestoreBufferRegionARB');
-end;
-
-procedure Read_WGL_ARB_extensions_string;
-begin
-  wglGetExtensionsStringARB := dglGetProcAddress('wglGetExtensionsStringARB');
-end;
-
-procedure Read_WGL_ARB_make_current_read;
-begin
-  wglMakeContextCurrentARB := dglGetProcAddress('wglMakeContextCurrentARB');
-  wglGetCurrentReadDCARB := dglGetProcAddress('wglGetCurrentReadDCARB');
-end;
-
-procedure Read_WGL_ARB_pbuffer;
-begin
-  wglCreatePbufferARB := dglGetProcAddress('wglCreatePbufferARB');
-  wglGetPbufferDCARB := dglGetProcAddress('wglGetPbufferDCARB');
-  wglReleasePbufferDCARB := dglGetProcAddress('wglReleasePbufferDCARB');
-  wglDestroyPbufferARB := dglGetProcAddress('wglDestroyPbufferARB');
-  wglQueryPbufferARB := dglGetProcAddress('wglQueryPbufferARB');
-end;
-
-procedure Read_WGL_ARB_pixel_format;
-begin
-  wglGetPixelFormatAttribivARB := dglGetProcAddress('wglGetPixelFormatAttribivARB');
-  wglGetPixelFormatAttribfvARB := dglGetProcAddress('wglGetPixelFormatAttribfvARB');
-  wglChoosePixelFormatARB := dglGetProcAddress('wglChoosePixelFormatARB');
-end;
-
-procedure Read_WGL_ARB_pixel_format_float;
-begin
-  wglClampColorARB := dglGetProcAddress('wglClampColorARB');
-end;
-
-procedure Read_WGL_ARB_render_texture;
-begin
-  wglBindTexImageARB := dglGetProcAddress('wglBindTexImageARB');
-  wglReleaseTexImageARB := dglGetProcAddress('wglReleaseTexImageARB');
-  wglSetPbufferAttribARB := dglGetProcAddress('wglSetPbufferAttribARB');
-end;
-
-procedure Read_WGL_ARB_create_context;
-begin
-  wglCreateContextAttribsARB := dglGetProcAddress('wglCreateContextAttribsARB');
-end;
-
-procedure Read_WGL_AMD_gpu_association;
-begin
-  wglGetGPUIDsAMD := dglGetProcAddress('wglGetGPUIDsAMD');
-  wglGetGPUInfoAMD := dglGetProcAddress('wglGetGPUInfoAMD');
-  wglGetContextGPUIDAMD := dglGetProcAddress('wglGetContextGPUIDAMD');
-  wglCreateAssociatedContextAMD := dglGetProcAddress('wglCreateAssociatedContextAMD');
-  wglCreateAssociatedContextAttribsAMD := dglGetProcAddress('wglCreateAssociatedContextAttribsAMD');
-  wglDeleteAssociatedContextAMD := dglGetProcAddress('wglDeleteAssociatedContextAMD');
-  wglMakeAssociatedContextCurrentAMD := dglGetProcAddress('wglMakeAssociatedContextCurrentAMD');
-  wglGetCurrentAssociatedContextAMD := dglGetProcAddress('wglGetCurrentAssociatedContextAMD');
-  wglBlitContextFramebufferAMD := dglGetProcAddress('wglBlitContextFramebufferAMD');
-end;
-
-procedure Read_WGL_EXT_display_color_table;
-begin
-  wglCreateDisplayColorTableEXT := dglGetProcAddress('wglCreateDisplayColorTableEXT');
-  wglLoadDisplayColorTableEXT := dglGetProcAddress('wglLoadDisplayColorTableEXT');
-  wglBindDisplayColorTableEXT := dglGetProcAddress('wglBindDisplayColorTableEXT');
-  wglDestroyDisplayColorTableEXT := dglGetProcAddress('wglDestroyDisplayColorTableEXT');
-end;
-
-procedure Read_WGL_EXT_extensions_string;
-begin
-  wglGetExtensionsStringEXT := dglGetProcAddress('wglGetExtensionsStringEXT');
-end;
-
-procedure Read_WGL_EXT_make_current_read;
-begin
-  wglMakeContextCurrentEXT := dglGetProcAddress('wglMakeContextCurrentEXT');
-  wglGetCurrentReadDCEXT := dglGetProcAddress('wglGetCurrentReadDCEXT');
-end;
-
-procedure Read_WGL_EXT_pbuffer;
-begin
-  wglCreatePbufferEXT := dglGetProcAddress('wglCreatePbufferEXT');
-  wglGetPbufferDCEXT := dglGetProcAddress('wglGetPbufferDCEXT');
-  wglReleasePbufferDCEXT := dglGetProcAddress('wglReleasePbufferDCEXT');
-  wglDestroyPbufferEXT := dglGetProcAddress('wglDestroyPbufferEXT');
-  wglQueryPbufferEXT := dglGetProcAddress('wglQueryPbufferEXT');
-end;
-
-procedure Read_WGL_EXT_pixel_format;
-begin
-  wglGetPixelFormatAttribivEXT := dglGetProcAddress('wglGetPixelFormatAttribivEXT');
-  wglGetPixelFormatAttribfvEXT := dglGetProcAddress('wglGetPixelFormatAttribfvEXT');
-  wglChoosePixelFormatEXT := dglGetProcAddress('wglChoosePixelFormatEXT');
-end;
-
-procedure Read_WGL_EXT_swap_control;
-begin
-  wglSwapIntervalEXT := dglGetProcAddress('wglSwapIntervalEXT');
-  wglGetSwapIntervalEXT := dglGetProcAddress('wglGetSwapIntervalEXT');
-end;
-
-procedure Read_WGL_I3D_digital_video_control;
-begin
-  wglGetDigitalVideoParametersI3D := dglGetProcAddress('wglGetDigitalVideoParametersI3D');
-  wglSetDigitalVideoParametersI3D := dglGetProcAddress('wglSetDigitalVideoParametersI3D');
-end;
-
-procedure Read_WGL_I3D_gamma;
-begin
-  wglGetGammaTableParametersI3D := dglGetProcAddress('wglGetGammaTableParametersI3D');
-  wglSetGammaTableParametersI3D := dglGetProcAddress('wglSetGammaTableParametersI3D');
-  wglGetGammaTableI3D := dglGetProcAddress('wglGetGammaTableI3D');
-  wglSetGammaTableI3D := dglGetProcAddress('wglSetGammaTableI3D');
-end;
-
-procedure Read_WGL_I3D_genlock;
-begin
-  wglEnableGenlockI3D := dglGetProcAddress('wglEnableGenlockI3D');
-  wglDisableGenlockI3D := dglGetProcAddress('wglDisableGenlockI3D');
-  wglIsEnabledGenlockI3D := dglGetProcAddress('wglIsEnabledGenlockI3D');
-  wglGenlockSourceI3D := dglGetProcAddress('wglGenlockSourceI3D');
-  wglGetGenlockSourceI3D := dglGetProcAddress('wglGetGenlockSourceI3D');
-  wglGenlockSourceEdgeI3D := dglGetProcAddress('wglGenlockSourceEdgeI3D');
-  wglGetGenlockSourceEdgeI3D := dglGetProcAddress('wglGetGenlockSourceEdgeI3D');
-  wglGenlockSampleRateI3D := dglGetProcAddress('wglGenlockSampleRateI3D');
-  wglGetGenlockSampleRateI3D := dglGetProcAddress('wglGetGenlockSampleRateI3D');
-  wglGenlockSourceDelayI3D := dglGetProcAddress('wglGenlockSourceDelayI3D');
-  wglGetGenlockSourceDelayI3D := dglGetProcAddress('wglGetGenlockSourceDelayI3D');
-  wglQueryGenlockMaxSourceDelayI3D := dglGetProcAddress('wglQueryGenlockMaxSourceDelayI3D');
-end;
-
-procedure Read_WGL_I3D_image_buffer;
-begin
-  wglCreateImageBufferI3D := dglGetProcAddress('wglCreateImageBufferI3D');
-  wglDestroyImageBufferI3D := dglGetProcAddress('wglDestroyImageBufferI3D');
-  wglAssociateImageBufferEventsI3D := dglGetProcAddress('wglAssociateImageBufferEventsI3D');
-  wglReleaseImageBufferEventsI3D := dglGetProcAddress('wglReleaseImageBufferEventsI3D');
-end;
-
-procedure Read_WGL_I3D_swap_frame_lock;
-begin
-  wglEnableFrameLockI3D := dglGetProcAddress('wglEnableFrameLockI3D');
-  wglDisableFrameLockI3D := dglGetProcAddress('wglDisableFrameLockI3D');
-  wglIsEnabledFrameLockI3D := dglGetProcAddress('wglIsEnabledFrameLockI3D');
-  wglQueryFrameLockMasterI3D := dglGetProcAddress('wglQueryFrameLockMasterI3D');
-end;
-
-procedure Read_WGL_I3D_swap_frame_usage;
-begin
-  wglGetFrameUsageI3D := dglGetProcAddress('wglGetFrameUsageI3D');
-  wglBeginFrameTrackingI3D := dglGetProcAddress('wglBeginFrameTrackingI3D');
-  wglEndFrameTrackingI3D := dglGetProcAddress('wglEndFrameTrackingI3D');
-  wglQueryFrameTrackingI3D := dglGetProcAddress('wglQueryFrameTrackingI3D');
-end;
-
-procedure Read_WGL_NV_vertex_array_range;
-begin
-  wglAllocateMemoryNV := dglGetProcAddress('wglAllocateMemoryNV');
-  wglFreeMemoryNV := dglGetProcAddress('wglFreeMemoryNV');
-end;
-
-procedure Read_WGL_NV_present_video;
-begin
-  wglEnumerateVideoDevicesNV := dglGetProcAddress('wglEnumerateVideoDevicesNV');
-  wglBindVideoDeviceNV := dglGetProcAddress('wglBindVideoDeviceNV');
-  wglQueryCurrentContextNV := dglGetProcAddress('wglQueryCurrentContextNV');
-end;
-
-procedure Read_WGL_NV_video_out;
-begin
-  wglGetVideoDeviceNV := dglGetProcAddress('wglGetVideoDeviceNV');
-  wglReleaseVideoDeviceNV := dglGetProcAddress('wglReleaseVideoDeviceNV');
-  wglBindVideoImageNV := dglGetProcAddress('wglBindVideoImageNV');
-  wglReleaseVideoImageNV := dglGetProcAddress('wglReleaseVideoImageNV');
-  wglSendPbufferToVideoNV := dglGetProcAddress('wglSendPbufferToVideoNV');
-  wglGetVideoInfoNV := dglGetProcAddress('wglGetVideoInfoNV');
-end;
-
-procedure Read_WGL_NV_swap_group;
-begin
-  wglJoinSwapGroupNV := dglGetProcAddress('wglJoinSwapGroupNV');
-  wglBindSwapBarrierNV := dglGetProcAddress('wglBindSwapBarrierNV');
-  wglQuerySwapGroupNV := dglGetProcAddress('wglQuerySwapGroupNV');
-  wglQueryMaxSwapGroupsNV := dglGetProcAddress('wglQueryMaxSwapGroupsNV');
-  wglQueryFrameCountNV := dglGetProcAddress('wglQueryFrameCountNV');
-  wglResetFrameCountNV := dglGetProcAddress('wglResetFrameCountNV');
-end;
-
-procedure Read_WGL_NV_gpu_affinity;
-begin
-  wglEnumGpusNV := dglGetProcAddress('wglEnumGpusNV');
-  wglEnumGpuDevicesNV := dglGetProcAddress('wglEnumGpuDevicesNV');
-  wglCreateAffinityDCNV := dglGetProcAddress('wglCreateAffinityDCNV');
-  wglEnumGpusFromAffinityDCNV := dglGetProcAddress('wglEnumGpusFromAffinityDCNV');
-  wglDeleteDCNV := dglGetProcAddress('wglDeleteDCNV');
-end;
-
-procedure Read_WGL_OML_sync_control;
-begin
-  wglGetSyncValuesOML := dglGetProcAddress('wglGetSyncValuesOML');
-  wglGetMscRateOML := dglGetProcAddress('wglGetMscRateOML');
-  wglSwapBuffersMscOML := dglGetProcAddress('wglSwapBuffersMscOML');
-  wglSwapLayerBuffersMscOML := dglGetProcAddress('wglSwapLayerBuffersMscOML');
-  wglWaitForMscOML := dglGetProcAddress('wglWaitForMscOML');
-  wglWaitForSbcOML := dglGetProcAddress('wglWaitForSbcOML');
-end;
-
-procedure Read_WGL_3DL_stereo_control;
-begin
-  wglSetStereoEmitterState3DL := dglGetProcAddress('wglSetStereoEmitterState3DL');
-end;
-
-procedure Read_WIN_draw_range_elements;
-begin
-  glDrawRangeElementsWIN := dglGetProcAddress('glDrawRangeElementsWIN');
-end;
-
-procedure Read_WIN_swap_hint;
-begin
-  glAddSwapHintRectWIN := dglGetProcAddress('glAddSwapHintRectWIN');
-end;
-{$ENDIF}
-
-
-procedure ReadExtensions;
-begin
-  ReadOpenGLCore;
-  
-  Read_GL_3DFX_tbuffer;
-  Read_GL_APPLE_element_array;
-  Read_GL_APPLE_fence;
-  Read_GL_APPLE_vertex_array_object;
-  Read_GL_APPLE_vertex_array_range;
-  Read_GL_APPLE_texture_range;
-  Read_GL_APPLE_vertex_program_evaluators;
-  Read_GL_APPLE_object_purgeable;
-  Read_GL_ARB_matrix_palette;
-  Read_GL_ARB_multitexture;
-  Read_GL_ARB_point_parameters;
-  Read_GL_ARB_texture_compression;
-  Read_GL_ARB_transpose_matrix;
-  Read_GL_ARB_vertex_blend;
-  Read_GL_ARB_vertex_buffer_object;
-  Read_GL_ARB_vertex_program;
-  Read_GL_ARB_window_pos;
-  Read_GL_ARB_color_buffer_float;
-  Read_GL_ARB_Shader_Objects;
-  Read_GL_ARB_occlusion_query;
-  Read_GL_ARB_draw_instanced;
-  Read_GL_ARB_framebuffer_object;
-  Read_GL_ARB_geometry_shader4;
-  Read_GL_ARB_instanced_arrays;
-  Read_GL_ARB_map_buffer_range;
-  Read_GL_ARB_texture_buffer_object;
-  Read_GL_ARB_vertex_array_object;
-  Read_GL_ARB_uniform_buffer_object;
-  Read_GL_ARB_copy_buffer;
-  Read_GL_ARB_draw_elements_base_vertex;
-  Read_GL_ARB_provoking_vertex;
-  Read_GL_ARB_sync;
-  Read_GL_ARB_texture_multisample;
-  Read_GL_ARB_draw_buffers_blend;
-  Read_GL_ARB_sample_shading;
-  Read_GL_ATI_draw_buffers;
-  Read_GL_ATI_element_array;
-  Read_GL_ATI_envmap_bumpmap;
-  Read_GL_ATI_fragment_shader;
-  Read_GL_ATI_map_object_buffer;
-  Read_GL_ATI_pn_triangles;
-  Read_GL_ATI_separate_stencil;
-  Read_GL_ATI_vertex_array_object;
-  Read_GL_ATI_vertex_attrib_array_object;
-  Read_GL_ATI_vertex_streams;
-  Read_GL_AMD_performance_monitor;
-  Read_GL_EXT_blend_color;
-  Read_GL_EXT_blend_func_separate;
-  Read_GL_EXT_blend_minmax;
-  Read_GL_EXT_color_subtable;
-  Read_GL_EXT_compiled_vertex_array;
-  Read_GL_EXT_convolution;
-  Read_GL_EXT_coordinate_frame;
-  Read_GL_EXT_copy_texture;
-  Read_GL_EXT_cull_vertex;
-  Read_GL_EXT_draw_range_elements;
-  Read_GL_EXT_fog_coord;
-  Read_GL_EXT_framebuffer_object;
-  Read_GL_EXT_histogram;
-  Read_GL_EXT_index_func;
-  Read_GL_EXT_index_material;
-  Read_GL_EXT_multi_draw_arrays;
-  Read_GL_EXT_multisample;
-  Read_GL_EXT_paletted_texture;
-  Read_GL_EXT_pixel_transform;
-  Read_GL_EXT_point_parameters;
-  Read_GL_EXT_polygon_offset;
-  Read_GL_EXT_secondary_color;
-  Read_GL_EXT_stencil_two_side;
-  Read_GL_EXT_subtexture;
-  Read_GL_EXT_texture3D;
-  Read_GL_EXT_texture_object;
-  Read_GL_EXT_texture_perturb_normal;
-  Read_GL_EXT_vertex_array;
-  Read_GL_EXT_vertex_shader;
-  Read_GL_EXT_vertex_weighting;
-  Read_GL_EXT_depth_bounds_test;
-  Read_GL_EXT_blend_equation_separate;
-  Read_GL_EXT_stencil_clear_tag;
-  Read_GL_EXT_framebuffer_blit;
-  Read_GL_EXT_framebuffer_multisample;
-  Read_GL_EXT_timer_query;
-  Read_GL_EXT_gpu_program_parameters;
-  Read_GL_EXT_bindable_uniform;
-  Read_GL_EXT_draw_buffers2;
-  Read_GL_EXT_draw_instanced;
-  Read_GL_EXT_geometry_shader4;
-  Read_GL_EXT_gpu_shader4;
-  Read_GL_EXT_texture_array;
-  Read_GL_EXT_texture_buffer_object;
-  Read_GL_EXT_texture_integer;
-  Read_GL_EXT_transform_feedback;
-  Read_GL_EXT_direct_state_access;
-  Read_GL_HP_image_transform;
-  Read_GL_IBM_multimode_draw_arrays;
-  Read_GL_IBM_vertex_array_lists;
-  Read_GL_INGR_blend_func_separate;
-  Read_GL_INTEL_parallel_arrays;
-  Read_GL_MESA_resize_buffers;
-  Read_GL_MESA_window_pos;
-  Read_GL_NV_evaluators;
-  Read_GL_NV_fence;
-  Read_GL_NV_fragment_program;
-  Read_GL_NV_half_float;
-  Read_GL_NV_occlusion_query;
-  Read_GL_NV_pixel_data_range;
-  Read_GL_NV_point_sprite;
-  Read_GL_NV_primitive_restart;
-  Read_GL_NV_register_combiners;
-  Read_GL_NV_register_combiners2;
-  Read_GL_NV_vertex_array_range;
-  Read_GL_NV_vertex_program;
-  Read_GL_NV_depth_buffer_float;
-  Read_GL_NV_framebuffer_multisample_coverage;
-  Read_GL_NV_geometry_program4;
-  Read_GL_NV_gpu_program4;
-  Read_GL_NV_parameter_buffer_object;
-  Read_GL_NV_transform_feedback;
-  Read_GL_NV_conditional_render;
-  Read_GL_NV_present_video;
-  Read_GL_NV_explicit_multisample;
-  Read_GL_NV_transform_feedback2;
-  Read_GL_PGI_misc_hints;
-  Read_GL_SGIS_detail_texture;
-  Read_GL_SGIS_fog_function;
-  Read_GL_SGIS_multisample;
-  Read_GL_SGIS_pixel_texture;
-  Read_GL_SGIS_point_parameters;
-  Read_GL_SGIS_sharpen_texture;
-  Read_GL_SGIS_texture4D;
-  Read_GL_SGIS_texture_color_mask;
-  Read_GL_SGIS_texture_filter4;
-  Read_GL_SGIX_async;
-  Read_GL_SGIX_flush_raster;
-  Read_GL_SGIX_fragment_lighting;
-  Read_GL_SGIX_framezoom;
-  Read_GL_SGIX_igloo_interface;
-  Read_GL_SGIX_instruments;
-  Read_GL_SGIX_list_priority;
-  Read_GL_SGIX_pixel_texture;
-  Read_GL_SGIX_polynomial_ffd;
-  Read_GL_SGIX_reference_plane;
-  Read_GL_SGIX_sprite;
-  Read_GL_SGIX_tag_sample_buffer;
-  Read_GL_SGI_color_table;
-  Read_GL_SUNX_constant_data;
-  Read_GL_SUN_global_alpha;
-  Read_GL_SUN_mesh_array;
-  Read_GL_SUN_triangle_list;
-  Read_GL_SUN_vertex;
-
-{$IFDEF DGL_WIN}
-  Read_WGL_ARB_buffer_region;
-  Read_WGL_ARB_extensions_string;
-  Read_WGL_ARB_make_current_read;
-  Read_WGL_ARB_pbuffer;
-  Read_WGL_ARB_pixel_format;
-  Read_WGL_ARB_pixel_format_float;
-  Read_WGL_ARB_render_texture;
-  Read_WGL_ARB_create_context;
-  Read_WGL_AMD_gpu_association;
-  Read_WGL_EXT_display_color_table;
-  Read_WGL_EXT_extensions_string;
-  Read_WGL_EXT_make_current_read;
-  Read_WGL_EXT_pbuffer;
-  Read_WGL_EXT_pixel_format;
-  Read_WGL_EXT_swap_control;
-  Read_WGL_I3D_digital_video_control;
-  Read_WGL_I3D_gamma;
-  Read_WGL_I3D_genlock;
-  Read_WGL_I3D_image_buffer;
-  Read_WGL_I3D_swap_frame_lock;
-  Read_WGL_I3D_swap_frame_usage;
-  Read_WGL_NV_vertex_array_range;
-  Read_WGL_NV_present_video;
-  Read_WGL_NV_video_out;
-  Read_WGL_NV_swap_group;
-  Read_WGL_NV_gpu_affinity;
-  Read_WGL_OML_sync_control;
-  Read_WGL_3DL_stereo_control;
-
-  Read_WIN_draw_range_elements;
-  Read_WIN_swap_hint;
-{$ENDIF}
-
-  ExtensionsRead := True;
-end;
-
-// =============================================================================
-//  ReadCoreVersion
-// =============================================================================
-
-procedure ReadCoreVersion;
-var
-  AnsiBuffer: AnsiString;
-  Buffer: String;
-  MajorVersion, MinorVersion: Integer;
-
-  procedure TrimAndSplitVersionString(Buffer: String; var Max, Min: Integer);
-    // Peels out the X.Y form from the given Buffer which must contain a version string like "text Minor.Major.Build text"
-    // at least however "Major.Minor".
-  var
-    Separator: Integer;
-  begin
-    try
-      // There must be at least one dot to separate major and minor version number.
-      Separator := Pos('.', Buffer);
-      // At least one number must be before and one after the dot.
-      if (Separator > 1) and (Separator < Length(Buffer)) and (AnsiChar(Buffer[Separator - 1]) in ['0'..'9']) and
-      (AnsiChar(Buffer[Separator + 1]) in ['0'..'9']) then
-      begin
-        // OK, it's a valid version string. Now remove unnecessary parts.
-        Dec(Separator);
-        // Find last non-numeric character before version number.
-        while (Separator > 0) and (AnsiChar(Buffer[Separator]) in ['0'..'9']) do
-          Dec(Separator);
-        // Delete leading characters which do not belong to the version string.
-        Delete(Buffer, 1, Separator);
-        Separator := Pos('.', Buffer) + 1;
-        // Find first non-numeric character after version number
-        while (Separator <= Length(Buffer)) and (AnsiChar(Buffer[Separator]) in ['0'..'9']) do
-          Inc(Separator);
-        // delete trailing characters not belonging to the version string
-        Delete(Buffer, Separator, 255);
-        // Now translate the numbers.
-        Separator := Pos('.', Buffer); // This is necessary because the buffer length might have changed.
-        Max := StrToInt(Copy(Buffer, 1, Separator - 1));
-        Min := StrToInt(Copy(Buffer, Separator + 1, 1));
-      end
-      else
-        Abort;
-    except
-      Min := 0;
-      Max := 0;
-    end;
-  end;
-
-
-begin
-  // determine version of implementation
-  // GL
-  if not Assigned(@glGetString) then
-    glGetString := dglGetProcAddress('glGetString');
-
-  AnsiBuffer := glGetString(GL_VERSION);
-  Buffer := String(AnsiBuffer);
-
-  TrimAndSplitVersionString(Buffer, MajorVersion, MinorVersion);
-
-  GL_VERSION_1_0 := True;
-  GL_VERSION_1_1 := False;
-  GL_VERSION_1_2 := False;
-  GL_VERSION_1_3 := False;
-  GL_VERSION_1_4 := False;
-  GL_VERSION_1_5 := False;
-  GL_VERSION_2_0 := False;
-  GL_VERSION_2_1 := False;
-  GL_VERSION_3_0 := False;
-  GL_VERSION_3_1 := False;
-  GL_VERSION_3_2 := False;
-
-  if MajorVersion = 1 then
-  begin
-    if MinorVersion >= 1 then
-      GL_VERSION_1_1 := True;
-    if MinorVersion >= 2 then
-      GL_VERSION_1_2 := True;
-    if MinorVersion >= 3 then
-      GL_VERSION_1_3 := True;
-    if MinorVersion >= 4 then
-      GL_VERSION_1_4 := True;
-    if MinorVersion >= 5 then
-      GL_VERSION_1_5 := True;
-  end;
-
-  if MajorVersion >= 2 then
-  begin
-    GL_VERSION_1_1 := True;
-    GL_VERSION_1_2 := True;
-    GL_VERSION_1_3 := True;
-    GL_VERSION_1_4 := True;
-    GL_VERSION_1_5 := True;
-    GL_VERSION_2_0 := True;
-
-    if MinorVersion >= 1 then
-      GL_VERSION_2_1 := True;
-  end;
-
-  if MajorVersion >= 3 then
-  begin
-    GL_VERSION_2_1 := True;
-    GL_VERSION_3_0 := True;
-    
-    if MinorVersion >= 1 then
-      GL_VERSION_3_1 := True;
-    if MinorVersion >= 2 then
-      GL_VERSION_3_2 := True;
-  end;
-
-
-  // GLU
-  GLU_VERSION_1_1 := False;
-  GLU_VERSION_1_2 := False;
-  GLU_VERSION_1_3 := False;
-
-  if Assigned(gluGetString) then begin
-    AnsiBuffer := gluGetString(GLU_VERSION);
-    Buffer := String(AnsiBuffer);
-
-    TrimAndSplitVersionString(Buffer, Majorversion, MinorVersion);
-
-    GLU_VERSION_1_1 := True;
-
-    if MinorVersion >= 2 then
-      GLU_VERSION_1_2 := True;
-
-    if MinorVersion >= 3 then
-      GLU_VERSION_1_3 := True;
-  end;
-end;
-
-
-// =============================================================================
-//  ReadImplementationProperties
-// =============================================================================
-
-procedure ReadImplementationProperties;
-var
-  Buffer: Ansistring;
-begin
-  ReadCoreVersion;
-
-  // Check all extensions
-  Buffer := Int_GetExtensionString;
-
-  // === 3DFX ====================================================================
-  GL_3DFX_multisample := Int_CheckExtension(Buffer, 'GL_3DFX_multisample');
-  GL_3DFX_tbuffer := Int_CheckExtension(Buffer, 'GL_3DFX_tbuffer');
-  GL_3DFX_texture_compression_FXT1 := Int_CheckExtension(Buffer, 'GL_3DFX_texture_compression_FXT1');
-
-  // === APPLE ===================================================================
-  GL_APPLE_client_storage := Int_CheckExtension(Buffer, 'GL_APPLE_client_storage');
-  GL_APPLE_element_array := Int_CheckExtension(Buffer, 'GL_APPLE_element_array');
-  GL_APPLE_fence := Int_CheckExtension(Buffer, 'GL_APPLE_fence');
-  GL_APPLE_specular_vector := Int_CheckExtension(Buffer, 'GL_APPLE_specular_vector');
-  GL_APPLE_transform_hint := Int_CheckExtension(Buffer, 'GL_APPLE_transform_hint');
-  GL_APPLE_vertex_array_object := Int_CheckExtension(Buffer, 'GL_APPLE_vertex_array_object');
-  GL_APPLE_vertex_array_range := Int_CheckExtension(Buffer, 'GL_APPLE_vertex_array_range');
-  GL_APPLE_ycbcr_422 := Int_CheckExtension(Buffer, 'GL_APPLE_ycbcr_422');
-  GL_APPLE_texture_range := Int_CheckExtension(Buffer, 'GL_APPLE_texture_range');
-  GL_APPLE_float_pixels := Int_CheckExtension(Buffer, 'GL_APPLE_float_pixels');
-  GL_APPLE_vertex_program_evaluators := Int_CheckExtension(Buffer, 'GL_APPLE_vertex_program_evaluators');
-  GL_APPLE_aux_depth_stencil := Int_CheckExtension(Buffer, 'GL_APPLE_aux_depth_stencil');
-  GL_APPLE_object_purgeable := Int_CheckExtension(Buffer, 'GL_APPLE_object_purgeable');
-
-  // === ARB =====================================================================
-  GL_ARB_depth_texture := Int_CheckExtension(Buffer, 'GL_ARB_depth_texture');
-  GL_ARB_fragment_program := Int_CheckExtension(Buffer, 'GL_ARB_fragment_program');
-  GL_ARB_imaging := Int_CheckExtension(Buffer, 'GL_ARB_imaging');
-  GL_ARB_matrix_palette := Int_CheckExtension(Buffer, 'GL_ARB_matrix_palette');
-  GL_ARB_multisample := Int_CheckExtension(Buffer, 'GL_ARB_multisample');
-  GL_ARB_multitexture := Int_CheckExtension(Buffer, 'GL_ARB_multitexture');
-  GL_ARB_point_parameters := Int_CheckExtension(Buffer, 'GL_ARB_point_parameters');
-  GL_ARB_shadow := Int_CheckExtension(Buffer, 'GL_ARB_shadow');
-  GL_ARB_shadow_ambient := Int_CheckExtension(Buffer, 'GL_ARB_shadow_ambient');
-  GL_ARB_texture_border_clamp := Int_CheckExtension(Buffer, 'GL_ARB_texture_border_clamp');
-  GL_ARB_texture_compression := Int_CheckExtension(Buffer, 'GL_ARB_texture_compression');
-  GL_ARB_texture_cube_map := Int_CheckExtension(Buffer, 'GL_ARB_texture_cube_map');
-  GL_ARB_texture_env_add := Int_CheckExtension(Buffer, 'GL_ARB_texture_env_add');
-  GL_ARB_texture_env_combine := Int_CheckExtension(Buffer, 'GL_ARB_texture_env_combine');
-  GL_ARB_texture_env_crossbar := Int_CheckExtension(Buffer, 'GL_ARB_texture_env_crossbar');
-  GL_ARB_texture_env_dot3 := Int_CheckExtension(Buffer, 'GL_ARB_texture_env_dot3');
-  GL_ARB_texture_mirrored_repeat := Int_CheckExtension(Buffer, 'GL_ARB_texture_mirrored_repeat');
-  GL_ARB_transpose_matrix := Int_CheckExtension(Buffer, 'GL_ARB_transpose_matrix');
-  GL_ARB_vertex_blend := Int_CheckExtension(Buffer, 'GL_ARB_vertex_blend');
-  GL_ARB_vertex_buffer_object := Int_CheckExtension(Buffer, 'GL_ARB_vertex_buffer_object');
-  GL_ARB_vertex_program := Int_CheckExtension(Buffer, 'GL_ARB_vertex_program');
-  GL_ARB_window_pos := Int_CheckExtension(Buffer, 'GL_ARB_window_pos');
-  GL_ARB_shader_objects := Int_CheckExtension(Buffer, 'GL_ARB_shader_objects');
-  GL_ARB_vertex_shader := Int_CheckExtension(Buffer, 'GL_ARB_vertex_shader');
-  GL_ARB_fragment_shader := Int_CheckExtension(Buffer, 'GL_ARB_fragment_shader');
-  GL_ARB_occlusion_query := Int_CheckExtension(Buffer, 'GL_ARB_occlusion_query');
-  GL_ARB_shading_language_100 := Int_CheckExtension(Buffer, 'GL_ARB_shading_language_100');
-  GL_ARB_point_sprite := Int_CheckExtension(Buffer, 'GL_ARB_point_sprite');
-  GL_ARB_texture_non_power_of_two := Int_CheckExtension(Buffer, 'GL_ARB_texture_non_power_of_two');
-  GL_ARB_fragment_program_shadow := Int_CheckExtension(Buffer, 'GL_ARB_fragment_program_shadow');
-  GL_ARB_draw_buffers := Int_CheckExtension(Buffer, 'GL_ARB_draw_buffers');
-  GL_ARB_texture_rectangle := Int_CheckExtension(Buffer, 'GL_ARB_texture_rectangle');
-  GL_ARB_color_buffer_float := Int_CheckExtension(Buffer, 'GL_ARB_color_buffer_float');
-  GL_ARB_half_float_pixel := Int_CheckExtension(Buffer, 'GL_ARB_half_float_pixel');
-  GL_ARB_texture_float := Int_CheckExtension(Buffer, 'GL_ARB_texture_float');
-  GL_ARB_pixel_buffer_object := Int_CheckExtension(Buffer, 'GL_ARB_pixel_buffer_object');
-  GL_ARB_depth_buffer_float := Int_CheckExtension(Buffer, 'GL_ARB_depth_buffer_float');
-  GL_ARB_draw_instanced := Int_CheckExtension(Buffer, 'GL_ARB_draw_instanced');
-  GL_ARB_framebuffer_object := Int_CheckExtension(Buffer, 'GL_ARB_framebuffer_object');
-  GL_ARB_framebuffer_sRGB := Int_CheckExtension(Buffer, 'GL_ARB_framebuffer_sRGB');
-  GL_ARB_geometry_shader4 := Int_CheckExtension(Buffer, 'GL_ARB_geometry_shader4');
-  GL_ARB_half_float_vertex := Int_CheckExtension(Buffer, 'GL_ARB_half_float_vertex');
-  GL_ARB_instanced_arrays := Int_CheckExtension(Buffer, 'GL_ARB_instanced_arrays');
-  GL_ARB_map_buffer_range := Int_CheckExtension(Buffer, 'GL_ARB_map_buffer_range');
-  GL_ARB_texture_buffer_object := Int_CheckExtension(Buffer, 'GL_ARB_texture_buffer_object');
-  GL_ARB_texture_compression_rgtc := Int_CheckExtension(Buffer, 'GL_ARB_texture_compression_rgtc');
-  GL_ARB_texture_rg := Int_CheckExtension(Buffer, 'GL_ARB_texture_rg');
-  GL_ARB_vertex_array_object := Int_CheckExtension(Buffer, 'GL_ARB_vertex_array_object');
-  GL_ARB_uniform_buffer_object := Int_CheckExtension(Buffer, 'GL_ARB_uniform_buffer_object');
-  GL_ARB_compatibility := Int_CheckExtension(Buffer, 'GL_ARB_compatibility');
-  GL_ARB_copy_buffer := Int_CheckExtension(Buffer, 'GL_ARB_copy_buffer');
-  GL_ARB_shader_texture_lod := Int_CheckExtension(Buffer, 'GL_ARB_shader_texture_lod');
-  GL_ARB_depth_clamp := Int_CheckExtension(Buffer, 'GL_ARB_depth_clamp');
-  GL_ARB_draw_elements_base_vertex := Int_CheckExtension(Buffer, 'GL_ARB_draw_elements_base_vertex');
-  GL_ARB_fragment_coord_conventions := Int_CheckExtension(Buffer, 'GL_ARB_fragment_coord_conventions');
-  GL_ARB_provoking_vertex := Int_CheckExtension(Buffer, 'GL_ARB_provoking_vertex');
-  GL_ARB_seamless_cube_map := Int_CheckExtension(Buffer, 'GL_ARB_seamless_cube_map');
-  GL_ARB_sync := Int_CheckExtension(Buffer, 'GL_ARB_sync');
-  GL_ARB_texture_multisample := Int_CheckExtension(Buffer, 'GL_ARB_texture_multisample');
-  GL_ARB_vertex_array_bgra := Int_CheckExtension(Buffer, 'GL_ARB_vertex_array_bgra');
-  GL_ARB_draw_buffers_blend := Int_CheckExtension(Buffer, 'GL_ARB_draw_buffers_blend');
-  GL_ARB_sample_shading := Int_CheckExtension(Buffer, 'GL_ARB_sample_shading');
-  GL_ARB_texture_cube_map_array := Int_CheckExtension(Buffer, 'GL_ARB_texture_cube_map_array');
-  GL_ARB_texture_gather := Int_CheckExtension(Buffer, 'GL_ARB_texture_gather');
-  GL_ARB_texture_query_lod := Int_CheckExtension(Buffer, 'GL_ARB_texture_query_lod');
-  
-  // === ATI/AMD =================================================================
-  GL_ATI_draw_buffers := Int_CheckExtension(Buffer, 'GL_ATI_draw_buffers');
-  GL_ATI_element_array := Int_CheckExtension(Buffer, 'GL_ATI_element_array');
-  GL_ATI_envmap_bumpmap := Int_CheckExtension(Buffer, 'GL_ATI_envmap_bumpmap');
-  GL_ATI_fragment_shader := Int_CheckExtension(Buffer, 'GL_ATI_fragment_shader');
-  GL_ATI_map_object_buffer := Int_CheckExtension(Buffer, 'GL_ATI_map_object_buffer');
-  GL_ATI_pn_triangles := Int_CheckExtension(Buffer, 'GL_ATI_pn_triangles');
-  GL_ATI_separate_stencil := Int_CheckExtension(Buffer, 'GL_ATI_separate_stencil');
-  GL_ATI_text_fragment_shader := Int_CheckExtension(Buffer, 'GL_ATI_text_fragment_shader');
-  GL_ATI_texture_env_combine3 := Int_CheckExtension(Buffer, 'GL_ATI_texture_env_combine3');
-  GL_ATI_texture_float := Int_CheckExtension(Buffer, 'GL_ATI_texture_float');
-  GL_ATI_texture_mirror_once := Int_CheckExtension(Buffer, 'GL_ATI_texture_mirror_once');
-  GL_ATI_vertex_array_object := Int_CheckExtension(Buffer, 'GL_ATI_vertex_array_object');
-  GL_ATI_vertex_attrib_array_object := Int_CheckExtension(Buffer, 'GL_ATI_vertex_attrib_array_object');
-  GL_ATI_vertex_streams := Int_CheckExtension(Buffer, 'GL_ATI_vertex_streams');
-  GL_ATI_meminfo := Int_CheckExtension(Buffer, 'GL_ATI_meminfo');
-  GL_AMD_performance_monitor := Int_CheckExtension(Buffer, 'GL_AMD_performance_monitor');
-  GL_AMD_texture_texture4 := Int_CheckExtension(Buffer, 'GL_AMD_texture_texture4');
-  GL_AMD_vertex_shader_tesselator := Int_CheckExtension(Buffer, 'GL_AMD_vertex_shader_tesselator');
-
-  // === EXT =====================================================================
-  GL_EXT_422_pixels := Int_CheckExtension(Buffer, 'GL_EXT_422_pixels');
-  GL_EXT_abgr := Int_CheckExtension(Buffer, 'GL_EXT_abgr');
-  GL_EXT_bgra := Int_CheckExtension(Buffer, 'GL_EXT_bgra');
-  GL_EXT_blend_color := Int_CheckExtension(Buffer, 'GL_EXT_blend_color');
-  GL_EXT_blend_func_separate := Int_CheckExtension(Buffer, 'GL_EXT_blend_func_separate');
-  GL_EXT_blend_logic_op := Int_CheckExtension(Buffer, 'GL_EXT_blend_logic_op');
-  GL_EXT_blend_minmax := Int_CheckExtension(Buffer, 'GL_EXT_blend_minmax');
-  GL_EXT_blend_subtract := Int_CheckExtension(Buffer, 'GL_EXT_blend_subtract');
-  GL_EXT_clip_volume_hint := Int_CheckExtension(Buffer, 'GL_EXT_clip_volume_hint');
-  GL_EXT_cmyka := Int_CheckExtension(Buffer, 'GL_EXT_cmyka');
-  GL_EXT_color_matrix := Int_CheckExtension(Buffer, 'GL_EXT_color_matrix');
-  GL_EXT_color_subtable := Int_CheckExtension(Buffer, 'GL_EXT_color_subtable');
-  GL_EXT_compiled_vertex_array := Int_CheckExtension(Buffer, 'GL_EXT_compiled_vertex_array');
-  GL_EXT_convolution := Int_CheckExtension(Buffer, 'GL_EXT_convolution');
-  GL_EXT_coordinate_frame := Int_CheckExtension(Buffer, 'GL_EXT_coordinate_frame');
-  GL_EXT_copy_texture := Int_CheckExtension(Buffer, 'GL_EXT_copy_texture');
-  GL_EXT_cull_vertex := Int_CheckExtension(Buffer, 'GL_EXT_cull_vertex');
-  GL_EXT_draw_range_elements := Int_CheckExtension(Buffer, 'GL_EXT_draw_range_elements');
-  GL_EXT_fog_coord := Int_CheckExtension(Buffer, 'GL_EXT_fog_coord');
-  GL_EXT_framebuffer_object := Int_CheckExtension(Buffer, 'GL_EXT_framebuffer_object');
-  GL_EXT_histogram := Int_CheckExtension(Buffer, 'GL_EXT_histogram');
-  GL_EXT_index_array_formats := Int_CheckExtension(Buffer, 'GL_EXT_index_array_formats');
-  GL_EXT_index_func := Int_CheckExtension(Buffer, 'GL_EXT_index_func');
-  GL_EXT_index_material := Int_CheckExtension(Buffer, 'GL_EXT_index_material');
-  GL_EXT_index_texture := Int_CheckExtension(Buffer, 'GL_EXT_index_texture');
-  GL_EXT_light_texture := Int_CheckExtension(Buffer, 'GL_EXT_light_texture');
-  GL_EXT_misc_attribute := Int_CheckExtension(Buffer, 'GL_EXT_misc_attribute');
-  GL_EXT_multi_draw_arrays := Int_CheckExtension(Buffer, 'GL_EXT_multi_draw_arrays');
-  GL_EXT_multisample := Int_CheckExtension(Buffer, 'GL_EXT_multisample');
-  GL_EXT_packed_pixels := Int_CheckExtension(Buffer, 'GL_EXT_packed_pixels');
-  GL_EXT_paletted_texture := Int_CheckExtension(Buffer, 'GL_EXT_paletted_texture');
-  GL_EXT_pixel_transform := Int_CheckExtension(Buffer, 'GL_EXT_pixel_transform');
-  GL_EXT_pixel_transform_color_table := Int_CheckExtension(Buffer, 'GL_EXT_pixel_transform_color_table');
-  GL_EXT_point_parameters := Int_CheckExtension(Buffer, 'GL_EXT_point_parameters');
-  GL_EXT_polygon_offset := Int_CheckExtension(Buffer, 'GL_EXT_polygon_offset');
-  GL_EXT_rescale_normal := Int_CheckExtension(Buffer, 'GL_EXT_rescale_normal');
-  GL_EXT_secondary_color := Int_CheckExtension(Buffer, 'GL_EXT_secondary_color');
-  GL_EXT_separate_specular_color := Int_CheckExtension(Buffer, 'GL_EXT_separate_specular_color');
-  GL_EXT_shadow_funcs := Int_CheckExtension(Buffer, 'GL_EXT_shadow_funcs');
-  GL_EXT_shared_texture_palette := Int_CheckExtension(Buffer, 'GL_EXT_shared_texture_palette');
-  GL_EXT_stencil_two_side := Int_CheckExtension(Buffer, 'GL_EXT_stencil_two_side');
-  GL_EXT_stencil_wrap := Int_CheckExtension(Buffer, 'GL_EXT_stencil_wrap');
-  GL_EXT_subtexture := Int_CheckExtension(Buffer, 'GL_EXT_subtexture');
-  GL_EXT_texture := Int_CheckExtension(Buffer, 'GL_EXT_texture');
-  GL_EXT_texture3D := Int_CheckExtension(Buffer, 'GL_EXT_texture3D');
-  GL_EXT_texture_compression_s3tc := Int_CheckExtension(Buffer, 'GL_EXT_texture_compression_s3tc');
-  GL_EXT_texture_cube_map := Int_CheckExtension(Buffer, 'GL_EXT_texture_cube_map');
-  GL_EXT_texture_edge_clamp := Int_CheckExtension(Buffer, 'GL_EXT_texture_edge_clamp');
-  GL_EXT_texture_env_add := Int_CheckExtension(Buffer, 'GL_EXT_texture_env_add');
-  GL_EXT_texture_env_combine := Int_CheckExtension(Buffer, 'GL_EXT_texture_env_combine');
-  GL_EXT_texture_env_dot3 := Int_CheckExtension(Buffer, 'GL_EXT_texture_env_dot3');
-  GL_EXT_texture_filter_anisotropic := Int_CheckExtension(Buffer, 'GL_EXT_texture_filter_anisotropic');
-  GL_EXT_texture_lod_bias := Int_CheckExtension(Buffer, 'GL_EXT_texture_lod_bias');
-  GL_EXT_texture_object := Int_CheckExtension(Buffer, 'GL_EXT_texture_object');
-  GL_EXT_texture_perturb_normal := Int_CheckExtension(Buffer, 'GL_EXT_texture_perturb_normal');
-  GL_EXT_texture_rectangle := Int_CheckExtension(Buffer, 'GL_EXT_texture_rectangle');
-  GL_EXT_vertex_array := Int_CheckExtension(Buffer, 'GL_EXT_vertex_array');
-  GL_EXT_vertex_shader := Int_CheckExtension(Buffer, 'GL_EXT_vertex_shader');
-  GL_EXT_vertex_weighting := Int_CheckExtension(Buffer, 'GL_EXT_vertex_weighting');
-  GL_EXT_depth_bounds_test := Int_CheckExtension(Buffer, 'GL_EXT_depth_bounds_test');
-  GL_EXT_texture_mirror_clamp := Int_CheckExtension(Buffer, 'GL_EXT_texture_mirror_clamp');
-  GL_EXT_blend_equation_separate := Int_CheckExtension(Buffer, 'GL_EXT_blend_equation_separate');
-  GL_EXT_pixel_buffer_object := Int_CheckExtension(Buffer, 'GL_EXT_pixel_buffer_object');
-  GL_EXT_texture_compression_dxt1 := Int_CheckExtension(Buffer, 'GL_EXT_texture_compression_dxt1');
-  GL_EXT_stencil_clear_tag := Int_CheckExtension(Buffer, 'GL_EXT_stencil_clear_tag');
-  GL_EXT_packed_depth_stencil := Int_CheckExtension(Buffer, 'GL_EXT_packed_depth_stencil');
-  GL_EXT_texture_sRGB := Int_CheckExtension(Buffer, 'GL_EXT_texture_sRGB');
-  GL_EXT_framebuffer_blit := Int_CheckExtension(Buffer, 'GL_EXT_framebuffer_blit');
-  GL_EXT_framebuffer_multisample := Int_CheckExtension(Buffer, 'GL_EXT_framebuffer_multisample');
-  GL_EXT_timer_query := Int_CheckExtension(Buffer, 'GL_EXT_timer_query');
-  GL_EXT_gpu_program_parameters := Int_CheckExtension(Buffer, 'GL_EXT_gpu_program_parameters');
-  GL_EXT_bindable_uniform := Int_CheckExtension(Buffer, 'GL_EXT_bindable_uniform');
-  GL_EXT_draw_buffers2 := Int_CheckExtension(Buffer, 'GL_EXT_draw_buffers2');
-  GL_EXT_draw_instanced := Int_CheckExtension(Buffer, 'GL_EXT_draw_instanced');
-  GL_EXT_framebuffer_sRGB := Int_CheckExtension(Buffer, 'GL_EXT_framebuffer_sRGB');
-  GL_EXT_geometry_shader4 := Int_CheckExtension(Buffer, 'GL_EXT_geometry_shader4');
-  GL_EXT_gpu_shader4 := Int_CheckExtension(Buffer, 'GL_EXT_gpu_shader4');
-  GL_EXT_packed_float := Int_CheckExtension(Buffer, 'GL_EXT_packed_float');
-  GL_EXT_texture_array := Int_CheckExtension(Buffer, 'GL_EXT_texture_array');
-  GL_EXT_texture_buffer_object := Int_CheckExtension(Buffer, 'GL_EXT_texture_buffer_object');
-  GL_EXT_texture_compression_latc := Int_CheckExtension(Buffer, 'GL_EXT_texture_compression_latc');
-  GL_EXT_texture_compression_rgtc := Int_CheckExtension(Buffer, 'GL_EXT_texture_compression_rgtc');
-  GL_EXT_texture_integer := Int_CheckExtension(Buffer, 'GL_EXT_texture_integer');
-  GL_EXT_texture_shared_exponent := Int_CheckExtension(Buffer, 'GL_EXT_texture_shared_exponent');
-  GL_EXT_transform_feedback := Int_CheckExtension(Buffer, 'GL_EXT_transform_feedback');
-  GL_EXT_direct_state_access := Int_CheckExtension(Buffer, 'GL_EXT_direct_state_access');
-  GL_EXT_vertex_array_bgra := Int_CheckExtension(Buffer, 'GL_EXT_vertex_array_bgra');
-  GL_EXT_texture_swizzle := Int_CheckExtension(Buffer, 'GL_EXT_texture_swizzle');
-  GL_EXT_provoking_vertex := Int_CheckExtension(Buffer, 'GL_EXT_provoking_vertex');
-
-  // === HP ======================================================================
-  GL_HP_convolution_border_modes := Int_CheckExtension(Buffer, 'GL_HP_convolution_border_modes');
-  GL_HP_image_transform := Int_CheckExtension(Buffer, 'GL_HP_image_transform');
-  GL_HP_occlusion_test := Int_CheckExtension(Buffer, 'GL_HP_occlusion_test');
-  GL_HP_texture_lighting := Int_CheckExtension(Buffer, 'GL_HP_texture_lighting');
-
-  // === IBM =====================================================================
-  GL_IBM_cull_vertex := Int_CheckExtension(Buffer, 'GL_IBM_cull_vertex');
-  GL_IBM_multimode_draw_arrays := Int_CheckExtension(Buffer, 'GL_IBM_multimode_draw_arrays');
-  GL_IBM_rasterpos_clip := Int_CheckExtension(Buffer, 'GL_IBM_rasterpos_clip');
-  GL_IBM_texture_mirrored_repeat := Int_CheckExtension(Buffer, 'GL_IBM_texture_mirrored_repeat');
-  GL_IBM_vertex_array_lists := Int_CheckExtension(Buffer, 'GL_IBM_vertex_array_lists');
-
-  // === INGR ====================================================================
-  GL_INGR_blend_func_separate := Int_CheckExtension(Buffer, 'GL_INGR_blend_func_separate');
-  GL_INGR_color_clamp := Int_CheckExtension(Buffer, 'GL_INGR_color_clamp');
-  GL_INGR_interlace_read := Int_CheckExtension(Buffer, 'GL_INGR_interlace_read');
-  GL_INGR_palette_buffer := Int_CheckExtension(Buffer, 'GL_INGR_palette_buffer');
-
-  // === INTEL ===================================================================
-  GL_INTEL_parallel_arrays := Int_CheckExtension(Buffer, 'GL_INTEL_parallel_arrays');
-  GL_INTEL_texture_scissor := Int_CheckExtension(Buffer, 'GL_INTEL_texture_scissor');
-
-  // === MESA ====================================================================
-  GL_MESA_resize_buffers := Int_CheckExtension(Buffer, 'GL_MESA_resize_buffers');
-  GL_MESA_window_pos := Int_CheckExtension(Buffer, 'GL_MESA_window_pos');
-
-  // === NVIDIA ==================================================================
-  GL_NV_blend_square := Int_CheckExtension(Buffer, 'GL_NV_blend_square');
-  GL_NV_copy_depth_to_color := Int_CheckExtension(Buffer, 'GL_NV_copy_depth_to_color');
-  GL_NV_depth_clamp := Int_CheckExtension(Buffer, 'GL_NV_depth_clamp');
-  GL_NV_evaluators := Int_CheckExtension(Buffer, 'GL_NV_evaluators');
-  GL_NV_fence := Int_CheckExtension(Buffer, 'GL_NV_fence');
-  GL_NV_float_buffer := Int_CheckExtension(Buffer, 'GL_NV_float_buffer');
-  GL_NV_fog_distance := Int_CheckExtension(Buffer, 'GL_NV_fog_distance');
-  GL_NV_fragment_program := Int_CheckExtension(Buffer, 'GL_NV_fragment_program');
-  GL_NV_half_float := Int_CheckExtension(Buffer, 'GL_NV_half_float');
-  GL_NV_light_max_exponent := Int_CheckExtension(Buffer, 'GL_NV_light_max_exponent');
-  GL_NV_multisample_filter_hint := Int_CheckExtension(Buffer, 'GL_NV_multisample_filter_hint');
-  GL_NV_occlusion_query := Int_CheckExtension(Buffer, 'GL_NV_occlusion_query');
-  GL_NV_packed_depth_stencil := Int_CheckExtension(Buffer, 'GL_NV_packed_depth_stencil');
-  GL_NV_pixel_data_range := Int_CheckExtension(Buffer, 'GL_NV_pixel_data_range');
-  GL_NV_point_sprite := Int_CheckExtension(Buffer, 'GL_NV_point_sprite');
-  GL_NV_primitive_restart := Int_CheckExtension(Buffer, 'GL_NV_primitive_restart');
-  GL_NV_register_combiners := Int_CheckExtension(Buffer, 'GL_NV_register_combiners');
-  GL_NV_register_combiners2 := Int_CheckExtension(Buffer, 'GL_NV_register_combiners2');
-  GL_NV_texgen_emboss := Int_CheckExtension(Buffer, 'GL_NV_texgen_emboss');
-  GL_NV_texgen_reflection := Int_CheckExtension(Buffer, 'GL_NV_texgen_reflection');
-  GL_NV_texture_compression_vtc := Int_CheckExtension(Buffer, 'GL_NV_texture_compression_vtc');
-  GL_NV_texture_env_combine4 := Int_CheckExtension(Buffer, 'GL_NV_texture_env_combine4');
-  GL_NV_texture_expand_normal := Int_CheckExtension(Buffer, 'GL_NV_texture_expand_normal');
-  GL_NV_texture_rectangle := Int_CheckExtension(Buffer, 'GL_NV_texture_rectangle');
-  GL_NV_texture_shader := Int_CheckExtension(Buffer, 'GL_NV_texture_shader');
-  GL_NV_texture_shader2 := Int_CheckExtension(Buffer, 'GL_NV_texture_shader2');
-  GL_NV_texture_shader3 := Int_CheckExtension(Buffer, 'GL_NV_texture_shader3');
-  GL_NV_vertex_array_range := Int_CheckExtension(Buffer, 'GL_NV_vertex_array_range');
-  GL_NV_vertex_array_range2 := Int_CheckExtension(Buffer, 'GL_NV_vertex_array_range2');
-  GL_NV_vertex_program := Int_CheckExtension(Buffer, 'GL_NV_vertex_program');
-  GL_NV_vertex_program1_1 := Int_CheckExtension(Buffer, 'GL_NV_vertex_program1_1');
-  GL_NV_vertex_program2 := Int_CheckExtension(Buffer, 'GL_NV_vertex_program2');
-  GL_NV_fragment_program_option := Int_CheckExtension(Buffer, 'GL_NV_fragment_program_option');
-  GL_NV_fragment_program2 := Int_CheckExtension(Buffer, 'GL_NV_fragment_program2');
-  GL_NV_vertex_program2_option := Int_CheckExtension(Buffer, 'GL_NV_vertex_program2_option');
-  GL_NV_vertex_program3 := Int_CheckExtension(Buffer, 'GL_NV_vertex_program3');
-  GL_NV_depth_buffer_float := Int_CheckExtension(Buffer, 'GL_NV_depth_buffer_float');
-  GL_NV_fragment_program4 := Int_CheckExtension(Buffer, 'GL_NV_fragment_program4');
-  GL_NV_framebuffer_multisample_coverage := Int_CheckExtension(Buffer, 'GL_NV_framebuffer_multisample_coverage');
-  GL_NV_geometry_program4 := Int_CheckExtension(Buffer, 'GL_NV_geometry_program4');
-  GL_NV_gpu_program4 := Int_CheckExtension(Buffer, 'GL_NV_gpu_program4');
-  GL_NV_parameter_buffer_object := Int_CheckExtension(Buffer, 'GL_NV_parameter_buffer_object');
-  GL_NV_transform_feedback := Int_CheckExtension(Buffer, 'GL_NV_transform_feedback');
-  GL_NV_vertex_program4 := Int_CheckExtension(Buffer, 'GL_NV_vertex_program4');
-  GL_NV_conditional_render := Int_CheckExtension(Buffer, 'GL_NV_conditional_render');
-  GL_NV_present_video := Int_CheckExtension(Buffer, 'GL_NV_present_video');
-  GL_NV_explicit_multisample := Int_CheckExtension(Buffer, 'GL_NV_explicit_multisample');
-  GL_NV_transform_feedback2 := Int_CheckExtension(Buffer, 'GL_NV_transform_feedback2');
-
-  // === OML =====================================================================
-  GL_OML_interlace := Int_CheckExtension(Buffer, 'GL_OML_interlace');
-  GL_OML_resample := Int_CheckExtension(Buffer, 'GL_OML_resample');
-  GL_OML_subsample := Int_CheckExtension(Buffer, 'GL_OML_subsample');
-
-  // === PGI =====================================================================
-  GL_PGI_misc_hints := Int_CheckExtension(Buffer, 'GL_PGI_misc_hints');
-  GL_PGI_vertex_hints := Int_CheckExtension(Buffer, 'GL_PGI_vertex_hints');
-
-  // === REND ====================================================================
-  GL_REND_screen_coordinates := Int_CheckExtension(Buffer, 'GL_REND_screen_coordinates');
-
-  // === S3 ======================================================================
-  GL_S3_s3tc := Int_CheckExtension(Buffer, 'GL_S3_s3tc');
-
-  // === SGIS ====================================================================
-  GL_SGIS_detail_texture := Int_CheckExtension(Buffer, 'GL_SGIS_detail_texture');
-  GL_SGIS_fog_function := Int_CheckExtension(Buffer, 'GL_SGIS_fog_function');
-  GL_SGIS_generate_mipmap := Int_CheckExtension(Buffer, 'GL_SGIS_generate_mipmap');
-  GL_SGIS_multisample := Int_CheckExtension(Buffer, 'GL_SGIS_multisample');
-  GL_SGIS_pixel_texture := Int_CheckExtension(Buffer, 'GL_SGIS_pixel_texture');
-  GL_SGIS_point_line_texgen := Int_CheckExtension(Buffer, 'GL_SGIS_point_line_texgen');
-  GL_SGIS_point_parameters := Int_CheckExtension(Buffer, 'GL_SGIS_point_parameters');
-  GL_SGIS_sharpen_texture := Int_CheckExtension(Buffer, 'GL_SGIS_sharpen_texture');
-  GL_SGIS_texture4D := Int_CheckExtension(Buffer, 'GL_SGIS_texture4D');
-  GL_SGIS_texture_border_clamp := Int_CheckExtension(Buffer, 'GL_SGIS_texture_border_clamp');
-  GL_SGIS_texture_color_mask := Int_CheckExtension(Buffer, 'GL_SGIS_texture_color_mask');
-  GL_SGIS_texture_edge_clamp := Int_CheckExtension(Buffer, 'GL_SGIS_texture_edge_clamp');
-  GL_SGIS_texture_filter4 := Int_CheckExtension(Buffer, 'GL_SGIS_texture_filter4');
-  GL_SGIS_texture_lod := Int_CheckExtension(Buffer, 'GL_SGIS_texture_lod');
-  GL_SGIS_texture_select := Int_CheckExtension(Buffer, 'GL_SGIS_texture_select');
-
-  // === SGIX ====================================================================
-  GL_FfdMaskSGIX := Int_CheckExtension(Buffer, 'GL_FfdMaskSGIX');
-  GL_SGIX_async := Int_CheckExtension(Buffer, 'GL_SGIX_async');
-  GL_SGIX_async_histogram := Int_CheckExtension(Buffer, 'GL_SGIX_async_histogram');
-  GL_SGIX_async_pixel := Int_CheckExtension(Buffer, 'GL_SGIX_async_pixel');
-  GL_SGIX_blend_alpha_minmax := Int_CheckExtension(Buffer, 'GL_SGIX_blend_alpha_minmax');
-  GL_SGIX_calligraphic_fragment := Int_CheckExtension(Buffer, 'GL_SGIX_calligraphic_fragment');
-  GL_SGIX_clipmap := Int_CheckExtension(Buffer, 'GL_SGIX_clipmap');
-  GL_SGIX_convolution_accuracy := Int_CheckExtension(Buffer, 'GL_SGIX_convolution_accuracy');
-  GL_SGIX_depth_pass_instrument := Int_CheckExtension(Buffer, 'GL_SGIX_depth_pass_instrument');
-  GL_SGIX_depth_texture := Int_CheckExtension(Buffer, 'GL_SGIX_depth_texture');
-  GL_SGIX_flush_raster := Int_CheckExtension(Buffer, 'GL_SGIX_flush_raster');
-  GL_SGIX_fog_offset := Int_CheckExtension(Buffer, 'GL_SGIX_fog_offset');
-  GL_SGIX_fog_scale := Int_CheckExtension(Buffer, 'GL_SGIX_fog_scale');
-  GL_SGIX_fragment_lighting := Int_CheckExtension(Buffer, 'GL_SGIX_fragment_lighting');
-  GL_SGIX_framezoom := Int_CheckExtension(Buffer, 'GL_SGIX_framezoom');
-  GL_SGIX_igloo_interface := Int_CheckExtension(Buffer, 'GL_SGIX_igloo_interface');
-  GL_SGIX_impact_pixel_texture := Int_CheckExtension(Buffer, 'GL_SGIX_impact_pixel_texture');
-  GL_SGIX_instruments := Int_CheckExtension(Buffer, 'GL_SGIX_instruments');
-  GL_SGIX_interlace := Int_CheckExtension(Buffer, 'GL_SGIX_interlace');
-  GL_SGIX_ir_instrument1 := Int_CheckExtension(Buffer, 'GL_SGIX_ir_instrument1');
-  GL_SGIX_list_priority := Int_CheckExtension(Buffer, 'GL_SGIX_list_priority');
-  GL_SGIX_pixel_texture := Int_CheckExtension(Buffer, 'GL_SGIX_pixel_texture');
-  GL_SGIX_pixel_tiles := Int_CheckExtension(Buffer, 'GL_SGIX_pixel_tiles');
-  GL_SGIX_polynomial_ffd := Int_CheckExtension(Buffer, 'GL_SGIX_polynomial_ffd');
-  GL_SGIX_reference_plane := Int_CheckExtension(Buffer, 'GL_SGIX_reference_plane');
-  GL_SGIX_resample := Int_CheckExtension(Buffer, 'GL_SGIX_resample');
-  GL_SGIX_scalebias_hint := Int_CheckExtension(Buffer, 'GL_SGIX_scalebias_hint');
-  GL_SGIX_shadow := Int_CheckExtension(Buffer, 'GL_SGIX_shadow');
-  GL_SGIX_shadow_ambient := Int_CheckExtension(Buffer, 'GL_SGIX_shadow_ambient');
-  GL_SGIX_sprite := Int_CheckExtension(Buffer, 'GL_SGIX_sprite');
-  GL_SGIX_subsample := Int_CheckExtension(Buffer, 'GL_SGIX_subsample');
-  GL_SGIX_tag_sample_buffer := Int_CheckExtension(Buffer, 'GL_SGIX_tag_sample_buffer');
-  GL_SGIX_texture_add_env := Int_CheckExtension(Buffer, 'GL_SGIX_texture_add_env');
-  GL_SGIX_texture_coordinate_clamp := Int_CheckExtension(Buffer, 'GL_SGIX_texture_coordinate_clamp');
-  GL_SGIX_texture_lod_bias := Int_CheckExtension(Buffer, 'GL_SGIX_texture_lod_bias');
-  GL_SGIX_texture_multi_buffer := Int_CheckExtension(Buffer, 'GL_SGIX_texture_multi_buffer');
-  GL_SGIX_texture_scale_bias := Int_CheckExtension(Buffer, 'GL_SGIX_texture_scale_bias');
-  GL_SGIX_texture_select := Int_CheckExtension(Buffer, 'GL_SGIX_texture_select');
-  GL_SGIX_vertex_preclip := Int_CheckExtension(Buffer, 'GL_SGIX_vertex_preclip');
-  GL_SGIX_ycrcb := Int_CheckExtension(Buffer, 'GL_SGIX_ycrcb');
-  GL_SGIX_ycrcb_subsample := Int_CheckExtension(Buffer, 'GL_SGIX_ycrcb_subsample');
-  GL_SGIX_ycrcba := Int_CheckExtension(Buffer, 'GL_SGIX_ycrcba');
-
-  // === SGI =====================================================================
-  GL_SGI_color_matrix := Int_CheckExtension(Buffer, 'GL_SGI_color_matrix');
-  GL_SGI_color_table := Int_CheckExtension(Buffer, 'GL_SGI_color_table');
-  GL_SGI_depth_pass_instrument := Int_CheckExtension(Buffer, 'GL_SGI_depth_pass_instrument');
-  GL_SGI_texture_color_table := Int_CheckExtension(Buffer, 'GL_SGI_texture_color_table');
-
-  // === SUN =====================================================================
-  GL_SUNX_constant_data := Int_CheckExtension(Buffer, 'GL_SUNX_constant_data');
-  GL_SUN_convolution_border_modes := Int_CheckExtension(Buffer, 'GL_SUN_convolution_border_modes');
-  GL_SUN_global_alpha := Int_CheckExtension(Buffer, 'GL_SUN_global_alpha');
-  GL_SUN_mesh_array := Int_CheckExtension(Buffer, 'GL_SUN_mesh_array');
-  GL_SUN_slice_accum := Int_CheckExtension(Buffer, 'GL_SUN_slice_accum');
-  GL_SUN_triangle_list := Int_CheckExtension(Buffer, 'GL_SUN_triangle_list');
-  GL_SUN_vertex := Int_CheckExtension(Buffer, 'GL_SUN_vertex');
-
-  // === WIN =====================================================================
-  GL_WIN_phong_shading := Int_CheckExtension(Buffer, 'GL_WIN_phong_shading');
-  GL_WIN_specular_fog := Int_CheckExtension(Buffer, 'GL_WIN_specular_fog');
-
-  {$IFDEF DGL_WIN}
-  // === WGL =====================================================================
-  WGL_3DFX_multisample := Int_CheckExtension(Buffer, 'WGL_3DFX_multisample');
-  WGL_ARB_buffer_region := Int_CheckExtension(Buffer, 'WGL_ARB_buffer_region');
-  WGL_ARB_extensions_string := Int_CheckExtension(Buffer, 'WGL_ARB_extensions_string');
-  WGL_ARB_make_current_read := Int_CheckExtension(Buffer, 'WGL_ARB_make_current_read');
-  WGL_ARB_multisample := Int_CheckExtension(Buffer, 'WGL_ARB_multisample');
-  WGL_ARB_pbuffer := Int_CheckExtension(Buffer, 'WGL_ARB_pbuffer');
-  WGL_ARB_pixel_format := Int_CheckExtension(Buffer, 'WGL_ARB_pixel_format');
-  WGL_ARB_pixel_format_float := Int_CheckExtension(Buffer, 'WGL_ARB_pixel_format_float');
-  WGL_ARB_render_texture := Int_CheckExtension(Buffer, 'WGL_ARB_render_texture');
-  WGL_ARB_create_context := Int_CheckExtension(Buffer, 'WGL_ARB_create_context');
-  WGL_ARB_create_context_profile := Int_CheckExtension(Buffer, 'WGL_ARB_create_context_profile');
-  WGL_ATI_pixel_format_float := Int_CheckExtension(Buffer, 'WGL_ATI_pixel_format_float');
-  WGL_AMD_gpu_association := Int_CheckExtension(Buffer, 'WGL_AMD_gpu_association');
-  WGL_EXT_depth_float := Int_CheckExtension(Buffer, 'WGL_EXT_depth_float');
-  WGL_EXT_display_color_table := Int_CheckExtension(Buffer, 'WGL_EXT_display_color_table');
-  WGL_EXT_extensions_string := Int_CheckExtension(Buffer, 'WGL_EXT_extensions_string');
-  WGL_EXT_make_current_read := Int_CheckExtension(Buffer, 'WGL_EXT_make_current_read');
-  WGL_EXT_multisample := Int_CheckExtension(Buffer, 'WGL_EXT_multisample');
-  WGL_EXT_pbuffer := Int_CheckExtension(Buffer, 'WGL_EXT_pbuffer');
-  WGL_EXT_pixel_format := Int_CheckExtension(Buffer, 'WGL_EXT_pixel_format');
-  WGL_EXT_swap_control := Int_CheckExtension(Buffer, 'WGL_EXT_swap_control');
-  WGL_I3D_digital_video_control := Int_CheckExtension(Buffer, 'WGL_I3D_digital_video_control');
-  WGL_I3D_gamma := Int_CheckExtension(Buffer, 'WGL_I3D_gamma');
-  WGL_I3D_genlock := Int_CheckExtension(Buffer, 'WGL_I3D_genlock');
-  WGL_I3D_image_buffer := Int_CheckExtension(Buffer, 'WGL_I3D_image_buffer');
-  WGL_I3D_swap_frame_lock := Int_CheckExtension(Buffer, 'WGL_I3D_swap_frame_lock');
-  WGL_I3D_swap_frame_usage := Int_CheckExtension(Buffer, 'WGL_I3D_swap_frame_usage');
-  WGL_NV_float_buffer := Int_CheckExtension(Buffer, 'WGL_NV_float_buffer');
-  WGL_NV_render_depth_texture := Int_CheckExtension(Buffer, 'WGL_NV_render_depth_texture');
-  WGL_NV_render_texture_rectangle := Int_CheckExtension(Buffer, 'WGL_NV_render_texture_rectangle');
-  WGL_NV_vertex_array_range := Int_CheckExtension(Buffer, 'WGL_NV_vertex_array_range');
-  WGL_NV_present_video := Int_CheckExtension(Buffer, 'WGL_NV_present_video');
-  WGL_NV_video_out := Int_CheckExtension(Buffer, 'WGL_NV_video_out');
-  WGL_NV_swap_group := Int_CheckExtension(Buffer, 'WGL_NV_swap_group');
-  WGL_NV_gpu_affinity := Int_CheckExtension(Buffer, 'WGL_NV_gpu_affinity');
-  WGL_OML_sync_control := Int_CheckExtension(Buffer, 'WGL_OML_sync_control');
-  WGL_3DL_stereo_control := Int_CheckExtension(Buffer, 'WGL_3DL_stereo_control');
-
-  WIN_draw_range_elements := Int_CheckExtension(Buffer, 'WIN_draw_range_elements');
-  WIN_swap_hint := Int_CheckExtension(Buffer, 'WIN_swap_hint');
-  {$ENDIF}
-
-  {$IFDEF DGL_LINUX}
-  // === GLX =====================================================================
-  GLX_ARB_multisample := Int_CheckExtension(Buffer, 'GLX_ARB_multisample');
-  GLX_ARB_fbconfig_float := Int_CheckExtension(Buffer, 'GLX_ARB_fbconfig_float');
-  GLX_ARB_get_proc_address := Int_CheckExtension(Buffer, 'GLX_ARB_get_proc_address');
-  GLX_ARB_create_context := Int_CheckExtension(Buffer, 'GLX_ARB_create_context');
-  GLX_ARB_create_context_profile := Int_CheckExtension(Buffer, 'GLX_ARB_create_context_profile');
-  GLX_EXT_visual_info := Int_CheckExtension(Buffer, 'GLX_EXT_visual_info');
-  GLX_EXT_visual_rating := Int_CheckExtension(Buffer, 'GLX_EXT_visual_rating');
-  GLX_EXT_import_context := Int_CheckExtension(Buffer, 'GLX_EXT_import_context');
-  GLX_EXT_fbconfig_packed_float := Int_CheckExtension(Buffer, 'GLX_EXT_fbconfig_packed_float');
-  GLX_EXT_framebuffer_sRGB := Int_CheckExtension(Buffer, 'GLX_EXT_framebuffer_sRGB');
-  GLX_EXT_texture_from_pixmap := Int_CheckExtension(Buffer, 'GLX_EXT_texture_from_pixmap');
-  {$ENDIF}
-  ImplementationRead := True;
-end;
-
-{$IFDEF DGL_WIN}
-// =============================================================================
-// RaiseLastOSError
-// =============================================================================
-// Needed for compatibility with older Delphiversions
-// =============================================================================
-
-procedure RaiseLastOSError;
-begin
-{$IFDEF FPC}
-  raise Exception.Create('RaiseLastOSError!'); // To-Do: find a better solution
-{$ELSE}
-  {$IFDEF DELPHI6_AND_DOWN} // If Delphi 6 or later
-    SysUtils.RaiseLastWin32Error;
-  {$ELSE}
-    SysUtils.RaiseLastOSError;
-  {$ENDIF}
-{$ENDIF}
-end;
-
-// =============================================================================
-// CreateRenderingContext
-// =============================================================================
-
-function CreateRenderingContext(DC: HDC; Options: TRCOptions; ColorBits, ZBits, StencilBits, AccumBits, AuxBuffers: Integer; Layer: Integer): HGLRC;
-const
-  OBJ_MEMDC = 10;
-  OBJ_ENHMETADC = 12;
-  OBJ_METADC = 4;
-  PFD_DOUBLEBUFFER = $00000001;
-  PFD_STEREO = $00000002;
-  PFD_DRAW_TO_WINDOW = $00000004;
-  PFD_DRAW_TO_BITMAP = $00000008;
-  PFD_SUPPORT_GDI = $00000010;
-  PFD_SUPPORT_OPENGL = $00000020;
-  PFD_TYPE_RGBA = 0;
-  PFD_MAIN_PLANE = 0;
-  PFD_OVERLAY_PLANE = 1;
-  PFD_UNDERLAY_PLANE = LongWord(-1);
-  MemoryDCs = [OBJ_MEMDC, OBJ_METADC, OBJ_ENHMETADC];
-var
-  PFDescriptor: TPixelFormatDescriptor;
-  PixelFormat: Integer;
-  AType: DWORD;
-begin
-  if GL_LibHandle = nil then
-    InitOpenGL;
-
-  FillChar(PFDescriptor, SizeOf(PFDescriptor), 0);
-
-  with PFDescriptor do
-  begin
-    nSize := SizeOf(PFDescriptor);
-    nVersion := 1;
-    dwFlags := PFD_SUPPORT_OPENGL;
-
-    AType := GetObjectType(DC);
-
-    if AType = 0 then
-      RaiseLastOSError;
-
-    if AType in MemoryDCs then
-      dwFlags := dwFlags or PFD_DRAW_TO_BITMAP
-    else
-      dwFlags := dwFlags or PFD_DRAW_TO_WINDOW;
-
-    if opDoubleBuffered in Options then
-      dwFlags := dwFlags or PFD_DOUBLEBUFFER;
-
-    if opGDI in Options then
-      dwFlags := dwFlags or PFD_SUPPORT_GDI;
-
-    if opStereo in Options then
-      dwFlags := dwFlags or PFD_STEREO;
-
-    iPixelType := PFD_TYPE_RGBA;
-    cColorBits := ColorBits;
-    cDepthBits := zBits;
-    cStencilBits := StencilBits;
-    cAccumBits := AccumBits;
-    cAuxBuffers := AuxBuffers;
-
-    if Layer = 0 then
-      iLayerType := PFD_MAIN_PLANE
-    else
-    if Layer > 0 then
-      iLayerType := PFD_OVERLAY_PLANE
-    else
-      iLayerType := Byte(PFD_UNDERLAY_PLANE);
-  end;
-
-  PixelFormat := ChoosePixelFormat(DC, @PFDescriptor);
-
-  if PixelFormat = 0 then
-    RaiseLastOSError;
-
-  if GetPixelFormat(DC) <> PixelFormat then
-    if not SetPixelFormat(DC, PixelFormat, @PFDescriptor) then
-      RaiseLastOSError;
-
-  DescribePixelFormat(DC, PixelFormat, SizeOf(PFDescriptor), PFDescriptor);
-
-  Result := wglCreateContext(DC);
-
-  if Result = 0 then
-    RaiseLastOSError
-  else
-    LastPixelFormat := 0;
-end;
-
-// =============================================================================
-// DestroyRenderingContext
-// =============================================================================
-
-procedure DestroyRenderingContext(RC: HGLRC);
-begin
-  wglDeleteContext(RC);
-end;
-
-
-// =============================================================================
-// ActivateRenderingContext
-// =============================================================================
-
-procedure ActivateRenderingContext(DC: HDC; RC: HGLRC; loadext: boolean = true);
-begin
-  Assert((DC <> 0), 'DC must not be 0');
-  Assert((RC <> 0), 'RC must not be 0');
-
-  wglMakeCurrent(DC, RC);
-
-  {$ifdef DGL_TINY_HEADER}
-  ReadCoreVersion;
-  {$else}
-  ReadImplementationProperties;
-
-  if (loadext) then
-    ReadExtensions;
-  {$endif}
-end;
-
-// =============================================================================
-// DeactivateRenderingContext
-// =============================================================================
-
-procedure DeactivateRenderingContext;
-begin
-  wglMakeCurrent(0, 0);
-end;
-{$ENDIF}
-
-
-initialization
-
-{$IFDEF CPU386}
-  Set8087CW($133F);
-{$ENDIF}
-
-finalization
-
-end.
-
diff --git a/src/lib/dgl/glExt.pas b/src/lib/dgl/glExt.pas
deleted file mode 100644 (file)
index 462db17..0000000
+++ /dev/null
@@ -1,9483 +0,0 @@
-unit GLext;
-
-(**************************************************
- *        OpenGL extension loading library        *
- * Generated by MetaGLext, written by Tom Nuydens *
- *  (tom@delphi3d.net -- http://www.delphi3d.net  *
- **************************************************)
-
-//*** Generated on 2/22/2005
-
-interface
-
-uses
-  Windows, SysUtils, GL;
-
-// Not present in Windows.pas.
-function wglGetProcAddress(proc: PChar): Pointer; stdcall; external 'OpenGL32.dll';
-
-// Test if the given extension name is present in the given extension string.
-function glext_ExtensionSupported(const extension: String; const searchIn: String): Boolean;
-
-// Load the extension with the given name.
-function glext_LoadExtension(ext: String): Boolean;
-
-// Some types that were introduced by extensions:
-type
-  GLintptrARB = Integer;
-  PGLintptrARB = ^GLintptrARB;
-
-  GLsizeiptrARB = Integer;
-  PGLsizeiptrARB = ^GLsizeiptrARB;
-
-  GLcharARB = Char;
-  PGLcharARB = ^GLcharARB;
-
-  GLhandleARB = Cardinal;
-  PGLhandleARB = ^GLhandleARB;
-
-  GLintptr = Integer;
-  PGLintptr = ^GLintptr;
-
-  GLsizeiptr = Integer;
-  PGLsizeiptr = ^GLsizeiptr;
-
-  GLchar = Char;
-  PGLchar = ^GLchar;
-
-//***** GL_version_1_2 *****//
-const
-  GL_UNSIGNED_BYTE_3_3_2 = $8032;
-  GL_UNSIGNED_SHORT_4_4_4_4 = $8033;
-  GL_UNSIGNED_SHORT_5_5_5_1 = $8034;
-  GL_UNSIGNED_INT_8_8_8_8 = $8035;
-  GL_UNSIGNED_INT_10_10_10_2 = $8036;
-  GL_RESCALE_NORMAL = $803A;
-  GL_UNSIGNED_BYTE_2_3_3_REV = $8362;
-  GL_UNSIGNED_SHORT_5_6_5 = $8363;
-  GL_UNSIGNED_SHORT_5_6_5_REV = $8364;
-  GL_UNSIGNED_SHORT_4_4_4_4_REV = $8365;
-  GL_UNSIGNED_SHORT_1_5_5_5_REV = $8366;
-  GL_UNSIGNED_INT_8_8_8_8_REV = $8367;
-  GL_UNSIGNED_INT_2_10_10_10_REV = $8368;
-  GL_BGR = $80E0;
-  GL_BGRA = $80E1;
-  GL_MAX_ELEMENTS_VERTICES = $80E8;
-  GL_MAX_ELEMENTS_INDICES = $80E9;
-  GL_CLAMP_TO_EDGE = $812F;
-  GL_TEXTURE_MIN_LOD = $813A;
-  GL_TEXTURE_MAX_LOD = $813B;
-  GL_TEXTURE_BASE_LEVEL = $813C;
-  GL_TEXTURE_MAX_LEVEL = $813D;
-  GL_LIGHT_MODEL_COLOR_CONTROL = $81F8;
-  GL_SINGLE_COLOR = $81F9;
-  GL_SEPARATE_SPECULAR_COLOR = $81FA;
-  GL_SMOOTH_POINT_SIZE_RANGE = $0B12;
-  GL_SMOOTH_POINT_SIZE_GRANULARITY = $0B13;
-  GL_SMOOTH_LINE_WIDTH_RANGE = $0B22;
-  GL_SMOOTH_LINE_WIDTH_GRANULARITY = $0B23;
-  GL_ALIASED_POINT_SIZE_RANGE = $846D;
-  GL_ALIASED_LINE_WIDTH_RANGE = $846E;
-  GL_PACK_SKIP_IMAGES = $806B;
-  GL_PACK_IMAGE_HEIGHT = $806C;
-  GL_UNPACK_SKIP_IMAGES = $806D;
-  GL_UNPACK_IMAGE_HEIGHT = $806E;
-  GL_TEXTURE_3D = $806F;
-  GL_PROXY_TEXTURE_3D = $8070;
-  GL_TEXTURE_DEPTH = $8071;
-  GL_TEXTURE_WRAP_R = $8072;
-  GL_MAX_3D_TEXTURE_SIZE = $8073;
-var
-  glDrawRangeElements: procedure(mode: GLenum; start: GLuint; _end: GLuint; count: GLsizei; _type: GLenum; const indices: PGLvoid); stdcall = nil;
-  glTexImage3D: procedure(target: GLenum; level: GLint; internalformat: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; format: GLenum; _type: GLenum; const pixels: PGLvoid); stdcall = nil;
-  glTexSubImage3D: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; _type: GLenum; const pixels: PGLvoid); stdcall = nil;
-  glCopyTexSubImage3D: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; x: GLint; y: GLint; width: GLsizei; height: GLsizei); stdcall = nil;
-
-function Load_GL_version_1_2: Boolean;
-
-//***** GL_ARB_imaging *****//
-const
-  GL_CONSTANT_COLOR = $8001;
-  GL_ONE_MINUS_CONSTANT_COLOR = $8002;
-  GL_CONSTANT_ALPHA = $8003;
-  GL_ONE_MINUS_CONSTANT_ALPHA = $8004;
-  GL_BLEND_COLOR = $8005;
-  GL_FUNC_ADD = $8006;
-  GL_MIN = $8007;
-  GL_MAX = $8008;
-  GL_BLEND_EQUATION = $8009;
-  GL_FUNC_SUBTRACT = $800A;
-  GL_FUNC_REVERSE_SUBTRACT = $800B;
-  GL_CONVOLUTION_1D = $8010;
-  GL_CONVOLUTION_2D = $8011;
-  GL_SEPARABLE_2D = $8012;
-  GL_CONVOLUTION_BORDER_MODE = $8013;
-  GL_CONVOLUTION_FILTER_SCALE = $8014;
-  GL_CONVOLUTION_FILTER_BIAS = $8015;
-  GL_REDUCE = $8016;
-  GL_CONVOLUTION_FORMAT = $8017;
-  GL_CONVOLUTION_WIDTH = $8018;
-  GL_CONVOLUTION_HEIGHT = $8019;
-  GL_MAX_CONVOLUTION_WIDTH = $801A;
-  GL_MAX_CONVOLUTION_HEIGHT = $801B;
-  GL_POST_CONVOLUTION_RED_SCALE = $801C;
-  GL_POST_CONVOLUTION_GREEN_SCALE = $801D;
-  GL_POST_CONVOLUTION_BLUE_SCALE = $801E;
-  GL_POST_CONVOLUTION_ALPHA_SCALE = $801F;
-  GL_POST_CONVOLUTION_RED_BIAS = $8020;
-  GL_POST_CONVOLUTION_GREEN_BIAS = $8021;
-  GL_POST_CONVOLUTION_BLUE_BIAS = $8022;
-  GL_POST_CONVOLUTION_ALPHA_BIAS = $8023;
-  GL_HISTOGRAM = $8024;
-  GL_PROXY_HISTOGRAM = $8025;
-  GL_HISTOGRAM_WIDTH = $8026;
-  GL_HISTOGRAM_FORMAT = $8027;
-  GL_HISTOGRAM_RED_SIZE = $8028;
-  GL_HISTOGRAM_GREEN_SIZE = $8029;
-  GL_HISTOGRAM_BLUE_SIZE = $802A;
-  GL_HISTOGRAM_ALPHA_SIZE = $802B;
-  GL_HISTOGRAM_LUMINANCE_SIZE = $802C;
-  GL_HISTOGRAM_SINK = $802D;
-  GL_MINMAX = $802E;
-  GL_MINMAX_FORMAT = $802F;
-  GL_MINMAX_SINK = $8030;
-  GL_TABLE_TOO_LARGE = $8031;
-  GL_COLOR_MATRIX = $80B1;
-  GL_COLOR_MATRIX_STACK_DEPTH = $80B2;
-  GL_MAX_COLOR_MATRIX_STACK_DEPTH = $80B3;
-  GL_POST_COLOR_MATRIX_RED_SCALE = $80B4;
-  GL_POST_COLOR_MATRIX_GREEN_SCALE = $80B5;
-  GL_POST_COLOR_MATRIX_BLUE_SCALE = $80B6;
-  GL_POST_COLOR_MATRIX_ALPHA_SCALE = $80B7;
-  GL_POST_COLOR_MATRIX_RED_BIAS = $80B8;
-  GL_POST_COLOR_MATRIX_GREEN_BIAS = $80B9;
-  GL_POST_COLOR_MATRIX_BLUE_BIAS = $80BA;
-  GL_POST_COLOR_MATIX_ALPHA_BIAS = $80BB;
-  GL_COLOR_TABLE = $80D0;
-  GL_POST_CONVOLUTION_COLOR_TABLE = $80D1;
-  GL_POST_COLOR_MATRIX_COLOR_TABLE = $80D2;
-  GL_PROXY_COLOR_TABLE = $80D3;
-  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE = $80D4;
-  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE = $80D5;
-  GL_COLOR_TABLE_SCALE = $80D6;
-  GL_COLOR_TABLE_BIAS = $80D7;
-  GL_COLOR_TABLE_FORMAT = $80D8;
-  GL_COLOR_TABLE_WIDTH = $80D9;
-  GL_COLOR_TABLE_RED_SIZE = $80DA;
-  GL_COLOR_TABLE_GREEN_SIZE = $80DB;
-  GL_COLOR_TABLE_BLUE_SIZE = $80DC;
-  GL_COLOR_TABLE_ALPHA_SIZE = $80DD;
-  GL_COLOR_TABLE_LUMINANCE_SIZE = $80DE;
-  GL_COLOR_TABLE_INTENSITY_SIZE = $80DF;
-  GL_IGNORE_BORDER = $8150;
-  GL_CONSTANT_BORDER = $8151;
-  GL_WRAP_BORDER = $8152;
-  GL_REPLICATE_BORDER = $8153;
-  GL_CONVOLUTION_BORDER_COLOR = $8154;
-var
-  glColorTable: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; format: GLenum; _type: GLenum; const table: PGLvoid); stdcall = nil;
-  glColorTableParameterfv: procedure(target: GLenum; pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glColorTableParameteriv: procedure(target: GLenum; pname: GLenum; const params: PGLint); stdcall = nil;
-  glCopyColorTable: procedure(target: GLenum; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei); stdcall = nil;
-  glGetColorTable: procedure(target: GLenum; format: GLenum; _type: GLenum; table: PGLvoid); stdcall = nil;
-  glGetColorTableParameterfv: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetColorTableParameteriv: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glColorSubTable: procedure(target: GLenum; start: GLsizei; count: GLsizei; format: GLenum; _type: GLenum; const data: PGLvoid); stdcall = nil;
-  glCopyColorSubTable: procedure(target: GLenum; start: GLsizei; x: GLint; y: GLint; width: GLsizei); stdcall = nil;
-  glConvolutionFilter1D: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; format: GLenum; _type: GLenum; const image: PGLvoid); stdcall = nil;
-  glConvolutionFilter2D: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; height: GLsizei; format: GLenum; _type: GLenum; const image: PGLvoid); stdcall = nil;
-  glConvolutionParameterf: procedure(target: GLenum; pname: GLenum; params: GLfloat); stdcall = nil;
-  glConvolutionParameterfv: procedure(target: GLenum; pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glConvolutionParameteri: procedure(target: GLenum; pname: GLenum; params: GLint); stdcall = nil;
-  glConvolutionParameteriv: procedure(target: GLenum; pname: GLenum; const params: PGLint); stdcall = nil;
-  glCopyConvolutionFilter1D: procedure(target: GLenum; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei); stdcall = nil;
-  glCopyConvolutionFilter2D: procedure(target: GLenum; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei; height: GLsizei); stdcall = nil;
-  glGetConvolutionFilter: procedure(target: GLenum; format: GLenum; _type: GLenum; image: PGLvoid); stdcall = nil;
-  glGetConvolutionParameterfv: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetConvolutionParameteriv: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetSeparableFilter: procedure(target: GLenum; format: GLenum; _type: GLenum; row: PGLvoid; column: PGLvoid; span: PGLvoid); stdcall = nil;
-  glSeparableFilter2D: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; height: GLsizei; format: GLenum; _type: GLenum; const row: PGLvoid; const column: PGLvoid); stdcall = nil;
-  glGetHistogram: procedure(target: GLenum; reset: GLboolean; format: GLenum; _type: GLenum; values: PGLvoid); stdcall = nil;
-  glGetHistogramParameterfv: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetHistogramParameteriv: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetMinmax: procedure(target: GLenum; reset: GLboolean; format: GLenum; _type: GLenum; values: PGLvoid); stdcall = nil;
-  glGetMinmaxParameterfv: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetMinmaxParameteriv: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glHistogram: procedure(target: GLenum; width: GLsizei; internalformat: GLenum; sink: GLboolean); stdcall = nil;
-  glMinmax: procedure(target: GLenum; internalformat: GLenum; sink: GLboolean); stdcall = nil;
-  glResetHistogram: procedure(target: GLenum); stdcall = nil;
-  glResetMinmax: procedure(target: GLenum); stdcall = nil;
-  glBlendEquation: procedure(mode: GLenum); stdcall = nil;
-  glBlendColor: procedure(red: GLclampf; green: GLclampf; blue: GLclampf; alpha: GLclampf); stdcall = nil;
-
-function Load_GL_ARB_imaging: Boolean;
-
-//***** GL_version_1_3 *****//
-const
-  GL_TEXTURE0 = $84C0;
-  GL_TEXTURE1 = $84C1;
-  GL_TEXTURE2 = $84C2;
-  GL_TEXTURE3 = $84C3;
-  GL_TEXTURE4 = $84C4;
-  GL_TEXTURE5 = $84C5;
-  GL_TEXTURE6 = $84C6;
-  GL_TEXTURE7 = $84C7;
-  GL_TEXTURE8 = $84C8;
-  GL_TEXTURE9 = $84C9;
-  GL_TEXTURE10 = $84CA;
-  GL_TEXTURE11 = $84CB;
-  GL_TEXTURE12 = $84CC;
-  GL_TEXTURE13 = $84CD;
-  GL_TEXTURE14 = $84CE;
-  GL_TEXTURE15 = $84CF;
-  GL_TEXTURE16 = $84D0;
-  GL_TEXTURE17 = $84D1;
-  GL_TEXTURE18 = $84D2;
-  GL_TEXTURE19 = $84D3;
-  GL_TEXTURE20 = $84D4;
-  GL_TEXTURE21 = $84D5;
-  GL_TEXTURE22 = $84D6;
-  GL_TEXTURE23 = $84D7;
-  GL_TEXTURE24 = $84D8;
-  GL_TEXTURE25 = $84D9;
-  GL_TEXTURE26 = $84DA;
-  GL_TEXTURE27 = $84DB;
-  GL_TEXTURE28 = $84DC;
-  GL_TEXTURE29 = $84DD;
-  GL_TEXTURE30 = $84DE;
-  GL_TEXTURE31 = $84DF;
-  GL_ACTIVE_TEXTURE = $84E0;
-  GL_CLIENT_ACTIVE_TEXTURE = $84E1;
-  GL_MAX_TEXTURE_UNITS = $84E2;
-  GL_TRANSPOSE_MODELVIEW_MATRIX = $84E3;
-  GL_TRANSPOSE_PROJECTION_MATRIX = $84E4;
-  GL_TRANSPOSE_TEXTURE_MATRIX = $84E5;
-  GL_TRANSPOSE_COLOR_MATRIX = $84E6;
-  GL_MULTISAMPLE = $809D;
-  GL_SAMPLE_ALPHA_TO_COVERAGE = $809E;
-  GL_SAMPLE_ALPHA_TO_ONE = $809F;
-  GL_SAMPLE_COVERAGE = $80A0;
-  GL_SAMPLE_BUFFERS = $80A8;
-  GL_SAMPLES = $80A9;
-  GL_SAMPLE_COVERAGE_VALUE = $80AA;
-  GL_SAMPLE_COVERAGE_INVERT = $80AB;
-  GL_MULTISAMPLE_BIT = $20000000;
-  GL_NORMAL_MAP = $8511;
-  GL_REFLECTION_MAP = $8512;
-  GL_TEXTURE_CUBE_MAP = $8513;
-  GL_TEXTURE_BINDING_CUBE_MAP = $8514;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_X = $8515;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_X = $8516;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Y = $8517;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = $8518;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Z = $8519;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = $851A;
-  GL_PROXY_TEXTURE_CUBE_MAP = $851B;
-  GL_MAX_CUBE_MAP_TEXTURE_SIZE = $851C;
-  GL_COMPRESSED_ALPHA = $84E9;
-  GL_COMPRESSED_LUMINANCE = $84EA;
-  GL_COMPRESSED_LUMINANCE_ALPHA = $84EB;
-  GL_COMPRESSED_INTENSITY = $84EC;
-  GL_COMPRESSED_RGB = $84ED;
-  GL_COMPRESSED_RGBA = $84EE;
-  GL_TEXTURE_COMPRESSION_HINT = $84EF;
-  GL_TEXTURE_COMPRESSED_IMAGE_SIZE = $86A0;
-  GL_TEXTURE_COMPRESSED = $86A1;
-  GL_NUM_COMPRESSED_TEXTURE_FORMATS = $86A2;
-  GL_COMPRESSED_TEXTURE_FORMATS = $86A3;
-  GL_CLAMP_TO_BORDER = $812D;
-  GL_CLAMP_TO_BORDER_SGIS = $812D;
-  GL_COMBINE = $8570;
-  GL_COMBINE_RGB = $8571;
-  GL_COMBINE_ALPHA = $8572;
-  GL_SOURCE0_RGB = $8580;
-  GL_SOURCE1_RGB = $8581;
-  GL_SOURCE2_RGB = $8582;
-  GL_SOURCE0_ALPHA = $8588;
-  GL_SOURCE1_ALPHA = $8589;
-  GL_SOURCE2_ALPHA = $858A;
-  GL_OPERAND0_RGB = $8590;
-  GL_OPERAND1_RGB = $8591;
-  GL_OPERAND2_RGB = $8592;
-  GL_OPERAND0_ALPHA = $8598;
-  GL_OPERAND1_ALPHA = $8599;
-  GL_OPERAND2_ALPHA = $859A;
-  GL_RGB_SCALE = $8573;
-  GL_ADD_SIGNED = $8574;
-  GL_INTERPOLATE = $8575;
-  GL_SUBTRACT = $84E7;
-  GL_CONSTANT = $8576;
-  GL_PRIMARY_COLOR = $8577;
-  GL_PREVIOUS = $8578;
-  GL_DOT3_RGB = $86AE;
-  GL_DOT3_RGBA = $86AF;
-var
-  glActiveTexture: procedure(texture: GLenum); stdcall = nil;
-  glClientActiveTexture: procedure(texture: GLenum); stdcall = nil;
-  glMultiTexCoord1d: procedure(target: GLenum; s: GLdouble); stdcall = nil;
-  glMultiTexCoord1dv: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord1f: procedure(target: GLenum; s: GLfloat); stdcall = nil;
-  glMultiTexCoord1fv: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord1i: procedure(target: GLenum; s: GLint); stdcall = nil;
-  glMultiTexCoord1iv: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord1s: procedure(target: GLenum; s: GLshort); stdcall = nil;
-  glMultiTexCoord1sv: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-  glMultiTexCoord2d: procedure(target: GLenum; s: GLdouble; t: GLdouble); stdcall = nil;
-  glMultiTexCoord2dv: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord2f: procedure(target: GLenum; s: GLfloat; t: GLfloat); stdcall = nil;
-  glMultiTexCoord2fv: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord2i: procedure(target: GLenum; s: GLint; t: GLint); stdcall = nil;
-  glMultiTexCoord2iv: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord2s: procedure(target: GLenum; s: GLshort; t: GLshort); stdcall = nil;
-  glMultiTexCoord2sv: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-  glMultiTexCoord3d: procedure(target: GLenum; s: GLdouble; t: GLdouble; r: GLdouble); stdcall = nil;
-  glMultiTexCoord3dv: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord3f: procedure(target: GLenum; s: GLfloat; t: GLfloat; r: GLfloat); stdcall = nil;
-  glMultiTexCoord3fv: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord3i: procedure(target: GLenum; s: GLint; t: GLint; r: GLint); stdcall = nil;
-  glMultiTexCoord3iv: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord3s: procedure(target: GLenum; s: GLshort; t: GLshort; r: GLshort); stdcall = nil;
-  glMultiTexCoord3sv: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-  glMultiTexCoord4d: procedure(target: GLenum; s: GLdouble; t: GLdouble; r: GLdouble; q: GLdouble); stdcall = nil;
-  glMultiTexCoord4dv: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord4f: procedure(target: GLenum; s: GLfloat; t: GLfloat; r: GLfloat; q: GLfloat); stdcall = nil;
-  glMultiTexCoord4fv: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord4i: procedure(target: GLenum; s: GLint; t: GLint; r: GLint; q: GLint); stdcall = nil;
-  glMultiTexCoord4iv: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord4s: procedure(target: GLenum; s: GLshort; t: GLshort; r: GLshort; q: GLshort); stdcall = nil;
-  glMultiTexCoord4sv: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-  glLoadTransposeMatrixf: procedure(const m: PGLfloat); stdcall = nil;
-  glLoadTransposeMatrixd: procedure(const m: PGLdouble); stdcall = nil;
-  glMultTransposeMatrixf: procedure(const m: PGLfloat); stdcall = nil;
-  glMultTransposeMatrixd: procedure(const m: PGLdouble); stdcall = nil;
-  glSampleCoverage: procedure(value: GLclampf; invert: GLboolean); stdcall = nil;
-  glCompressedTexImage3D: procedure(target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexImage2D: procedure(target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; border: GLint; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexImage1D: procedure(target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; border: GLint; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexSubImage3D: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexSubImage2D: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexSubImage1D: procedure(target: GLenum; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glGetCompressedTexImage: procedure(target: GLenum; level: GLint; img: PGLvoid); stdcall = nil;
-
-function Load_GL_version_1_3: Boolean;
-
-//***** GL_ARB_multitexture *****//
-const
-  GL_TEXTURE0_ARB = $84C0;
-  GL_TEXTURE1_ARB = $84C1;
-  GL_TEXTURE2_ARB = $84C2;
-  GL_TEXTURE3_ARB = $84C3;
-  GL_TEXTURE4_ARB = $84C4;
-  GL_TEXTURE5_ARB = $84C5;
-  GL_TEXTURE6_ARB = $84C6;
-  GL_TEXTURE7_ARB = $84C7;
-  GL_TEXTURE8_ARB = $84C8;
-  GL_TEXTURE9_ARB = $84C9;
-  GL_TEXTURE10_ARB = $84CA;
-  GL_TEXTURE11_ARB = $84CB;
-  GL_TEXTURE12_ARB = $84CC;
-  GL_TEXTURE13_ARB = $84CD;
-  GL_TEXTURE14_ARB = $84CE;
-  GL_TEXTURE15_ARB = $84CF;
-  GL_TEXTURE16_ARB = $84D0;
-  GL_TEXTURE17_ARB = $84D1;
-  GL_TEXTURE18_ARB = $84D2;
-  GL_TEXTURE19_ARB = $84D3;
-  GL_TEXTURE20_ARB = $84D4;
-  GL_TEXTURE21_ARB = $84D5;
-  GL_TEXTURE22_ARB = $84D6;
-  GL_TEXTURE23_ARB = $84D7;
-  GL_TEXTURE24_ARB = $84D8;
-  GL_TEXTURE25_ARB = $84D9;
-  GL_TEXTURE26_ARB = $84DA;
-  GL_TEXTURE27_ARB = $84DB;
-  GL_TEXTURE28_ARB = $84DC;
-  GL_TEXTURE29_ARB = $84DD;
-  GL_TEXTURE30_ARB = $84DE;
-  GL_TEXTURE31_ARB = $84DF;
-  GL_ACTIVE_TEXTURE_ARB = $84E0;
-  GL_CLIENT_ACTIVE_TEXTURE_ARB = $84E1;
-  GL_MAX_TEXTURE_UNITS_ARB = $84E2;
-var
-  glActiveTextureARB: procedure(texture: GLenum); stdcall = nil;
-  glClientActiveTextureARB: procedure(texture: GLenum); stdcall = nil;
-  glMultiTexCoord1dARB: procedure(target: GLenum; s: GLdouble); stdcall = nil;
-  glMultiTexCoord1dvARB: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord1fARB: procedure(target: GLenum; s: GLfloat); stdcall = nil;
-  glMultiTexCoord1fvARB: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord1iARB: procedure(target: GLenum; s: GLint); stdcall = nil;
-  glMultiTexCoord1ivARB: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord1sARB: procedure(target: GLenum; s: GLshort); stdcall = nil;
-  glMultiTexCoord1svARB: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-  glMultiTexCoord2dARB: procedure(target: GLenum; s: GLdouble; t: GLdouble); stdcall = nil;
-  glMultiTexCoord2dvARB: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord2fARB: procedure(target: GLenum; s: GLfloat; t: GLfloat); stdcall = nil;
-  glMultiTexCoord2fvARB: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord2iARB: procedure(target: GLenum; s: GLint; t: GLint); stdcall = nil;
-  glMultiTexCoord2ivARB: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord2sARB: procedure(target: GLenum; s: GLshort; t: GLshort); stdcall = nil;
-  glMultiTexCoord2svARB: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-  glMultiTexCoord3dARB: procedure(target: GLenum; s: GLdouble; t: GLdouble; r: GLdouble); stdcall = nil;
-  glMultiTexCoord3dvARB: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord3fARB: procedure(target: GLenum; s: GLfloat; t: GLfloat; r: GLfloat); stdcall = nil;
-  glMultiTexCoord3fvARB: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord3iARB: procedure(target: GLenum; s: GLint; t: GLint; r: GLint); stdcall = nil;
-  glMultiTexCoord3ivARB: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord3sARB: procedure(target: GLenum; s: GLshort; t: GLshort; r: GLshort); stdcall = nil;
-  glMultiTexCoord3svARB: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-  glMultiTexCoord4dARB: procedure(target: GLenum; s: GLdouble; t: GLdouble; r: GLdouble; q: GLdouble); stdcall = nil;
-  glMultiTexCoord4dvARB: procedure(target: GLenum; const v: PGLdouble); stdcall = nil;
-  glMultiTexCoord4fARB: procedure(target: GLenum; s: GLfloat; t: GLfloat; r: GLfloat; q: GLfloat); stdcall = nil;
-  glMultiTexCoord4fvARB: procedure(target: GLenum; const v: PGLfloat); stdcall = nil;
-  glMultiTexCoord4iARB: procedure(target: GLenum; s: GLint; t: GLint; r: GLint; q: GLint); stdcall = nil;
-  glMultiTexCoord4ivARB: procedure(target: GLenum; const v: PGLint); stdcall = nil;
-  glMultiTexCoord4sARB: procedure(target: GLenum; s: GLshort; t: GLshort; r: GLshort; q: GLshort); stdcall = nil;
-  glMultiTexCoord4svARB: procedure(target: GLenum; const v: PGLshort); stdcall = nil;
-
-function Load_GL_ARB_multitexture: Boolean;
-
-//***** GL_ARB_transpose_matrix *****//
-const
-  GL_TRANSPOSE_MODELVIEW_MATRIX_ARB = $84E3;
-  GL_TRANSPOSE_PROJECTION_MATRIX_ARB = $84E4;
-  GL_TRANSPOSE_TEXTURE_MATRIX_ARB = $84E5;
-  GL_TRANSPOSE_COLOR_MATRIX_ARB = $84E6;
-var
-  glLoadTransposeMatrixfARB: procedure(m: PGLfloat); stdcall = nil;
-  glLoadTransposeMatrixdARB: procedure(m: PGLdouble); stdcall = nil;
-  glMultTransposeMatrixfARB: procedure(m: PGLfloat); stdcall = nil;
-  glMultTransposeMatrixdARB: procedure(m: PGLdouble); stdcall = nil;
-
-function Load_GL_ARB_transpose_matrix: Boolean;
-
-//***** GL_ARB_multisample *****//
-const
-  WGL_SAMPLE_BUFFERS_ARB = $2041;
-  WGL_SAMPLES_ARB = $2042;
-  GL_MULTISAMPLE_ARB = $809D;
-  GL_SAMPLE_ALPHA_TO_COVERAGE_ARB = $809E;
-  GL_SAMPLE_ALPHA_TO_ONE_ARB = $809F;
-  GL_SAMPLE_COVERAGE_ARB = $80A0;
-  GL_MULTISAMPLE_BIT_ARB = $20000000;
-  GL_SAMPLE_BUFFERS_ARB = $80A8;
-  GL_SAMPLES_ARB = $80A9;
-  GL_SAMPLE_COVERAGE_VALUE_ARB = $80AA;
-  GL_SAMPLE_COVERAGE_INVERT_ARB = $80AB;
-var
-  glSampleCoverageARB: procedure(value: GLclampf; invert: GLboolean); stdcall = nil;
-
-function Load_GL_ARB_multisample: Boolean;
-
-//***** GL_ARB_texture_env_add *****//
-
-function Load_GL_ARB_texture_env_add: Boolean;
-
-//***** WGL_ARB_extensions_string *****//
-var
-  wglGetExtensionsStringARB: function(hdc: HDC): Pchar; stdcall = nil;
-
-function Load_WGL_ARB_extensions_string: Boolean;
-
-//***** WGL_ARB_buffer_region *****//
-const
-  WGL_FRONT_COLOR_BUFFER_BIT_ARB = $0001;
-  WGL_BACK_COLOR_BUFFER_BIT_ARB = $0002;
-  WGL_DEPTH_BUFFER_BIT_ARB = $0004;
-  WGL_STENCIL_BUFFER_BIT_ARB = $0008;
-var
-  wglCreateBufferRegionARB: function(hDC: HDC; iLayerPlane: GLint; uType: GLuint): THandle; stdcall = nil;
-  wglDeleteBufferRegionARB: procedure(hRegion: THandle); stdcall = nil;
-  wglSaveBufferRegionARB: function(hRegion: THandle; x: GLint; y: GLint; width: GLint; height: GLint): BOOL; stdcall = nil;
-  wglRestoreBufferRegionARB: function(hRegion: THandle; x: GLint; y: GLint; width: GLint; height: GLint; xSrc: GLint; ySrc: GLint): BOOL; stdcall = nil;
-
-function Load_WGL_ARB_buffer_region: Boolean;
-
-//***** GL_ARB_texture_cube_map *****//
-const
-  GL_NORMAL_MAP_ARB = $8511;
-  GL_REFLECTION_MAP_ARB = $8512;
-  GL_TEXTURE_CUBE_MAP_ARB = $8513;
-  GL_TEXTURE_BINDING_CUBE_MAP_ARB = $8514;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB = $8515;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB = $8516;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB = $8517;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB = $8518;
-  GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB = $8519;
-  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB = $851A;
-  GL_PROXY_TEXTURE_CUBE_MAP_ARB = $851B;
-  GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB = $851C;
-
-function Load_GL_ARB_texture_cube_map: Boolean;
-
-//***** GL_ARB_depth_texture *****//
-const
-  GL_DEPTH_COMPONENT16_ARB = $81A5;
-  GL_DEPTH_COMPONENT24_ARB = $81A6;
-  GL_DEPTH_COMPONENT32_ARB = $81A7;
-  GL_TEXTURE_DEPTH_SIZE_ARB = $884A;
-  GL_DEPTH_TEXTURE_MODE_ARB = $884B;
-
-function Load_GL_ARB_depth_texture: Boolean;
-
-//***** GL_ARB_point_parameters *****//
-const
-  GL_POINT_SIZE_MIN_ARB = $8126;
-  GL_POINT_SIZE_MAX_ARB = $8127;
-  GL_POINT_FADE_THRESHOLD_SIZE_ARB = $8128;
-  GL_POINT_DISTANCE_ATTENUATION_ARB = $8129;
-var
-  glPointParameterfARB: procedure(pname: GLenum; param: GLfloat); stdcall = nil;
-  glPointParameterfvARB: procedure(pname: GLenum; params: PGLfloat); stdcall = nil;
-
-function Load_GL_ARB_point_parameters: Boolean;
-
-//***** GL_ARB_shadow *****//
-const
-  GL_TEXTURE_COMPARE_MODE_ARB = $884C;
-  GL_TEXTURE_COMPARE_FUNC_ARB = $884D;
-  GL_COMPARE_R_TO_TEXTURE_ARB = $884E;
-
-function Load_GL_ARB_shadow: Boolean;
-
-//***** GL_ARB_shadow_ambient *****//
-const
-  GL_TEXTURE_COMPARE_FAIL_VALUE_ARB = $80BF;
-
-function Load_GL_ARB_shadow_ambient: Boolean;
-
-//***** GL_ARB_texture_border_clamp *****//
-const
-  GL_CLAMP_TO_BORDER_ARB = $812D;
-
-function Load_GL_ARB_texture_border_clamp: Boolean;
-
-//***** GL_ARB_texture_compression *****//
-const
-  GL_COMPRESSED_ALPHA_ARB = $84E9;
-  GL_COMPRESSED_LUMINANCE_ARB = $84EA;
-  GL_COMPRESSED_LUMINANCE_ALPHA_ARB = $84EB;
-  GL_COMPRESSED_INTENSITY_ARB = $84EC;
-  GL_COMPRESSED_RGB_ARB = $84ED;
-  GL_COMPRESSED_RGBA_ARB = $84EE;
-  GL_TEXTURE_COMPRESSION_HINT_ARB = $84EF;
-  GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB = $86A0;
-  GL_TEXTURE_COMPRESSED_ARB = $86A1;
-  GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB = $86A2;
-  GL_COMPRESSED_TEXTURE_FORMATS_ARB = $86A3;
-var
-  glCompressedTexImage3DARB: procedure(target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexImage2DARB: procedure(target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; border: GLint; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexImage1DARB: procedure(target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; border: GLint; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexSubImage3DARB: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexSubImage2DARB: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glCompressedTexSubImage1DARB: procedure(target: GLenum; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; imageSize: GLsizei; const data: PGLvoid); stdcall = nil;
-  glGetCompressedTexImageARB: procedure(target: GLenum; lod: GLint; img: PGLvoid); stdcall = nil;
-
-function Load_GL_ARB_texture_compression: Boolean;
-
-//***** GL_ARB_texture_env_combine *****//
-const
-  GL_COMBINE_ARB = $8570;
-  GL_COMBINE_RGB_ARB = $8571;
-  GL_COMBINE_ALPHA_ARB = $8572;
-  GL_SOURCE0_RGB_ARB = $8580;
-  GL_SOURCE1_RGB_ARB = $8581;
-  GL_SOURCE2_RGB_ARB = $8582;
-  GL_SOURCE0_ALPHA_ARB = $8588;
-  GL_SOURCE1_ALPHA_ARB = $8589;
-  GL_SOURCE2_ALPHA_ARB = $858A;
-  GL_OPERAND0_RGB_ARB = $8590;
-  GL_OPERAND1_RGB_ARB = $8591;
-  GL_OPERAND2_RGB_ARB = $8592;
-  GL_OPERAND0_ALPHA_ARB = $8598;
-  GL_OPERAND1_ALPHA_ARB = $8599;
-  GL_OPERAND2_ALPHA_ARB = $859A;
-  GL_RGB_SCALE_ARB = $8573;
-  GL_ADD_SIGNED_ARB = $8574;
-  GL_INTERPOLATE_ARB = $8575;
-  GL_SUBTRACT_ARB = $84E7;
-  GL_CONSTANT_ARB = $8576;
-  GL_PRIMARY_COLOR_ARB = $8577;
-  GL_PREVIOUS_ARB = $8578;
-
-function Load_GL_ARB_texture_env_combine: Boolean;
-
-//***** GL_ARB_texture_env_crossbar *****//
-
-function Load_GL_ARB_texture_env_crossbar: Boolean;
-
-//***** GL_ARB_texture_env_dot3 *****//
-const
-  GL_DOT3_RGB_ARB = $86AE;
-  GL_DOT3_RGBA_ARB = $86AF;
-
-function Load_GL_ARB_texture_env_dot3: Boolean;
-
-//***** GL_ARB_texture_mirrored_repeat *****//
-const
-  GL_MIRRORED_REPEAT_ARB = $8370;
-
-function Load_GL_ARB_texture_mirrored_repeat: Boolean;
-
-//***** GL_ARB_vertex_blend *****//
-const
-  GL_MAX_VERTEX_UNITS_ARB = $86A4;
-  GL_ACTIVE_VERTEX_UNITS_ARB = $86A5;
-  GL_WEIGHT_SUM_UNITY_ARB = $86A6;
-  GL_VERTEX_BLEND_ARB = $86A7;
-  GL_MODELVIEW0_ARB = $1700;
-  GL_MODELVIEW1_ARB = $850A;
-  GL_MODELVIEW2_ARB = $8722;
-  GL_MODELVIEW3_ARB = $8723;
-  GL_MODELVIEW4_ARB = $8724;
-  GL_MODELVIEW5_ARB = $8725;
-  GL_MODELVIEW6_ARB = $8726;
-  GL_MODELVIEW7_ARB = $8727;
-  GL_MODELVIEW8_ARB = $8728;
-  GL_MODELVIEW9_ARB = $8729;
-  GL_MODELVIEW10_ARB = $872A;
-  GL_MODELVIEW11_ARB = $872B;
-  GL_MODELVIEW12_ARB = $872C;
-  GL_MODELVIEW13_ARB = $872D;
-  GL_MODELVIEW14_ARB = $872E;
-  GL_MODELVIEW15_ARB = $872F;
-  GL_MODELVIEW16_ARB = $8730;
-  GL_MODELVIEW17_ARB = $8731;
-  GL_MODELVIEW18_ARB = $8732;
-  GL_MODELVIEW19_ARB = $8733;
-  GL_MODELVIEW20_ARB = $8734;
-  GL_MODELVIEW21_ARB = $8735;
-  GL_MODELVIEW22_ARB = $8736;
-  GL_MODELVIEW23_ARB = $8737;
-  GL_MODELVIEW24_ARB = $8738;
-  GL_MODELVIEW25_ARB = $8739;
-  GL_MODELVIEW26_ARB = $873A;
-  GL_MODELVIEW27_ARB = $873B;
-  GL_MODELVIEW28_ARB = $873C;
-  GL_MODELVIEW29_ARB = $873D;
-  GL_MODELVIEW30_ARB = $873E;
-  GL_MODELVIEW31_ARB = $873F;
-  GL_CURRENT_WEIGHT_ARB = $86A8;
-  GL_WEIGHT_ARRAY_TYPE_ARB = $86A9;
-  GL_WEIGHT_ARRAY_STRIDE_ARB = $86AA;
-  GL_WEIGHT_ARRAY_SIZE_ARB = $86AB;
-  GL_WEIGHT_ARRAY_POINTER_ARB = $86AC;
-  GL_WEIGHT_ARRAY_ARB = $86AD;
-var
-  glWeightbvARB: procedure(size: GLint; weights: PGLbyte); stdcall = nil;
-  glWeightsvARB: procedure(size: GLint; weights: PGLshort); stdcall = nil;
-  glWeightivARB: procedure(size: GLint; weights: PGLint); stdcall = nil;
-  glWeightfvARB: procedure(size: GLint; weights: PGLfloat); stdcall = nil;
-  glWeightdvARB: procedure(size: GLint; weights: PGLdouble); stdcall = nil;
-  glWeightvARB: procedure(size: GLint; weights: PGLdouble); stdcall = nil;
-  glWeightubvARB: procedure(size: GLint; weights: PGLubyte); stdcall = nil;
-  glWeightusvARB: procedure(size: GLint; weights: PGLushort); stdcall = nil;
-  glWeightuivARB: procedure(size: GLint; weights: PGLuint); stdcall = nil;
-  glWeightPointerARB: procedure(size: GLint; _type: GLenum; stride: GLsizei; pointer: PGLvoid); stdcall = nil;
-  glVertexBlendARB: procedure(count: GLint); stdcall = nil;
-
-function Load_GL_ARB_vertex_blend: Boolean;
-
-//***** GL_ARB_vertex_program *****//
-const
-  GL_VERTEX_PROGRAM_ARB = $8620;
-  GL_VERTEX_PROGRAM_POINT_SIZE_ARB = $8642;
-  GL_VERTEX_PROGRAM_TWO_SIDE_ARB = $8643;
-  GL_COLOR_SUM_ARB = $8458;
-  GL_PROGRAM_FORMAT_ASCII_ARB = $8875;
-  GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB = $8622;
-  GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB = $8623;
-  GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB = $8624;
-  GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB = $8625;
-  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB = $886A;
-  GL_CURRENT_VERTEX_ATTRIB_ARB = $8626;
-  GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB = $8645;
-  GL_PROGRAM_LENGTH_ARB = $8627;
-  GL_PROGRAM_FORMAT_ARB = $8876;
-  GL_PROGRAM_BINDING_ARB = $8677;
-  GL_PROGRAM_INSTRUCTIONS_ARB = $88A0;
-  GL_MAX_PROGRAM_INSTRUCTIONS_ARB = $88A1;
-  GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB = $88A2;
-  GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB = $88A3;
-  GL_PROGRAM_TEMPORARIES_ARB = $88A4;
-  GL_MAX_PROGRAM_TEMPORARIES_ARB = $88A5;
-  GL_PROGRAM_NATIVE_TEMPORARIES_ARB = $88A6;
-  GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB = $88A7;
-  GL_PROGRAM_PARAMETERS_ARB = $88A8;
-  GL_MAX_PROGRAM_PARAMETERS_ARB = $88A9;
-  GL_PROGRAM_NATIVE_PARAMETERS_ARB = $88AA;
-  GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB = $88AB;
-  GL_PROGRAM_ATTRIBS_ARB = $88AC;
-  GL_MAX_PROGRAM_ATTRIBS_ARB = $88AD;
-  GL_PROGRAM_NATIVE_ATTRIBS_ARB = $88AE;
-  GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB = $88AF;
-  GL_PROGRAM_ADDRESS_REGISTERS_ARB = $88B0;
-  GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB = $88B1;
-  GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = $88B2;
-  GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = $88B3;
-  GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB = $88B4;
-  GL_MAX_PROGRAM_ENV_PARAMETERS_ARB = $88B5;
-  GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB = $88B6;
-  GL_PROGRAM_STRING_ARB = $8628;
-  GL_PROGRAM_ERROR_POSITION_ARB = $864B;
-  GL_CURRENT_MATRIX_ARB = $8641;
-  GL_TRANSPOSE_CURRENT_MATRIX_ARB = $88B7;
-  GL_CURRENT_MATRIX_STACK_DEPTH_ARB = $8640;
-  GL_MAX_VERTEX_ATTRIBS_ARB = $8869;
-  GL_MAX_PROGRAM_MATRICES_ARB = $862F;
-  GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB = $862E;
-  GL_PROGRAM_ERROR_STRING_ARB = $8874;
-  GL_MATRIX0_ARB = $88C0;
-  GL_MATRIX1_ARB = $88C1;
-  GL_MATRIX2_ARB = $88C2;
-  GL_MATRIX3_ARB = $88C3;
-  GL_MATRIX4_ARB = $88C4;
-  GL_MATRIX5_ARB = $88C5;
-  GL_MATRIX6_ARB = $88C6;
-  GL_MATRIX7_ARB = $88C7;
-  GL_MATRIX8_ARB = $88C8;
-  GL_MATRIX9_ARB = $88C9;
-  GL_MATRIX10_ARB = $88CA;
-  GL_MATRIX11_ARB = $88CB;
-  GL_MATRIX12_ARB = $88CC;
-  GL_MATRIX13_ARB = $88CD;
-  GL_MATRIX14_ARB = $88CE;
-  GL_MATRIX15_ARB = $88CF;
-  GL_MATRIX16_ARB = $88D0;
-  GL_MATRIX17_ARB = $88D1;
-  GL_MATRIX18_ARB = $88D2;
-  GL_MATRIX19_ARB = $88D3;
-  GL_MATRIX20_ARB = $88D4;
-  GL_MATRIX21_ARB = $88D5;
-  GL_MATRIX22_ARB = $88D6;
-  GL_MATRIX23_ARB = $88D7;
-  GL_MATRIX24_ARB = $88D8;
-  GL_MATRIX25_ARB = $88D9;
-  GL_MATRIX26_ARB = $88DA;
-  GL_MATRIX27_ARB = $88DB;
-  GL_MATRIX28_ARB = $88DC;
-  GL_MATRIX29_ARB = $88DD;
-  GL_MATRIX30_ARB = $88DE;
-  GL_MATRIX31_ARB = $88DF;
-var
-  glVertexAttrib1sARB: procedure(index: GLuint; x: GLshort); stdcall = nil;
-  glVertexAttrib1fARB: procedure(index: GLuint; x: GLfloat); stdcall = nil;
-  glVertexAttrib1dARB: procedure(index: GLuint; x: GLdouble); stdcall = nil;
-  glVertexAttrib2sARB: procedure(index: GLuint; x: GLshort; y: GLshort); stdcall = nil;
-  glVertexAttrib2fARB: procedure(index: GLuint; x: GLfloat; y: GLfloat); stdcall = nil;
-  glVertexAttrib2dARB: procedure(index: GLuint; x: GLdouble; y: GLdouble); stdcall = nil;
-  glVertexAttrib3sARB: procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort); stdcall = nil;
-  glVertexAttrib3fARB: procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glVertexAttrib3dARB: procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble); stdcall = nil;
-  glVertexAttrib4sARB: procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort; w: GLshort); stdcall = nil;
-  glVertexAttrib4fARB: procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glVertexAttrib4dARB: procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); stdcall = nil;
-  glVertexAttrib4NubARB: procedure(index: GLuint; x: GLubyte; y: GLubyte; z: GLubyte; w: GLubyte); stdcall = nil;
-  glVertexAttrib1svARB: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib1fvARB: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib1dvARB: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib2svARB: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib2fvARB: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib2dvARB: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib3svARB: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib3fvARB: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib3dvARB: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib4bvARB: procedure(index: GLuint; const v: PGLbyte); stdcall = nil;
-  glVertexAttrib4svARB: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib4ivARB: procedure(index: GLuint; const v: PGLint); stdcall = nil;
-  glVertexAttrib4ubvARB: procedure(index: GLuint; const v: PGLubyte); stdcall = nil;
-  glVertexAttrib4usvARB: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttrib4uivARB: procedure(index: GLuint; const v: PGLuint); stdcall = nil;
-  glVertexAttrib4fvARB: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib4dvARB: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib4NbvARB: procedure(index: GLuint; const v: PGLbyte); stdcall = nil;
-  glVertexAttrib4NsvARB: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib4NivARB: procedure(index: GLuint; const v: PGLint); stdcall = nil;
-  glVertexAttrib4NubvARB: procedure(index: GLuint; const v: PGLubyte); stdcall = nil;
-  glVertexAttrib4NusvARB: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttrib4NuivARB: procedure(index: GLuint; const v: PGLuint); stdcall = nil;
-  glVertexAttribPointerARB: procedure(index: GLuint; size: GLint; _type: GLenum; normalized: GLboolean; stride: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glEnableVertexAttribArrayARB: procedure(index: GLuint); stdcall = nil;
-  glDisableVertexAttribArrayARB: procedure(index: GLuint); stdcall = nil;
-  glProgramStringARB: procedure(target: GLenum; format: GLenum; len: GLsizei; const _string: PGLvoid); stdcall = nil;
-  glBindProgramARB: procedure(target: GLenum; _program: GLuint); stdcall = nil;
-  glDeleteProgramsARB: procedure(n: GLsizei; const programs: PGLuint); stdcall = nil;
-  glGenProgramsARB: procedure(n: GLsizei; programs: PGLuint); stdcall = nil;
-  glProgramEnvParameter4dARB: procedure(target: GLenum; index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); stdcall = nil;
-  glProgramEnvParameter4dvARB: procedure(target: GLenum; index: GLuint; const params: PGLdouble); stdcall = nil;
-  glProgramEnvParameter4fARB: procedure(target: GLenum; index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glProgramEnvParameter4fvARB: procedure(target: GLenum; index: GLuint; const params: PGLfloat); stdcall = nil;
-  glProgramLocalParameter4dARB: procedure(target: GLenum; index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); stdcall = nil;
-  glProgramLocalParameter4dvARB: procedure(target: GLenum; index: GLuint; const params: PGLdouble); stdcall = nil;
-  glProgramLocalParameter4fARB: procedure(target: GLenum; index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glProgramLocalParameter4fvARB: procedure(target: GLenum; index: GLuint; const params: PGLfloat); stdcall = nil;
-  glGetProgramEnvParameterdvARB: procedure(target: GLenum; index: GLuint; params: PGLdouble); stdcall = nil;
-  glGetProgramEnvParameterfvARB: procedure(target: GLenum; index: GLuint; params: PGLfloat); stdcall = nil;
-  glGetProgramLocalParameterdvARB: procedure(target: GLenum; index: GLuint; params: PGLdouble); stdcall = nil;
-  glGetProgramLocalParameterfvARB: procedure(target: GLenum; index: GLuint; params: PGLfloat); stdcall = nil;
-  glGetProgramivARB: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetProgramStringARB: procedure(target: GLenum; pname: GLenum; _string: PGLvoid); stdcall = nil;
-  glGetVertexAttribdvARB: procedure(index: GLuint; pname: GLenum; params: PGLdouble); stdcall = nil;
-  glGetVertexAttribfvARB: procedure(index: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetVertexAttribivARB: procedure(index: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetVertexAttribPointervARB: procedure(index: GLuint; pname: GLenum; pointer: PGLvoid); stdcall = nil;
-  glIsProgramARB: function(_program: GLuint): GLboolean; stdcall = nil;
-
-function Load_GL_ARB_vertex_program: Boolean;
-
-//***** GL_ARB_window_pos *****//
-var
-  glWindowPos2dARB: procedure(x: GLdouble; y: GLdouble); stdcall = nil;
-  glWindowPos2fARB: procedure(x: GLfloat; y: GLfloat); stdcall = nil;
-  glWindowPos2iARB: procedure(x: GLint; y: GLint); stdcall = nil;
-  glWindowPos2sARB: procedure(x: GLshort; y: GLshort); stdcall = nil;
-  glWindowPos2dvARB: procedure(const p: PGLdouble); stdcall = nil;
-  glWindowPos2fvARB: procedure(const p: PGLfloat); stdcall = nil;
-  glWindowPos2ivARB: procedure(const p: PGLint); stdcall = nil;
-  glWindowPos2svARB: procedure(const p: PGLshort); stdcall = nil;
-  glWindowPos3dARB: procedure(x: GLdouble; y: GLdouble; z: GLdouble); stdcall = nil;
-  glWindowPos3fARB: procedure(x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glWindowPos3iARB: procedure(x: GLint; y: GLint; z: GLint); stdcall = nil;
-  glWindowPos3sARB: procedure(x: GLshort; y: GLshort; z: GLshort); stdcall = nil;
-  glWindowPos3dvARB: procedure(const p: PGLdouble); stdcall = nil;
-  glWindowPos3fvARB: procedure(const p: PGLfloat); stdcall = nil;
-  glWindowPos3ivARB: procedure(const p: PGLint); stdcall = nil;
-  glWindowPos3svARB: procedure(const p: PGLshort); stdcall = nil;
-
-function Load_GL_ARB_window_pos: Boolean;
-
-//***** GL_EXT_422_pixels *****//
-const
-  GL_422_EXT = $80CC;
-  GL_422_REV_EXT = $80CD;
-  GL_422_AVERAGE_EXT = $80CE;
-  GL_422_REV_AVERAGE_EXT = $80CF;
-
-function Load_GL_EXT_422_pixels: Boolean;
-
-//***** GL_EXT_abgr *****//
-const
-  GL_ABGR_EXT = $8000;
-
-function Load_GL_EXT_abgr: Boolean;
-
-//***** GL_EXT_bgra *****//
-const
-  GL_BGR_EXT = $80E0;
-  GL_BGRA_EXT = $80E1;
-
-function Load_GL_EXT_bgra: Boolean;
-
-//***** GL_EXT_blend_color *****//
-const
-  GL_CONSTANT_COLOR_EXT = $8001;
-  GL_ONE_MINUS_CONSTANT_COLOR_EXT = $8002;
-  GL_CONSTANT_ALPHA_EXT = $8003;
-  GL_ONE_MINUS_CONSTANT_ALPHA_EXT = $8004;
-  GL_BLEND_COLOR_EXT = $8005;
-var
-  glBlendColorEXT: procedure(red: GLclampf; green: GLclampf; blue: GLclampf; alpha: GLclampf); stdcall = nil;
-
-function Load_GL_EXT_blend_color: Boolean;
-
-//***** GL_EXT_blend_func_separate *****//
-const
-  GL_BLEND_DST_RGB_EXT = $80C8;
-  GL_BLEND_SRC_RGB_EXT = $80C9;
-  GL_BLEND_DST_ALPHA_EXT = $80CA;
-  GL_BLEND_SRC_ALPHA_EXT = $80CB;
-var
-  glBlendFuncSeparateEXT: procedure(sfactorRGB: GLenum; dfactorRGB: GLenum; sfactorAlpha: GLenum; dfactorAlpha: GLenum); stdcall = nil;
-
-function Load_GL_EXT_blend_func_separate: Boolean;
-
-//***** GL_EXT_blend_logic_op *****//
-
-function Load_GL_EXT_blend_logic_op: Boolean;
-
-//***** GL_EXT_blend_minmax *****//
-const
-  GL_FUNC_ADD_EXT = $8006;
-  GL_MIN_EXT = $8007;
-  GL_MAX_EXT = $8008;
-  GL_BLEND_EQUATION_EXT = $8009;
-var
-  glBlendEquationEXT: procedure(mode: GLenum); stdcall = nil;
-
-function Load_GL_EXT_blend_minmax: Boolean;
-
-//***** GL_EXT_blend_subtract *****//
-const
-  GL_FUNC_SUBTRACT_EXT = $800A;
-  GL_FUNC_REVERSE_SUBTRACT_EXT = $800B;
-
-function Load_GL_EXT_blend_subtract: Boolean;
-
-//***** GL_EXT_clip_volume_hint *****//
-const
-  GL_CLIP_VOLUME_CLIPPING_HINT_EXT = $80F0;
-
-function Load_GL_EXT_clip_volume_hint: Boolean;
-
-//***** GL_EXT_color_subtable *****//
-var
-  glColorSubTableEXT: procedure(target: GLenum; start: GLsizei; count: GLsizei; format: GLenum; _type: GLenum; const data: PGLvoid); stdcall = nil;
-  glCopyColorSubTableEXT: procedure(target: GLenum; start: GLsizei; x: GLint; y: GLint; width: GLsizei); stdcall = nil;
-
-function Load_GL_EXT_color_subtable: Boolean;
-
-//***** GL_EXT_compiled_vertex_array *****//
-const
-  GL_ARRAY_ELEMENT_LOCK_FIRST_EXT = $81A8;
-  GL_ARRAY_ELEMENT_LOCK_COUNT_EXT = $81A9;
-var
-  glLockArraysEXT: procedure(first: GLint; count: GLsizei); stdcall = nil;
-  glUnlockArraysEXT: procedure(); stdcall = nil;
-
-function Load_GL_EXT_compiled_vertex_array: Boolean;
-
-//***** GL_EXT_convolution *****//
-const
-  GL_CONVOLUTION_1D_EXT = $8010;
-  GL_CONVOLUTION_2D_EXT = $8011;
-  GL_SEPARABLE_2D_EXT = $8012;
-  GL_CONVOLUTION_BORDER_MODE_EXT = $8013;
-  GL_CONVOLUTION_FILTER_SCALE_EXT = $8014;
-  GL_CONVOLUTION_FILTER_BIAS_EXT = $8015;
-  GL_REDUCE_EXT = $8016;
-  GL_CONVOLUTION_FORMAT_EXT = $8017;
-  GL_CONVOLUTION_WIDTH_EXT = $8018;
-  GL_CONVOLUTION_HEIGHT_EXT = $8019;
-  GL_MAX_CONVOLUTION_WIDTH_EXT = $801A;
-  GL_MAX_CONVOLUTION_HEIGHT_EXT = $801B;
-  GL_POST_CONVOLUTION_RED_SCALE_EXT = $801C;
-  GL_POST_CONVOLUTION_GREEN_SCALE_EXT = $801D;
-  GL_POST_CONVOLUTION_BLUE_SCALE_EXT = $801E;
-  GL_POST_CONVOLUTION_ALPHA_SCALE_EXT = $801F;
-  GL_POST_CONVOLUTION_RED_BIAS_EXT = $8020;
-  GL_POST_CONVOLUTION_GREEN_BIAS_EXT = $8021;
-  GL_POST_CONVOLUTION_BLUE_BIAS_EXT = $8022;
-  GL_POST_CONVOLUTION_ALPHA_BIAS_EXT = $8023;
-var
-  glConvolutionFilter1DEXT: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; format: GLenum; _type: GLenum; const image: PGLvoid); stdcall = nil;
-  glConvolutionFilter2DEXT: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; height: GLsizei; format: GLenum; _type: GLenum; const image: PGLvoid); stdcall = nil;
-  glCopyConvolutionFilter1DEXT: procedure(target: GLenum; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei); stdcall = nil;
-  glCopyConvolutionFilter2DEXT: procedure(target: GLenum; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei; height: GLsizei); stdcall = nil;
-  glGetConvolutionFilterEXT: procedure(target: GLenum; format: GLenum; _type: GLenum; image: PGLvoid); stdcall = nil;
-  glSeparableFilter2DEXT: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; height: GLsizei; format: GLenum; _type: GLenum; const row: PGLvoid; const column: PGLvoid); stdcall = nil;
-  glGetSeparableFilterEXT: procedure(target: GLenum; format: GLenum; _type: GLenum; row: PGLvoid; column: PGLvoid; span: PGLvoid); stdcall = nil;
-  glConvolutionParameteriEXT: procedure(target: GLenum; pname: GLenum; param: GLint); stdcall = nil;
-  glConvolutionParameterivEXT: procedure(target: GLenum; pname: GLenum; const params: PGLint); stdcall = nil;
-  glConvolutionParameterfEXT: procedure(target: GLenum; pname: GLenum; param: GLfloat); stdcall = nil;
-  glConvolutionParameterfvEXT: procedure(target: GLenum; pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glGetConvolutionParameterivEXT: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetConvolutionParameterfvEXT: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-
-function Load_GL_EXT_convolution: Boolean;
-
-//***** GL_EXT_histogram *****//
-const
-  GL_HISTOGRAM_EXT = $8024;
-  GL_PROXY_HISTOGRAM_EXT = $8025;
-  GL_HISTOGRAM_WIDTH_EXT = $8026;
-  GL_HISTOGRAM_FORMAT_EXT = $8027;
-  GL_HISTOGRAM_RED_SIZE_EXT = $8028;
-  GL_HISTOGRAM_GREEN_SIZE_EXT = $8029;
-  GL_HISTOGRAM_BLUE_SIZE_EXT = $802A;
-  GL_HISTOGRAM_ALPHA_SIZE_EXT = $802B;
-  GL_HISTOGRAM_LUMINANCE_SIZE_EXT = $802C;
-  GL_HISTOGRAM_SINK_EXT = $802D;
-  GL_MINMAX_EXT = $802E;
-  GL_MINMAX_FORMAT_EXT = $802F;
-  GL_MINMAX_SINK_EXT = $8030;
-var
-  glHistogramEXT: procedure(target: GLenum; width: GLsizei; internalformat: GLenum; sink: GLboolean); stdcall = nil;
-  glResetHistogramEXT: procedure(target: GLenum); stdcall = nil;
-  glGetHistogramEXT: procedure(target: GLenum; reset: GLboolean; format: GLenum; _type: GLenum; values: PGLvoid); stdcall = nil;
-  glGetHistogramParameterivEXT: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetHistogramParameterfvEXT: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glMinmaxEXT: procedure(target: GLenum; internalformat: GLenum; sink: GLboolean); stdcall = nil;
-  glResetMinmaxEXT: procedure(target: GLenum); stdcall = nil;
-  glGetMinmaxEXT: procedure(target: GLenum; reset: GLboolean; format: GLenum; _type: GLenum; values: PGLvoid); stdcall = nil;
-  glGetMinmaxParameterivEXT: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetMinmaxParameterfvEXT: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-
-function Load_GL_EXT_histogram: Boolean;
-
-//***** GL_EXT_multi_draw_arrays *****//
-var
-  glMultiDrawArraysEXT: procedure(mode: GLenum; first: PGLint; count: PGLsizei; primcount: GLsizei); stdcall = nil;
-  glMultiDrawElementsEXT: procedure(mode: GLenum; count: PGLsizei; _type: GLenum; const indices: PGLvoid; primcount: GLsizei); stdcall = nil;
-
-function Load_GL_EXT_multi_draw_arrays: Boolean;
-
-//***** GL_EXT_packed_pixels *****//
-const
-  GL_UNSIGNED_BYTE_3_3_2_EXT = $8032;
-  GL_UNSIGNED_SHORT_4_4_4_4_EXT = $8033;
-  GL_UNSIGNED_SHORT_5_5_5_1_EXT = $8034;
-  GL_UNSIGNED_INT_8_8_8_8_EXT = $8035;
-  GL_UNSIGNED_INT_10_10_10_2_EXT = $8036;
-
-function Load_GL_EXT_packed_pixels: Boolean;
-
-//***** GL_EXT_paletted_texture *****//
-const
-  GL_COLOR_INDEX1_EXT = $80E2;
-  GL_COLOR_INDEX2_EXT = $80E3;
-  GL_COLOR_INDEX4_EXT = $80E4;
-  GL_COLOR_INDEX8_EXT = $80E5;
-  GL_COLOR_INDEX12_EXT = $80E6;
-  GL_COLOR_INDEX16_EXT = $80E7;
-  GL_COLOR_TABLE_FORMAT_EXT = $80D8;
-  GL_COLOR_TABLE_WIDTH_EXT = $80D9;
-  GL_COLOR_TABLE_RED_SIZE_EXT = $80DA;
-  GL_COLOR_TABLE_GREEN_SIZE_EXT = $80DB;
-  GL_COLOR_TABLE_BLUE_SIZE_EXT = $80DC;
-  GL_COLOR_TABLE_ALPHA_SIZE_EXT = $80DD;
-  GL_COLOR_TABLE_LUMINANCE_SIZE_EXT = $80DE;
-  GL_COLOR_TABLE_INTENSITY_SIZE_EXT = $80DF;
-  GL_TEXTURE_INDEX_SIZE_EXT = $80ED;
-  GL_TEXTURE_1D = $0DE0;
-  GL_TEXTURE_2D = $0DE1;
-  GL_TEXTURE_3D_EXT = $806F;
-  // GL_TEXTURE_CUBE_MAP_ARB  { already defined }
-  GL_PROXY_TEXTURE_1D = $8063;
-  GL_PROXY_TEXTURE_2D = $8064;
-  GL_PROXY_TEXTURE_3D_EXT = $8070;
-  // GL_PROXY_TEXTURE_CUBE_MAP_ARB  { already defined }
-  // GL_TEXTURE_1D  { already defined }
-  // GL_TEXTURE_2D  { already defined }
-  // GL_TEXTURE_3D_EXT  { already defined }
-  // GL_TEXTURE_CUBE_MAP_ARB  { already defined }
-var
-  glColorTableEXT: procedure(target: GLenum; internalFormat: GLenum; width: GLsizei; format: GLenum; _type: GLenum; const data: PGLvoid); stdcall = nil;
-  // glColorSubTableEXT  { already defined }
-  glGetColorTableEXT: procedure(target: GLenum; format: GLenum; _type: GLenum; data: PGLvoid); stdcall = nil;
-  glGetColorTableParameterivEXT: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetColorTableParameterfvEXT: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-
-function Load_GL_EXT_paletted_texture: Boolean;
-
-//***** GL_EXT_point_parameters *****//
-const
-  GL_POINT_SIZE_MIN_EXT = $8126;
-  GL_POINT_SIZE_MAX_EXT = $8127;
-  GL_POINT_FADE_THRESHOLD_SIZE_EXT = $8128;
-  GL_DISTANCE_ATTENUATION_EXT = $8129;
-var
-  glPointParameterfEXT: procedure(pname: GLenum; param: GLfloat); stdcall = nil;
-  glPointParameterfvEXT: procedure(pname: GLenum; params: PGLfloat); stdcall = nil;
-
-function Load_GL_EXT_point_parameters: Boolean;
-
-//***** GL_EXT_polygon_offset *****//
-const
-  GL_POLYGON_OFFSET_EXT = $8037;
-  GL_POLYGON_OFFSET_FACTOR_EXT = $8038;
-  GL_POLYGON_OFFSET_BIAS_EXT = $8039;
-var
-  glPolygonOffsetEXT: procedure(factor: GLfloat; bias: GLfloat); stdcall = nil;
-
-function Load_GL_EXT_polygon_offset: Boolean;
-
-//***** GL_EXT_separate_specular_color *****//
-const
-  GL_LIGHT_MODEL_COLOR_CONTROL_EXT = $81F8;
-  GL_SINGLE_COLOR_EXT = $81F9;
-  GL_SEPARATE_SPECULAR_COLOR_EXT = $81FA;
-
-function Load_GL_EXT_separate_specular_color: Boolean;
-
-//***** GL_EXT_shadow_funcs *****//
-
-function Load_GL_EXT_shadow_funcs: Boolean;
-
-//***** GL_EXT_shared_texture_palette *****//
-const
-  GL_SHARED_TEXTURE_PALETTE_EXT = $81FB;
-
-function Load_GL_EXT_shared_texture_palette: Boolean;
-
-//***** GL_EXT_stencil_two_side *****//
-const
-  GL_STENCIL_TEST_TWO_SIDE_EXT = $8910;
-  GL_ACTIVE_STENCIL_FACE_EXT = $8911;
-var
-  glActiveStencilFaceEXT: procedure(face: GLenum); stdcall = nil;
-
-function Load_GL_EXT_stencil_two_side: Boolean;
-
-//***** GL_EXT_stencil_wrap *****//
-const
-  GL_INCR_WRAP_EXT = $8507;
-  GL_DECR_WRAP_EXT = $8508;
-
-function Load_GL_EXT_stencil_wrap: Boolean;
-
-//***** GL_EXT_subtexture *****//
-var
-  glTexSubImage1DEXT: procedure(target: GLenum; level: GLint; xoffset: GLint; width: GLsizei; format: GLenum; _type: GLenum; const pixels: PGLvoid); stdcall = nil;
-  glTexSubImage2DEXT: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; width: GLsizei; height: GLsizei; format: GLenum; _type: GLenum; const pixels: PGLvoid); stdcall = nil;
-  glTexSubImage3DEXT: procedure(target: GLenum; level: GLint; xoffset: GLint; yoffset: GLint; zoffset: GLint; width: GLsizei; height: GLsizei; depth: GLsizei; format: GLenum; _type: GLenum; const pixels: PGLvoid); stdcall = nil;
-
-function Load_GL_EXT_subtexture: Boolean;
-
-//***** GL_EXT_texture3D *****//
-const
-  GL_PACK_SKIP_IMAGES_EXT = $806B;
-  GL_PACK_IMAGE_HEIGHT_EXT = $806C;
-  GL_UNPACK_SKIP_IMAGES_EXT = $806D;
-  GL_UNPACK_IMAGE_HEIGHT_EXT = $806E;
-  // GL_TEXTURE_3D_EXT  { already defined }
-  // GL_PROXY_TEXTURE_3D_EXT  { already defined }
-  GL_TEXTURE_DEPTH_EXT = $8071;
-  GL_TEXTURE_WRAP_R_EXT = $8072;
-  GL_MAX_3D_TEXTURE_SIZE_EXT = $8073;
-var
-  glTexImage3DEXT: procedure(target: GLenum; level: GLint; internalformat: GLenum; width: GLsizei; height: GLsizei; depth: GLsizei; border: GLint; format: GLenum; _type: GLenum; const pixels: PGLvoid); stdcall = nil;
-
-function Load_GL_EXT_texture3D: Boolean;
-
-//***** GL_EXT_texture_compression_s3tc *****//
-const
-  GL_COMPRESSED_RGB_S3TC_DXT1_EXT = $83F0;
-  GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = $83F1;
-  GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = $83F2;
-  GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = $83F3;
-
-function Load_GL_EXT_texture_compression_s3tc: Boolean;
-
-//***** GL_EXT_texture_env_add *****//
-
-function Load_GL_EXT_texture_env_add: Boolean;
-
-//***** GL_EXT_texture_env_combine *****//
-const
-  GL_COMBINE_EXT = $8570;
-  GL_COMBINE_RGB_EXT = $8571;
-  GL_COMBINE_ALPHA_EXT = $8572;
-  GL_SOURCE0_RGB_EXT = $8580;
-  GL_SOURCE1_RGB_EXT = $8581;
-  GL_SOURCE2_RGB_EXT = $8582;
-  GL_SOURCE0_ALPHA_EXT = $8588;
-  GL_SOURCE1_ALPHA_EXT = $8589;
-  GL_SOURCE2_ALPHA_EXT = $858A;
-  GL_OPERAND0_RGB_EXT = $8590;
-  GL_OPERAND1_RGB_EXT = $8591;
-  GL_OPERAND2_RGB_EXT = $8592;
-  GL_OPERAND0_ALPHA_EXT = $8598;
-  GL_OPERAND1_ALPHA_EXT = $8599;
-  GL_OPERAND2_ALPHA_EXT = $859A;
-  GL_RGB_SCALE_EXT = $8573;
-  GL_ADD_SIGNED_EXT = $8574;
-  GL_INTERPOLATE_EXT = $8575;
-  GL_CONSTANT_EXT = $8576;
-  GL_PRIMARY_COLOR_EXT = $8577;
-  GL_PREVIOUS_EXT = $8578;
-
-function Load_GL_EXT_texture_env_combine: Boolean;
-
-//***** GL_EXT_texture_env_dot3 *****//
-const
-  GL_DOT3_RGB_EXT = $8740;
-  GL_DOT3_RGBA_EXT = $8741;
-
-function Load_GL_EXT_texture_env_dot3: Boolean;
-
-//***** GL_EXT_texture_filter_anisotropic *****//
-const
-  GL_TEXTURE_MAX_ANISOTROPY_EXT = $84FE;
-  GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = $84FF;
-
-function Load_GL_EXT_texture_filter_anisotropic: Boolean;
-
-//***** GL_EXT_texture_lod_bias *****//
-const
-  GL_TEXTURE_FILTER_CONTROL_EXT = $8500;
-  GL_TEXTURE_LOD_BIAS_EXT = $8501;
-  GL_MAX_TEXTURE_LOD_BIAS_EXT = $84FD;
-
-function Load_GL_EXT_texture_lod_bias: Boolean;
-
-//***** GL_EXT_texture_object *****//
-const
-  GL_TEXTURE_PRIORITY_EXT = $8066;
-  GL_TEXTURE_RESIDENT_EXT = $8067;
-  GL_TEXTURE_1D_BINDING_EXT = $8068;
-  GL_TEXTURE_2D_BINDING_EXT = $8069;
-  GL_TEXTURE_3D_BINDING_EXT = $806A;
-var
-  glGenTexturesEXT: procedure(n: GLsizei; textures: PGLuint); stdcall = nil;
-  glDeleteTexturesEXT: procedure(n: GLsizei; const textures: PGLuint); stdcall = nil;
-  glBindTextureEXT: procedure(target: GLenum; texture: GLuint); stdcall = nil;
-  glPrioritizeTexturesEXT: procedure(n: GLsizei; const textures: PGLuint; const priorities: PGLclampf); stdcall = nil;
-  glAreTexturesResidentEXT: function(n: GLsizei; const textures: PGLuint; residences: PGLboolean): GLboolean; stdcall = nil;
-  glIsTextureEXT: function(texture: GLuint): GLboolean; stdcall = nil;
-
-function Load_GL_EXT_texture_object: Boolean;
-
-//***** GL_EXT_vertex_array *****//
-const
-  GL_VERTEX_ARRAY_EXT = $8074;
-  GL_NORMAL_ARRAY_EXT = $8075;
-  GL_COLOR_ARRAY_EXT = $8076;
-  GL_INDEX_ARRAY_EXT = $8077;
-  GL_TEXTURE_COORD_ARRAY_EXT = $8078;
-  GL_EDGE_FLAG_ARRAY_EXT = $8079;
-  GL_DOUBLE_EXT = $140A;
-  GL_VERTEX_ARRAY_SIZE_EXT = $807A;
-  GL_VERTEX_ARRAY_TYPE_EXT = $807B;
-  GL_VERTEX_ARRAY_STRIDE_EXT = $807C;
-  GL_VERTEX_ARRAY_COUNT_EXT = $807D;
-  GL_NORMAL_ARRAY_TYPE_EXT = $807E;
-  GL_NORMAL_ARRAY_STRIDE_EXT = $807F;
-  GL_NORMAL_ARRAY_COUNT_EXT = $8080;
-  GL_COLOR_ARRAY_SIZE_EXT = $8081;
-  GL_COLOR_ARRAY_TYPE_EXT = $8082;
-  GL_COLOR_ARRAY_STRIDE_EXT = $8083;
-  GL_COLOR_ARRAY_COUNT_EXT = $8084;
-  GL_INDEX_ARRAY_TYPE_EXT = $8085;
-  GL_INDEX_ARRAY_STRIDE_EXT = $8086;
-  GL_INDEX_ARRAY_COUNT_EXT = $8087;
-  GL_TEXTURE_COORD_ARRAY_SIZE_EXT = $8088;
-  GL_TEXTURE_COORD_ARRAY_TYPE_EXT = $8089;
-  GL_TEXTURE_COORD_ARRAY_STRIDE_EXT = $808A;
-  GL_TEXTURE_COORD_ARRAY_COUNT_EXT = $808B;
-  GL_EDGE_FLAG_ARRAY_STRIDE_EXT = $808C;
-  GL_EDGE_FLAG_ARRAY_COUNT_EXT = $808D;
-  GL_VERTEX_ARRAY_POINTER_EXT = $808E;
-  GL_NORMAL_ARRAY_POINTER_EXT = $808F;
-  GL_COLOR_ARRAY_POINTER_EXT = $8090;
-  GL_INDEX_ARRAY_POINTER_EXT = $8091;
-  GL_TEXTURE_COORD_ARRAY_POINTER_EXT = $8092;
-  GL_EDGE_FLAG_ARRAY_POINTER_EXT = $8093;
-var
-  glArrayElementEXT: procedure(i: GLint); stdcall = nil;
-  glDrawArraysEXT: procedure(mode: GLenum; first: GLint; count: GLsizei); stdcall = nil;
-  glVertexPointerEXT: procedure(size: GLint; _type: GLenum; stride: GLsizei; count: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glNormalPointerEXT: procedure(_type: GLenum; stride: GLsizei; count: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glColorPointerEXT: procedure(size: GLint; _type: GLenum; stride: GLsizei; count: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glIndexPointerEXT: procedure(_type: GLenum; stride: GLsizei; count: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glTexCoordPointerEXT: procedure(size: GLint; _type: GLenum; stride: GLsizei; count: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glEdgeFlagPointerEXT: procedure(stride: GLsizei; count: GLsizei; const pointer: PGLboolean); stdcall = nil;
-  glGetPointervEXT: procedure(pname: GLenum; params: PGLvoid); stdcall = nil;
-
-function Load_GL_EXT_vertex_array: Boolean;
-
-//***** GL_EXT_vertex_shader *****//
-const
-  GL_VERTEX_SHADER_EXT = $8780;
-  GL_VARIANT_VALUE_EXT = $87E4;
-  GL_VARIANT_DATATYPE_EXT = $87E5;
-  GL_VARIANT_ARRAY_STRIDE_EXT = $87E6;
-  GL_VARIANT_ARRAY_TYPE_EXT = $87E7;
-  GL_VARIANT_ARRAY_EXT = $87E8;
-  GL_VARIANT_ARRAY_POINTER_EXT = $87E9;
-  GL_INVARIANT_VALUE_EXT = $87EA;
-  GL_INVARIANT_DATATYPE_EXT = $87EB;
-  GL_LOCAL_CONSTANT_VALUE_EXT = $87EC;
-  GL_LOCAL_CONSTANT_DATATYPE_EXT = $87ED;
-  GL_OP_INDEX_EXT = $8782;
-  GL_OP_NEGATE_EXT = $8783;
-  GL_OP_DOT3_EXT = $8784;
-  GL_OP_DOT4_EXT = $8785;
-  GL_OP_MUL_EXT = $8786;
-  GL_OP_ADD_EXT = $8787;
-  GL_OP_MADD_EXT = $8788;
-  GL_OP_FRAC_EXT = $8789;
-  GL_OP_MAX_EXT = $878A;
-  GL_OP_MIN_EXT = $878B;
-  GL_OP_SET_GE_EXT = $878C;
-  GL_OP_SET_LT_EXT = $878D;
-  GL_OP_CLAMP_EXT = $878E;
-  GL_OP_FLOOR_EXT = $878F;
-  GL_OP_ROUND_EXT = $8790;
-  GL_OP_EXP_BASE_2_EXT = $8791;
-  GL_OP_LOG_BASE_2_EXT = $8792;
-  GL_OP_POWER_EXT = $8793;
-  GL_OP_RECIP_EXT = $8794;
-  GL_OP_RECIP_SQRT_EXT = $8795;
-  GL_OP_SUB_EXT = $8796;
-  GL_OP_CROSS_PRODUCT_EXT = $8797;
-  GL_OP_MULTIPLY_MATRIX_EXT = $8798;
-  GL_OP_MOV_EXT = $8799;
-  GL_OUTPUT_VERTEX_EXT = $879A;
-  GL_OUTPUT_COLOR0_EXT = $879B;
-  GL_OUTPUT_COLOR1_EXT = $879C;
-  GL_OUTPUT_TEXTURE_COORD0_EXT = $879D;
-  GL_OUTPUT_TEXTURE_COORD1_EXT = $879E;
-  GL_OUTPUT_TEXTURE_COORD2_EXT = $879F;
-  GL_OUTPUT_TEXTURE_COORD3_EXT = $87A0;
-  GL_OUTPUT_TEXTURE_COORD4_EXT = $87A1;
-  GL_OUTPUT_TEXTURE_COORD5_EXT = $87A2;
-  GL_OUTPUT_TEXTURE_COORD6_EXT = $87A3;
-  GL_OUTPUT_TEXTURE_COORD7_EXT = $87A4;
-  GL_OUTPUT_TEXTURE_COORD8_EXT = $87A5;
-  GL_OUTPUT_TEXTURE_COORD9_EXT = $87A6;
-  GL_OUTPUT_TEXTURE_COORD10_EXT = $87A7;
-  GL_OUTPUT_TEXTURE_COORD11_EXT = $87A8;
-  GL_OUTPUT_TEXTURE_COORD12_EXT = $87A9;
-  GL_OUTPUT_TEXTURE_COORD13_EXT = $87AA;
-  GL_OUTPUT_TEXTURE_COORD14_EXT = $87AB;
-  GL_OUTPUT_TEXTURE_COORD15_EXT = $87AC;
-  GL_OUTPUT_TEXTURE_COORD16_EXT = $87AD;
-  GL_OUTPUT_TEXTURE_COORD17_EXT = $87AE;
-  GL_OUTPUT_TEXTURE_COORD18_EXT = $87AF;
-  GL_OUTPUT_TEXTURE_COORD19_EXT = $87B0;
-  GL_OUTPUT_TEXTURE_COORD20_EXT = $87B1;
-  GL_OUTPUT_TEXTURE_COORD21_EXT = $87B2;
-  GL_OUTPUT_TEXTURE_COORD22_EXT = $87B3;
-  GL_OUTPUT_TEXTURE_COORD23_EXT = $87B4;
-  GL_OUTPUT_TEXTURE_COORD24_EXT = $87B5;
-  GL_OUTPUT_TEXTURE_COORD25_EXT = $87B6;
-  GL_OUTPUT_TEXTURE_COORD26_EXT = $87B7;
-  GL_OUTPUT_TEXTURE_COORD27_EXT = $87B8;
-  GL_OUTPUT_TEXTURE_COORD28_EXT = $87B9;
-  GL_OUTPUT_TEXTURE_COORD29_EXT = $87BA;
-  GL_OUTPUT_TEXTURE_COORD30_EXT = $87BB;
-  GL_OUTPUT_TEXTURE_COORD31_EXT = $87BC;
-  GL_OUTPUT_FOG_EXT = $87BD;
-  GL_SCALAR_EXT = $87BE;
-  GL_VECTOR_EXT = $87BF;
-  GL_MATRIX_EXT = $87C0;
-  GL_VARIANT_EXT = $87C1;
-  GL_INVARIANT_EXT = $87C2;
-  GL_LOCAL_CONSTANT_EXT = $87C3;
-  GL_LOCAL_EXT = $87C4;
-  GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT = $87C5;
-  GL_MAX_VERTEX_SHADER_VARIANTS_EXT = $87C6;
-  GL_MAX_VERTEX_SHADER_INVARIANTS_EXT = $87C7;
-  GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = $87C8;
-  GL_MAX_VERTEX_SHADER_LOCALS_EXT = $87C9;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT = $87CA;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT = $87CB;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = $87CC;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT = $87CD;
-  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT = $87CE;
-  GL_VERTEX_SHADER_INSTRUCTIONS_EXT = $87CF;
-  GL_VERTEX_SHADER_VARIANTS_EXT = $87D0;
-  GL_VERTEX_SHADER_INVARIANTS_EXT = $87D1;
-  GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = $87D2;
-  GL_VERTEX_SHADER_LOCALS_EXT = $87D3;
-  GL_VERTEX_SHADER_BINDING_EXT = $8781;
-  GL_VERTEX_SHADER_OPTIMIZED_EXT = $87D4;
-  GL_X_EXT = $87D5;
-  GL_Y_EXT = $87D6;
-  GL_Z_EXT = $87D7;
-  GL_W_EXT = $87D8;
-  GL_NEGATIVE_X_EXT = $87D9;
-  GL_NEGATIVE_Y_EXT = $87DA;
-  GL_NEGATIVE_Z_EXT = $87DB;
-  GL_NEGATIVE_W_EXT = $87DC;
-  GL_ZERO_EXT = $87DD;
-  GL_ONE_EXT = $87DE;
-  GL_NEGATIVE_ONE_EXT = $87DF;
-  GL_NORMALIZED_RANGE_EXT = $87E0;
-  GL_FULL_RANGE_EXT = $87E1;
-  GL_CURRENT_VERTEX_EXT = $87E2;
-  GL_MVP_MATRIX_EXT = $87E3;
-var
-  glBeginVertexShaderEXT: procedure(); stdcall = nil;
-  glEndVertexShaderEXT: procedure(); stdcall = nil;
-  glBindVertexShaderEXT: procedure(id: GLuint); stdcall = nil;
-  glGenVertexShadersEXT: function(range: GLuint): GLuint; stdcall = nil;
-  glDeleteVertexShaderEXT: procedure(id: GLuint); stdcall = nil;
-  glShaderOp1EXT: procedure(op: GLenum; res: GLuint; arg1: GLuint); stdcall = nil;
-  glShaderOp2EXT: procedure(op: GLenum; res: GLuint; arg1: GLuint; arg2: GLuint); stdcall = nil;
-  glShaderOp3EXT: procedure(op: GLenum; res: GLuint; arg1: GLuint; arg2: GLuint; arg3: GLuint); stdcall = nil;
-  glSwizzleEXT: procedure(res: GLuint; _in: GLuint; outX: GLenum; outY: GLenum; outZ: GLenum; outW: GLenum); stdcall = nil;
-  glWriteMaskEXT: procedure(res: GLuint; _in: GLuint; outX: GLenum; outY: GLenum; outZ: GLenum; outW: GLenum); stdcall = nil;
-  glInsertComponentEXT: procedure(res: GLuint; src: GLuint; num: GLuint); stdcall = nil;
-  glExtractComponentEXT: procedure(res: GLuint; src: GLuint; num: GLuint); stdcall = nil;
-  glGenSymbolsEXT: function(datatype: GLenum; storagetype: GLenum; range: GLenum; components: GLuint): GLuint; stdcall = nil;
-  glSetInvariantEXT: procedure(id: GLuint; _type: GLenum; addr: PGLvoid); stdcall = nil;
-  glSetLocalConstantEXT: procedure(id: GLuint; _type: GLenum; addr: PGLvoid); stdcall = nil;
-  glVariantbvEXT: procedure(id: GLuint; addr: PGLbyte); stdcall = nil;
-  glVariantsvEXT: procedure(id: GLuint; addr: PGLshort); stdcall = nil;
-  glVariantivEXT: procedure(id: GLuint; addr: PGLint); stdcall = nil;
-  glVariantfvEXT: procedure(id: GLuint; addr: PGLfloat); stdcall = nil;
-  glVariantdvEXT: procedure(id: GLuint; addr: PGLdouble); stdcall = nil;
-  glVariantubvEXT: procedure(id: GLuint; addr: PGLubyte); stdcall = nil;
-  glVariantusvEXT: procedure(id: GLuint; addr: PGLushort); stdcall = nil;
-  glVariantuivEXT: procedure(id: GLuint; addr: PGLuint); stdcall = nil;
-  glVariantPointerEXT: procedure(id: GLuint; _type: GLenum; stride: GLuint; addr: PGLvoid); stdcall = nil;
-  glEnableVariantClientStateEXT: procedure(id: GLuint); stdcall = nil;
-  glDisableVariantClientStateEXT: procedure(id: GLuint); stdcall = nil;
-  glBindLightParameterEXT: function(light: GLenum; value: GLenum): GLuint; stdcall = nil;
-  glBindMaterialParameterEXT: function(face: GLenum; value: GLenum): GLuint; stdcall = nil;
-  glBindTexGenParameterEXT: function(_unit: GLenum; coord: GLenum; value: GLenum): GLuint; stdcall = nil;
-  glBindTextureUnitParameterEXT: function(_unit: GLenum; value: GLenum): GLuint; stdcall = nil;
-  glBindParameterEXT: function(value: GLenum): GLuint; stdcall = nil;
-  glIsVariantEnabledEXT: function(id: GLuint; cap: GLenum): GLboolean; stdcall = nil;
-  glGetVariantBooleanvEXT: procedure(id: GLuint; value: GLenum; data: PGLboolean); stdcall = nil;
-  glGetVariantIntegervEXT: procedure(id: GLuint; value: GLenum; data: PGLint); stdcall = nil;
-  glGetVariantFloatvEXT: procedure(id: GLuint; value: GLenum; data: PGLfloat); stdcall = nil;
-  glGetVariantPointervEXT: procedure(id: GLuint; value: GLenum; data: PGLvoid); stdcall = nil;
-  glGetInvariantBooleanvEXT: procedure(id: GLuint; value: GLenum; data: PGLboolean); stdcall = nil;
-  glGetInvariantIntegervEXT: procedure(id: GLuint; value: GLenum; data: PGLint); stdcall = nil;
-  glGetInvariantFloatvEXT: procedure(id: GLuint; value: GLenum; data: PGLfloat); stdcall = nil;
-  glGetLocalConstantBooleanvEXT: procedure(id: GLuint; value: GLenum; data: PGLboolean); stdcall = nil;
-  glGetLocalConstantIntegervEXT: procedure(id: GLuint; value: GLenum; data: PGLint); stdcall = nil;
-  glGetLocalConstantFloatvEXT: procedure(id: GLuint; value: GLenum; data: PGLfloat); stdcall = nil;
-
-function Load_GL_EXT_vertex_shader: Boolean;
-
-//***** GL_EXT_vertex_weighting *****//
-const
-  GL_VERTEX_WEIGHTING_EXT = $8509;
-  GL_MODELVIEW0_EXT = $1700;
-  GL_MODELVIEW1_EXT = $850A;
-  GL_MODELVIEW0_MATRIX_EXT = $0BA6;
-  GL_MODELVIEW1_MATRIX_EXT = $8506;
-  GL_CURRENT_VERTEX_WEIGHT_EXT = $850B;
-  GL_VERTEX_WEIGHT_ARRAY_EXT = $850C;
-  GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT = $850D;
-  GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT = $850E;
-  GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT = $850F;
-  GL_MODELVIEW0_STACK_DEPTH_EXT = $0BA3;
-  GL_MODELVIEW1_STACK_DEPTH_EXT = $8502;
-  GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT = $8510;
-var
-  glVertexWeightfEXT: procedure(weight: GLfloat); stdcall = nil;
-  glVertexWeightfvEXT: procedure(weight: PGLfloat); stdcall = nil;
-  glVertexWeightPointerEXT: procedure(size: GLint; _type: GLenum; stride: GLsizei; pointer: PGLvoid); stdcall = nil;
-
-function Load_GL_EXT_vertex_weighting: Boolean;
-
-//***** GL_HP_occlusion_test *****//
-const
-  GL_OCCLUSION_TEST_HP = $8165;
-  GL_OCCLUSION_TEST_RESULT_HP = $8166;
-
-function Load_GL_HP_occlusion_test: Boolean;
-
-//***** GL_NV_blend_square *****//
-
-function Load_GL_NV_blend_square: Boolean;
-
-//***** GL_NV_copy_depth_to_color *****//
-const
-  GL_DEPTH_STENCIL_TO_RGBA_NV = $886E;
-  GL_DEPTH_STENCIL_TO_BGRA_NV = $886F;
-
-function Load_GL_NV_copy_depth_to_color: Boolean;
-
-//***** GL_NV_depth_clamp *****//
-const
-  GL_DEPTH_CLAMP_NV = $864F;
-
-function Load_GL_NV_depth_clamp: Boolean;
-
-//***** GL_NV_evaluators *****//
-const
-  GL_EVAL_2D_NV = $86C0;
-  GL_EVAL_TRIANGULAR_2D_NV = $86C1;
-  GL_MAP_TESSELLATION_NV = $86C2;
-  GL_MAP_ATTRIB_U_ORDER_NV = $86C3;
-  GL_MAP_ATTRIB_V_ORDER_NV = $86C4;
-  GL_EVAL_FRACTIONAL_TESSELLATION_NV = $86C5;
-  GL_EVAL_VERTEX_ATTRIB0_NV = $86C6;
-  GL_EVAL_VERTEX_ATTRIB1_NV = $86C7;
-  GL_EVAL_VERTEX_ATTRIB2_NV = $86C8;
-  GL_EVAL_VERTEX_ATTRIB3_NV = $86C9;
-  GL_EVAL_VERTEX_ATTRIB4_NV = $86CA;
-  GL_EVAL_VERTEX_ATTRIB5_NV = $86CB;
-  GL_EVAL_VERTEX_ATTRIB6_NV = $86CC;
-  GL_EVAL_VERTEX_ATTRIB7_NV = $86CD;
-  GL_EVAL_VERTEX_ATTRIB8_NV = $86CE;
-  GL_EVAL_VERTEX_ATTRIB9_NV = $86CF;
-  GL_EVAL_VERTEX_ATTRIB10_NV = $86D0;
-  GL_EVAL_VERTEX_ATTRIB11_NV = $86D1;
-  GL_EVAL_VERTEX_ATTRIB12_NV = $86D2;
-  GL_EVAL_VERTEX_ATTRIB13_NV = $86D3;
-  GL_EVAL_VERTEX_ATTRIB14_NV = $86D4;
-  GL_EVAL_VERTEX_ATTRIB15_NV = $86D5;
-  GL_MAX_MAP_TESSELLATION_NV = $86D6;
-  GL_MAX_RATIONAL_EVAL_ORDER_NV = $86D7;
-var
-  glMapControlPointsNV: procedure(target: GLenum; index: GLuint; _type: GLenum; ustride: GLsizei; vstride: GLsizei; uorder: GLint; vorder: GLint; _packed: GLboolean; const points: PGLvoid); stdcall = nil;
-  glMapParameterivNV: procedure(target: GLenum; pname: GLenum; const params: PGLint); stdcall = nil;
-  glMapParameterfvNV: procedure(target: GLenum; pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glGetMapControlPointsNV: procedure(target: GLenum; index: GLuint; _type: GLenum; ustride: GLsizei; vstride: GLsizei; _packed: GLboolean; points: PGLvoid); stdcall = nil;
-  glGetMapParameterivNV: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetMapParameterfvNV: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetMapAttribParameterivNV: procedure(target: GLenum; index: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetMapAttribParameterfvNV: procedure(target: GLenum; index: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glEvalMapsNV: procedure(target: GLenum; mode: GLenum); stdcall = nil;
-
-function Load_GL_NV_evaluators: Boolean;
-
-//***** GL_NV_fence *****//
-const
-  GL_ALL_COMPLETED_NV = $84F2;
-  GL_FENCE_STATUS_NV = $84F3;
-  GL_FENCE_CONDITION_NV = $84F4;
-var
-  glGenFencesNV: procedure(n: GLsizei; fences: PGLuint); stdcall = nil;
-  glDeleteFencesNV: procedure(n: GLsizei; const fences: PGLuint); stdcall = nil;
-  glSetFenceNV: procedure(fence: GLuint; condition: GLenum); stdcall = nil;
-  glTestFenceNV: function(fence: GLuint): GLboolean; stdcall = nil;
-  glFinishFenceNV: procedure(fence: GLuint); stdcall = nil;
-  glIsFenceNV: function(fence: GLuint): GLboolean; stdcall = nil;
-  glGetFenceivNV: procedure(fence: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-
-function Load_GL_NV_fence: Boolean;
-
-//***** GL_NV_fog_distance *****//
-const
-  GL_FOG_DISTANCE_MODE_NV = $855A;
-  GL_EYE_RADIAL_NV = $855B;
-  GL_EYE_PLANE_ABSOLUTE_NV = $855C;
-
-function Load_GL_NV_fog_distance: Boolean;
-
-//***** GL_NV_light_max_exponent *****//
-const
-  GL_MAX_SHININESS_NV = $8504;
-  GL_MAX_SPOT_EXPONENT_NV = $8505;
-
-function Load_GL_NV_light_max_exponent: Boolean;
-
-//***** GL_NV_multisample_filter_hint *****//
-const
-  GL_MULTISAMPLE_FILTER_HINT_NV = $8534;
-
-function Load_GL_NV_multisample_filter_hint: Boolean;
-
-//***** GL_NV_occlusion_query *****//
-  // GL_OCCLUSION_TEST_HP  { already defined }
-  // GL_OCCLUSION_TEST_RESULT_HP  { already defined }
-const
-  GL_PIXEL_COUNTER_BITS_NV = $8864;
-  GL_CURRENT_OCCLUSION_QUERY_ID_NV = $8865;
-  GL_PIXEL_COUNT_NV = $8866;
-  GL_PIXEL_COUNT_AVAILABLE_NV = $8867;
-var
-  glGenOcclusionQueriesNV: procedure(n: GLsizei; ids: PGLuint); stdcall = nil;
-  glDeleteOcclusionQueriesNV: procedure(n: GLsizei; const ids: PGLuint); stdcall = nil;
-  glIsOcclusionQueryNV: function(id: GLuint): GLboolean; stdcall = nil;
-  glBeginOcclusionQueryNV: procedure(id: GLuint); stdcall = nil;
-  glEndOcclusionQueryNV: procedure(); stdcall = nil;
-  glGetOcclusionQueryivNV: procedure(id: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetOcclusionQueryuivNV: procedure(id: GLuint; pname: GLenum; params: PGLuint); stdcall = nil;
-
-function Load_GL_NV_occlusion_query: Boolean;
-
-//***** GL_NV_packed_depth_stencil *****//
-const
-  GL_DEPTH_STENCIL_NV = $84F9;
-  GL_UNSIGNED_INT_24_8_NV = $84FA;
-
-function Load_GL_NV_packed_depth_stencil: Boolean;
-
-//***** GL_NV_point_sprite *****//
-const
-  GL_POINT_SPRITE_NV = $8861;
-  GL_COORD_REPLACE_NV = $8862;
-  GL_POINT_SPRITE_R_MODE_NV = $8863;
-var
-  glPointParameteriNV: procedure(pname: GLenum; param: GLint); stdcall = nil;
-  glPointParameterivNV: procedure(pname: GLenum; const params: PGLint); stdcall = nil;
-
-function Load_GL_NV_point_sprite: Boolean;
-
-//***** GL_NV_register_combiners *****//
-const
-  GL_REGISTER_COMBINERS_NV = $8522;
-  GL_COMBINER0_NV = $8550;
-  GL_COMBINER1_NV = $8551;
-  GL_COMBINER2_NV = $8552;
-  GL_COMBINER3_NV = $8553;
-  GL_COMBINER4_NV = $8554;
-  GL_COMBINER5_NV = $8555;
-  GL_COMBINER6_NV = $8556;
-  GL_COMBINER7_NV = $8557;
-  GL_VARIABLE_A_NV = $8523;
-  GL_VARIABLE_B_NV = $8524;
-  GL_VARIABLE_C_NV = $8525;
-  GL_VARIABLE_D_NV = $8526;
-  GL_VARIABLE_E_NV = $8527;
-  GL_VARIABLE_F_NV = $8528;
-  GL_VARIABLE_G_NV = $8529;
-  GL_CONSTANT_COLOR0_NV = $852A;
-  GL_CONSTANT_COLOR1_NV = $852B;
-  GL_PRIMARY_COLOR_NV = $852C;
-  GL_SECONDARY_COLOR_NV = $852D;
-  GL_SPARE0_NV = $852E;
-  GL_SPARE1_NV = $852F;
-  GL_UNSIGNED_IDENTITY_NV = $8536;
-  GL_UNSIGNED_INVERT_NV = $8537;
-  GL_EXPAND_NORMAL_NV = $8538;
-  GL_EXPAND_NEGATE_NV = $8539;
-  GL_HALF_BIAS_NORMAL_NV = $853A;
-  GL_HALF_BIAS_NEGATE_NV = $853B;
-  GL_SIGNED_IDENTITY_NV = $853C;
-  GL_SIGNED_NEGATE_NV = $853D;
-  GL_E_TIMES_F_NV = $8531;
-  GL_SPARE0_PLUS_SECONDARY_COLOR_NV = $8532;
-  GL_SCALE_BY_TWO_NV = $853E;
-  GL_SCALE_BY_FOUR_NV = $853F;
-  GL_SCALE_BY_ONE_HALF_NV = $8540;
-  GL_BIAS_BY_NEGATIVE_ONE_HALF_NV = $8541;
-  GL_DISCARD_NV = $8530;
-  GL_COMBINER_INPUT_NV = $8542;
-  GL_COMBINER_MAPPING_NV = $8543;
-  GL_COMBINER_COMPONENT_USAGE_NV = $8544;
-  GL_COMBINER_AB_DOT_PRODUCT_NV = $8545;
-  GL_COMBINER_CD_DOT_PRODUCT_NV = $8546;
-  GL_COMBINER_MUX_SUM_NV = $8547;
-  GL_COMBINER_SCALE_NV = $8548;
-  GL_COMBINER_BIAS_NV = $8549;
-  GL_COMBINER_AB_OUTPUT_NV = $854A;
-  GL_COMBINER_CD_OUTPUT_NV = $854B;
-  GL_COMBINER_SUM_OUTPUT_NV = $854C;
-  GL_NUM_GENERAL_COMBINERS_NV = $854E;
-  GL_COLOR_SUM_CLAMP_NV = $854F;
-  GL_MAX_GENERAL_COMBINERS_NV = $854D;
-var
-  glCombinerParameterfvNV: procedure(pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glCombinerParameterivNV: procedure(pname: GLenum; const params: PGLint); stdcall = nil;
-  glCombinerParameterfNV: procedure(pname: GLenum; param: GLfloat); stdcall = nil;
-  glCombinerParameteriNV: procedure(pname: GLenum; param: GLint); stdcall = nil;
-  glCombinerInputNV: procedure(stage: GLenum; portion: GLenum; variable: GLenum; input: GLenum; mapping: GLenum; componentUsage: GLenum); stdcall = nil;
-  glCombinerOutputNV: procedure(stage: GLenum; portion: GLenum; abOutput: GLenum; cdOutput: GLenum; sumOutput: GLenum; scale: GLenum; bias: GLenum; abDotProduct: GLboolean; cdDotProduct: GLboolean; muxSum: GLboolean); stdcall = nil;
-  glFinalCombinerInputNV: procedure(variable: GLenum; input: GLenum; mapping: GLenum; componentUsage: GLenum); stdcall = nil;
-  glGetCombinerInputParameterfvNV: procedure(stage: GLenum; portion: GLenum; variable: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetCombinerInputParameterivNV: procedure(stage: GLenum; portion: GLenum; variable: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetCombinerOutputParameterfvNV: procedure(stage: GLenum; portion: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetCombinerOutputParameterivNV: procedure(stage: GLenum; portion: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetFinalCombinerInputParameterfvNV: procedure(variable: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetFinalCombinerInputParameterivNV: procedure(variable: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-
-function Load_GL_NV_register_combiners: Boolean;
-
-//***** GL_NV_register_combiners2 *****//
-const
-  GL_PER_STAGE_CONSTANTS_NV = $8535;
-var
-  glCombinerStageParameterfvNV: procedure(stage: GLenum; pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glGetCombinerStageParameterfvNV: procedure(stage: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-
-function Load_GL_NV_register_combiners2: Boolean;
-
-//***** GL_NV_texgen_emboss *****//
-const
-  GL_EMBOSS_MAP_NV = $855F;
-  GL_EMBOSS_LIGHT_NV = $855D;
-  GL_EMBOSS_CONSTANT_NV = $855E;
-
-function Load_GL_NV_texgen_emboss: Boolean;
-
-//***** GL_NV_texgen_reflection *****//
-const
-  GL_NORMAL_MAP_NV = $8511;
-  GL_REFLECTION_MAP_NV = $8512;
-
-function Load_GL_NV_texgen_reflection: Boolean;
-
-//***** GL_NV_texture_compression_vtc *****//
-  // GL_COMPRESSED_RGB_S3TC_DXT1_EXT  { already defined }
-  // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  { already defined }
-  // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  { already defined }
-  // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  { already defined }
-
-function Load_GL_NV_texture_compression_vtc: Boolean;
-
-//***** GL_NV_texture_env_combine4 *****//
-const
-  GL_COMBINE4_NV = $8503;
-  GL_SOURCE3_RGB_NV = $8583;
-  GL_SOURCE3_ALPHA_NV = $858B;
-  GL_OPERAND3_RGB_NV = $8593;
-  GL_OPERAND3_ALPHA_NV = $859B;
-
-function Load_GL_NV_texture_env_combine4: Boolean;
-
-//***** GL_NV_texture_rectangle *****//
-const
-  GL_TEXTURE_RECTANGLE_NV = $84F5;
-  GL_TEXTURE_BINDING_RECTANGLE_NV = $84F6;
-  GL_PROXY_TEXTURE_RECTANGLE_NV = $84F7;
-  GL_MAX_RECTANGLE_TEXTURE_SIZE_NV = $84F8;
-
-function Load_GL_NV_texture_rectangle: Boolean;
-
-//***** GL_NV_texture_shader *****//
-const
-  GL_TEXTURE_SHADER_NV = $86DE;
-  GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV = $86D9;
-  GL_SHADER_OPERATION_NV = $86DF;
-  GL_CULL_MODES_NV = $86E0;
-  GL_OFFSET_TEXTURE_MATRIX_NV = $86E1;
-  GL_OFFSET_TEXTURE_SCALE_NV = $86E2;
-  GL_OFFSET_TEXTURE_BIAS_NV = $86E3;
-  GL_PREVIOUS_TEXTURE_INPUT_NV = $86E4;
-  GL_CONST_EYE_NV = $86E5;
-  GL_SHADER_CONSISTENT_NV = $86DD;
-  GL_PASS_THROUGH_NV = $86E6;
-  GL_CULL_FRAGMENT_NV = $86E7;
-  GL_OFFSET_TEXTURE_2D_NV = $86E8;
-  GL_OFFSET_TEXTURE_RECTANGLE_NV = $864C;
-  GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV = $864D;
-  GL_DEPENDENT_AR_TEXTURE_2D_NV = $86E9;
-  GL_DEPENDENT_GB_TEXTURE_2D_NV = $86EA;
-  GL_DOT_PRODUCT_NV = $86EC;
-  GL_DOT_PRODUCT_DEPTH_REPLACE_NV = $86ED;
-  GL_DOT_PRODUCT_TEXTURE_2D_NV = $86EE;
-  GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV = $864E;
-  GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV = $86F0;
-  GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV = $86F1;
-  GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV = $86F2;
-  GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV = $86F3;
-  GL_HILO_NV = $86F4;
-  GL_DSDT_NV = $86F5;
-  GL_DSDT_MAG_NV = $86F6;
-  GL_DSDT_MAG_VIB_NV = $86F7;
-  GL_UNSIGNED_INT_S8_S8_8_8_NV = $86DA;
-  GL_UNSIGNED_INT_8_8_S8_S8_REV_NV = $86DB;
-  GL_SIGNED_RGBA_NV = $86FB;
-  GL_SIGNED_RGBA8_NV = $86FC;
-  GL_SIGNED_RGB_NV = $86FE;
-  GL_SIGNED_RGB8_NV = $86FF;
-  GL_SIGNED_LUMINANCE_NV = $8701;
-  GL_SIGNED_LUMINANCE8_NV = $8702;
-  GL_SIGNED_LUMINANCE_ALPHA_NV = $8703;
-  GL_SIGNED_LUMINANCE8_ALPHA8_NV = $8704;
-  GL_SIGNED_ALPHA_NV = $8705;
-  GL_SIGNED_ALPHA8_NV = $8706;
-  GL_SIGNED_INTENSITY_NV = $8707;
-  GL_SIGNED_INTENSITY8_NV = $8708;
-  GL_SIGNED_RGB_UNSIGNED_ALPHA_NV = $870C;
-  GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV = $870D;
-  GL_HILO16_NV = $86F8;
-  GL_SIGNED_HILO_NV = $86F9;
-  GL_SIGNED_HILO16_NV = $86FA;
-  GL_DSDT8_NV = $8709;
-  GL_DSDT8_MAG8_NV = $870A;
-  GL_DSDT_MAG_INTENSITY_NV = $86DC;
-  GL_DSDT8_MAG8_INTENSITY8_NV = $870B;
-  GL_HI_SCALE_NV = $870E;
-  GL_LO_SCALE_NV = $870F;
-  GL_DS_SCALE_NV = $8710;
-  GL_DT_SCALE_NV = $8711;
-  GL_MAGNITUDE_SCALE_NV = $8712;
-  GL_VIBRANCE_SCALE_NV = $8713;
-  GL_HI_BIAS_NV = $8714;
-  GL_LO_BIAS_NV = $8715;
-  GL_DS_BIAS_NV = $8716;
-  GL_DT_BIAS_NV = $8717;
-  GL_MAGNITUDE_BIAS_NV = $8718;
-  GL_VIBRANCE_BIAS_NV = $8719;
-  GL_TEXTURE_BORDER_VALUES_NV = $871A;
-  GL_TEXTURE_HI_SIZE_NV = $871B;
-  GL_TEXTURE_LO_SIZE_NV = $871C;
-  GL_TEXTURE_DS_SIZE_NV = $871D;
-  GL_TEXTURE_DT_SIZE_NV = $871E;
-  GL_TEXTURE_MAG_SIZE_NV = $871F;
-
-function Load_GL_NV_texture_shader: Boolean;
-
-//***** GL_NV_texture_shader2 *****//
-const
-  GL_DOT_PRODUCT_TEXTURE_3D_NV = $86EF;
-  // GL_HILO_NV  { already defined }
-  // GL_DSDT_NV  { already defined }
-  // GL_DSDT_MAG_NV  { already defined }
-  // GL_DSDT_MAG_VIB_NV  { already defined }
-  // GL_UNSIGNED_INT_S8_S8_8_8_NV  { already defined }
-  // GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  { already defined }
-  // GL_SIGNED_RGBA_NV  { already defined }
-  // GL_SIGNED_RGBA8_NV  { already defined }
-  // GL_SIGNED_RGB_NV  { already defined }
-  // GL_SIGNED_RGB8_NV  { already defined }
-  // GL_SIGNED_LUMINANCE_NV  { already defined }
-  // GL_SIGNED_LUMINANCE8_NV  { already defined }
-  // GL_SIGNED_LUMINANCE_ALPHA_NV  { already defined }
-  // GL_SIGNED_LUMINANCE8_ALPHA8_NV  { already defined }
-  // GL_SIGNED_ALPHA_NV  { already defined }
-  // GL_SIGNED_ALPHA8_NV  { already defined }
-  // GL_SIGNED_INTENSITY_NV  { already defined }
-  // GL_SIGNED_INTENSITY8_NV  { already defined }
-  // GL_SIGNED_RGB_UNSIGNED_ALPHA_NV  { already defined }
-  // GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV  { already defined }
-  // GL_HILO16_NV  { already defined }
-  // GL_SIGNED_HILO_NV  { already defined }
-  // GL_SIGNED_HILO16_NV  { already defined }
-  // GL_DSDT8_NV  { already defined }
-  // GL_DSDT8_MAG8_NV  { already defined }
-  // GL_DSDT_MAG_INTENSITY_NV  { already defined }
-  // GL_DSDT8_MAG8_INTENSITY8_NV  { already defined }
-
-function Load_GL_NV_texture_shader2: Boolean;
-
-//***** GL_NV_texture_shader3 *****//
-const
-  GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV = $8850;
-  GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV = $8851;
-  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV = $8852;
-  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV = $8853;
-  GL_OFFSET_HILO_TEXTURE_2D_NV = $8854;
-  GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV = $8855;
-  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV = $8856;
-  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV = $8857;
-  GL_DEPENDENT_HILO_TEXTURE_2D_NV = $8858;
-  GL_DEPENDENT_RGB_TEXTURE_3D_NV = $8859;
-  GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV = $885A;
-  GL_DOT_PRODUCT_PASS_THROUGH_NV = $885B;
-  GL_DOT_PRODUCT_TEXTURE_1D_NV = $885C;
-  GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV = $885D;
-  GL_HILO8_NV = $885E;
-  GL_SIGNED_HILO8_NV = $885F;
-  GL_FORCE_BLUE_TO_ONE_NV = $8860;
-
-function Load_GL_NV_texture_shader3: Boolean;
-
-//***** GL_NV_vertex_array_range *****//
-const
-  GL_VERTEX_ARRAY_RANGE_NV = $851D;
-  GL_VERTEX_ARRAY_RANGE_LENGTH_NV = $851E;
-  GL_VERTEX_ARRAY_RANGE_VALID_NV = $851F;
-  GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV = $8520;
-  GL_VERTEX_ARRAY_RANGE_POINTER_NV = $8521;
-var
-  glVertexArrayRangeNV: procedure(length: GLsizei; pointer: PGLvoid); stdcall = nil;
-  glFlushVertexArrayRangeNV: procedure(); stdcall = nil;
-  wglAllocateMemoryNV: function(size: GLsizei; readFrequency: GLfloat; writeFrequency: GLfloat; priority: GLfloat): PGLvoid; stdcall = nil;
-  wglFreeMemoryNV: procedure(pointer: PGLvoid); stdcall = nil;
-
-function Load_GL_NV_vertex_array_range: Boolean;
-
-//***** GL_NV_vertex_array_range2 *****//
-const
-  GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV = $8533;
-
-function Load_GL_NV_vertex_array_range2: Boolean;
-
-//***** GL_NV_vertex_program *****//
-const
-  GL_VERTEX_PROGRAM_NV = $8620;
-  GL_VERTEX_PROGRAM_POINT_SIZE_NV = $8642;
-  GL_VERTEX_PROGRAM_TWO_SIDE_NV = $8643;
-  GL_VERTEX_STATE_PROGRAM_NV = $8621;
-  GL_ATTRIB_ARRAY_SIZE_NV = $8623;
-  GL_ATTRIB_ARRAY_STRIDE_NV = $8624;
-  GL_ATTRIB_ARRAY_TYPE_NV = $8625;
-  GL_CURRENT_ATTRIB_NV = $8626;
-  GL_PROGRAM_PARAMETER_NV = $8644;
-  GL_ATTRIB_ARRAY_POINTER_NV = $8645;
-  GL_PROGRAM_TARGET_NV = $8646;
-  GL_PROGRAM_LENGTH_NV = $8627;
-  GL_PROGRAM_RESIDENT_NV = $8647;
-  GL_PROGRAM_STRING_NV = $8628;
-  GL_TRACK_MATRIX_NV = $8648;
-  GL_TRACK_MATRIX_TRANSFORM_NV = $8649;
-  GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV = $862E;
-  GL_MAX_TRACK_MATRICES_NV = $862F;
-  GL_CURRENT_MATRIX_STACK_DEPTH_NV = $8640;
-  GL_CURRENT_MATRIX_NV = $8641;
-  GL_VERTEX_PROGRAM_BINDING_NV = $864A;
-  GL_PROGRAM_ERROR_POSITION_NV = $864B;
-  GL_MODELVIEW_PROJECTION_NV = $8629;
-  GL_MATRIX0_NV = $8630;
-  GL_MATRIX1_NV = $8631;
-  GL_MATRIX2_NV = $8632;
-  GL_MATRIX3_NV = $8633;
-  GL_MATRIX4_NV = $8634;
-  GL_MATRIX5_NV = $8635;
-  GL_MATRIX6_NV = $8636;
-  GL_MATRIX7_NV = $8637;
-  GL_IDENTITY_NV = $862A;
-  GL_INVERSE_NV = $862B;
-  GL_TRANSPOSE_NV = $862C;
-  GL_INVERSE_TRANSPOSE_NV = $862D;
-  GL_VERTEX_ATTRIB_ARRAY0_NV = $8650;
-  GL_VERTEX_ATTRIB_ARRAY1_NV = $8651;
-  GL_VERTEX_ATTRIB_ARRAY2_NV = $8652;
-  GL_VERTEX_ATTRIB_ARRAY3_NV = $8653;
-  GL_VERTEX_ATTRIB_ARRAY4_NV = $8654;
-  GL_VERTEX_ATTRIB_ARRAY5_NV = $8655;
-  GL_VERTEX_ATTRIB_ARRAY6_NV = $8656;
-  GL_VERTEX_ATTRIB_ARRAY7_NV = $8657;
-  GL_VERTEX_ATTRIB_ARRAY8_NV = $8658;
-  GL_VERTEX_ATTRIB_ARRAY9_NV = $8659;
-  GL_VERTEX_ATTRIB_ARRAY10_NV = $865A;
-  GL_VERTEX_ATTRIB_ARRAY11_NV = $865B;
-  GL_VERTEX_ATTRIB_ARRAY12_NV = $865C;
-  GL_VERTEX_ATTRIB_ARRAY13_NV = $865D;
-  GL_VERTEX_ATTRIB_ARRAY14_NV = $865E;
-  GL_VERTEX_ATTRIB_ARRAY15_NV = $865F;
-  GL_MAP1_VERTEX_ATTRIB0_4_NV = $8660;
-  GL_MAP1_VERTEX_ATTRIB1_4_NV = $8661;
-  GL_MAP1_VERTEX_ATTRIB2_4_NV = $8662;
-  GL_MAP1_VERTEX_ATTRIB3_4_NV = $8663;
-  GL_MAP1_VERTEX_ATTRIB4_4_NV = $8664;
-  GL_MAP1_VERTEX_ATTRIB5_4_NV = $8665;
-  GL_MAP1_VERTEX_ATTRIB6_4_NV = $8666;
-  GL_MAP1_VERTEX_ATTRIB7_4_NV = $8667;
-  GL_MAP1_VERTEX_ATTRIB8_4_NV = $8668;
-  GL_MAP1_VERTEX_ATTRIB9_4_NV = $8669;
-  GL_MAP1_VERTEX_ATTRIB10_4_NV = $866A;
-  GL_MAP1_VERTEX_ATTRIB11_4_NV = $866B;
-  GL_MAP1_VERTEX_ATTRIB12_4_NV = $866C;
-  GL_MAP1_VERTEX_ATTRIB13_4_NV = $866D;
-  GL_MAP1_VERTEX_ATTRIB14_4_NV = $866E;
-  GL_MAP1_VERTEX_ATTRIB15_4_NV = $866F;
-  GL_MAP2_VERTEX_ATTRIB0_4_NV = $8670;
-  GL_MAP2_VERTEX_ATTRIB1_4_NV = $8671;
-  GL_MAP2_VERTEX_ATTRIB2_4_NV = $8672;
-  GL_MAP2_VERTEX_ATTRIB3_4_NV = $8673;
-  GL_MAP2_VERTEX_ATTRIB4_4_NV = $8674;
-  GL_MAP2_VERTEX_ATTRIB5_4_NV = $8675;
-  GL_MAP2_VERTEX_ATTRIB6_4_NV = $8676;
-  GL_MAP2_VERTEX_ATTRIB7_4_NV = $8677;
-  GL_MAP2_VERTEX_ATTRIB8_4_NV = $8678;
-  GL_MAP2_VERTEX_ATTRIB9_4_NV = $8679;
-  GL_MAP2_VERTEX_ATTRIB10_4_NV = $867A;
-  GL_MAP2_VERTEX_ATTRIB11_4_NV = $867B;
-  GL_MAP2_VERTEX_ATTRIB12_4_NV = $867C;
-  GL_MAP2_VERTEX_ATTRIB13_4_NV = $867D;
-  GL_MAP2_VERTEX_ATTRIB14_4_NV = $867E;
-  GL_MAP2_VERTEX_ATTRIB15_4_NV = $867F;
-var
-  glBindProgramNV: procedure(target: GLenum; id: GLuint); stdcall = nil;
-  glDeleteProgramsNV: procedure(n: GLsizei; const ids: PGLuint); stdcall = nil;
-  glExecuteProgramNV: procedure(target: GLenum; id: GLuint; const params: PGLfloat); stdcall = nil;
-  glGenProgramsNV: procedure(n: GLsizei; ids: PGLuint); stdcall = nil;
-  glAreProgramsResidentNV: function(n: GLsizei; const ids: PGLuint; residences: PGLboolean): GLboolean; stdcall = nil;
-  glRequestResidentProgramsNV: procedure(n: GLsizei; ids: PGLuint); stdcall = nil;
-  glGetProgramParameterfvNV: procedure(target: GLenum; index: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetProgramParameterdvNV: procedure(target: GLenum; index: GLuint; pname: GLenum; params: PGLdouble); stdcall = nil;
-  glGetProgramivNV: procedure(id: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetProgramStringNV: procedure(id: GLuint; pname: GLenum; _program: PGLubyte); stdcall = nil;
-  glGetTrackMatrixivNV: procedure(target: GLenum; address: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetVertexAttribdvNV: procedure(index: GLuint; pname: GLenum; params: PGLdouble); stdcall = nil;
-  glGetVertexAttribfvNV: procedure(index: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetVertexAttribivNV: procedure(index: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetVertexAttribPointervNV: procedure(index: GLuint; pname: GLenum; pointer: PGLvoid); stdcall = nil;
-  glIsProgramNV: function(id: GLuint): GLboolean; stdcall = nil;
-  glLoadProgramNV: procedure(target: GLenum; id: GLuint; len: GLsizei; const _program: PGLubyte); stdcall = nil;
-  glProgramParameter4fNV: procedure(target: GLenum; index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glProgramParameter4fvNV: procedure(target: GLenum; index: GLuint; const params: PGLfloat); stdcall = nil;
-  glProgramParameters4dvNV: procedure(target: GLenum; index: GLuint; num: GLuint; const params: PGLdouble); stdcall = nil;
-  glProgramParameters4fvNV: procedure(target: GLenum; index: GLuint; num: GLuint; const params: PGLfloat); stdcall = nil;
-  glTrackMatrixNV: procedure(target: GLenum; address: GLuint; matrix: GLenum; transform: GLenum); stdcall = nil;
-  glVertexAttribPointerNV: procedure(index: GLuint; size: GLint; _type: GLenum; stride: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glVertexAttrib1sNV: procedure(index: GLuint; x: GLshort); stdcall = nil;
-  glVertexAttrib1fNV: procedure(index: GLuint; x: GLfloat); stdcall = nil;
-  glVertexAttrib1dNV: procedure(index: GLuint; x: GLdouble); stdcall = nil;
-  glVertexAttrib2sNV: procedure(index: GLuint; x: GLshort; y: GLshort); stdcall = nil;
-  glVertexAttrib2fNV: procedure(index: GLuint; x: GLfloat; y: GLfloat); stdcall = nil;
-  glVertexAttrib2dNV: procedure(index: GLuint; x: GLdouble; y: GLdouble); stdcall = nil;
-  glVertexAttrib3sNV: procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort); stdcall = nil;
-  glVertexAttrib3fNV: procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glVertexAttrib3dNV: procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble); stdcall = nil;
-  glVertexAttrib4sNV: procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort; w: GLshort); stdcall = nil;
-  glVertexAttrib4fNV: procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glVertexAttrib4dNV: procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); stdcall = nil;
-  glVertexAttrib4ubNV: procedure(index: GLuint; x: GLubyte; y: GLubyte; z: GLubyte; w: GLubyte); stdcall = nil;
-  glVertexAttrib1svNV: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib1fvNV: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib1dvNV: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib2svNV: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib2fvNV: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib2dvNV: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib3svNV: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib3fvNV: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib3dvNV: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib4svNV: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib4fvNV: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib4dvNV: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib4ubvNV: procedure(index: GLuint; const v: PGLubyte); stdcall = nil;
-  glVertexAttribs1svNV: procedure(index: GLuint; n: GLsizei; const v: PGLshort); stdcall = nil;
-  glVertexAttribs1fvNV: procedure(index: GLuint; n: GLsizei; const v: PGLfloat); stdcall = nil;
-  glVertexAttribs1dvNV: procedure(index: GLuint; n: GLsizei; const v: PGLdouble); stdcall = nil;
-  glVertexAttribs2svNV: procedure(index: GLuint; n: GLsizei; const v: PGLshort); stdcall = nil;
-  glVertexAttribs2fvNV: procedure(index: GLuint; n: GLsizei; const v: PGLfloat); stdcall = nil;
-  glVertexAttribs2dvNV: procedure(index: GLuint; n: GLsizei; const v: PGLdouble); stdcall = nil;
-  glVertexAttribs3svNV: procedure(index: GLuint; n: GLsizei; const v: PGLshort); stdcall = nil;
-  glVertexAttribs3fvNV: procedure(index: GLuint; n: GLsizei; const v: PGLfloat); stdcall = nil;
-  glVertexAttribs3dvNV: procedure(index: GLuint; n: GLsizei; const v: PGLdouble); stdcall = nil;
-  glVertexAttribs4svNV: procedure(index: GLuint; n: GLsizei; const v: PGLshort); stdcall = nil;
-  glVertexAttribs4fvNV: procedure(index: GLuint; n: GLsizei; const v: PGLfloat); stdcall = nil;
-  glVertexAttribs4dvNV: procedure(index: GLuint; n: GLsizei; const v: PGLdouble); stdcall = nil;
-  glVertexAttribs4ubvNV: procedure(index: GLuint; n: GLsizei; const v: PGLubyte); stdcall = nil;
-
-function Load_GL_NV_vertex_program: Boolean;
-
-//***** GL_NV_vertex_program1_1 *****//
-
-function Load_GL_NV_vertex_program1_1: Boolean;
-
-//***** GL_ATI_element_array *****//
-const
-  GL_ELEMENT_ARRAY_ATI = $8768;
-  GL_ELEMENT_ARRAY_TYPE_ATI = $8769;
-  GL_ELEMENT_ARRAY_POINTER_ATI = $876A;
-var
-  glElementPointerATI: procedure(_type: GLenum; const pointer: PGLvoid); stdcall = nil;
-  glDrawElementArrayATI: procedure(mode: GLenum; count: GLsizei); stdcall = nil;
-  glDrawRangeElementArrayATI: procedure(mode: GLenum; start: GLuint; _end: GLuint; count: GLsizei); stdcall = nil;
-
-function Load_GL_ATI_element_array: Boolean;
-
-//***** GL_ATI_envmap_bumpmap *****//
-const
-  GL_BUMP_ROT_MATRIX_ATI = $8775;
-  GL_BUMP_ROT_MATRIX_SIZE_ATI = $8776;
-  GL_BUMP_NUM_TEX_UNITS_ATI = $8777;
-  GL_BUMP_TEX_UNITS_ATI = $8778;
-  GL_DUDV_ATI = $8779;
-  GL_DU8DV8_ATI = $877A;
-  GL_BUMP_ENVMAP_ATI = $877B;
-  GL_BUMP_TARGET_ATI = $877C;
-var
-  glTexBumpParameterivATI: procedure(pname: GLenum; param: PGLint); stdcall = nil;
-  glTexBumpParameterfvATI: procedure(pname: GLenum; param: PGLfloat); stdcall = nil;
-  glGetTexBumpParameterivATI: procedure(pname: GLenum; param: PGLint); stdcall = nil;
-  glGetTexBumpParameterfvATI: procedure(pname: GLenum; param: PGLfloat); stdcall = nil;
-
-function Load_GL_ATI_envmap_bumpmap: Boolean;
-
-//***** GL_ATI_fragment_shader *****//
-const
-  GL_FRAGMENT_SHADER_ATI = $8920;
-  GL_REG_0_ATI = $8921;
-  GL_REG_1_ATI = $8922;
-  GL_REG_2_ATI = $8923;
-  GL_REG_3_ATI = $8924;
-  GL_REG_4_ATI = $8925;
-  GL_REG_5_ATI = $8926;
-  GL_CON_0_ATI = $8941;
-  GL_CON_1_ATI = $8942;
-  GL_CON_2_ATI = $8943;
-  GL_CON_3_ATI = $8944;
-  GL_CON_4_ATI = $8945;
-  GL_CON_5_ATI = $8946;
-  GL_CON_6_ATI = $8947;
-  GL_CON_7_ATI = $8948;
-  GL_MOV_ATI = $8961;
-  GL_ADD_ATI = $8963;
-  GL_MUL_ATI = $8964;
-  GL_SUB_ATI = $8965;
-  GL_DOT3_ATI = $8966;
-  GL_DOT4_ATI = $8967;
-  GL_MAD_ATI = $8968;
-  GL_LERP_ATI = $8969;
-  GL_CND_ATI = $896A;
-  GL_CND0_ATI = $896B;
-  GL_DOT2_ADD_ATI = $896C;
-  GL_SECONDARY_INTERPOLATOR_ATI = $896D;
-  GL_SWIZZLE_STR_ATI = $8976;
-  GL_SWIZZLE_STQ_ATI = $8977;
-  GL_SWIZZLE_STR_DR_ATI = $8978;
-  GL_SWIZZLE_STQ_DQ_ATI = $8979;
-  GL_RED_BIT_ATI = $0001;
-  GL_GREEN_BIT_ATI = $0002;
-  GL_BLUE_BIT_ATI = $0004;
-  GL_2X_BIT_ATI = $0001;
-  GL_4X_BIT_ATI = $0002;
-  GL_8X_BIT_ATI = $0004;
-  GL_HALF_BIT_ATI = $0008;
-  GL_QUARTER_BIT_ATI = $0010;
-  GL_EIGHTH_BIT_ATI = $0020;
-  GL_SATURATE_BIT_ATI = $0040;
-  // GL_2X_BIT_ATI  { already defined }
-  GL_COMP_BIT_ATI = $0002;
-  GL_NEGATE_BIT_ATI = $0004;
-  GL_BIAS_BIT_ATI = $0008;
-var
-  glGenFragmentShadersATI: function(range: GLuint): GLuint; stdcall = nil;
-  glBindFragmentShaderATI: procedure(id: GLuint); stdcall = nil;
-  glDeleteFragmentShaderATI: procedure(id: GLuint); stdcall = nil;
-  glBeginFragmentShaderATI: procedure(); stdcall = nil;
-  glEndFragmentShaderATI: procedure(); stdcall = nil;
-  glPassTexCoordATI: procedure(dst: GLuint; coord: GLuint; swizzle: GLenum); stdcall = nil;
-  glSampleMapATI: procedure(dst: GLuint; interp: GLuint; swizzle: GLenum); stdcall = nil;
-  glColorFragmentOp1ATI: procedure(op: GLenum; dst: GLuint; dstMask: GLuint; dstMod: GLuint; arg1: GLuint; arg1Rep: GLuint; arg1Mod: GLuint); stdcall = nil;
-  glColorFragmentOp2ATI: procedure(op: GLenum; dst: GLuint; dstMask: GLuint; dstMod: GLuint; arg1: GLuint; arg1Rep: GLuint; arg1Mod: GLuint; arg2: GLuint; arg2Rep: GLuint; arg2Mod: GLuint); stdcall = nil;
-  glColorFragmentOp3ATI: procedure(op: GLenum; dst: GLuint; dstMask: GLuint; dstMod: GLuint; arg1: GLuint; arg1Rep: GLuint; arg1Mod: GLuint; arg2: GLuint; arg2Rep: GLuint; arg2Mod: GLuint; arg3: GLuint; arg3Rep: GLuint; arg3Mod: GLuint); stdcall = nil;
-  glAlphaFragmentOp1ATI: procedure(op: GLenum; dst: GLuint; dstMod: GLuint; arg1: GLuint; arg1Rep: GLuint; arg1Mod: GLuint); stdcall = nil;
-  glAlphaFragmentOp2ATI: procedure(op: GLenum; dst: GLuint; dstMod: GLuint; arg1: GLuint; arg1Rep: GLuint; arg1Mod: GLuint; arg2: GLuint; arg2Rep: GLuint; arg2Mod: GLuint); stdcall = nil;
-  glAlphaFragmentOp3ATI: procedure(op: GLenum; dst: GLuint; dstMod: GLuint; arg1: GLuint; arg1Rep: GLuint; arg1Mod: GLuint; arg2: GLuint; arg2Rep: GLuint; arg2Mod: GLuint; arg3: GLuint; arg3Rep: GLuint; arg3Mod: GLuint); stdcall = nil;
-  glSetFragmentShaderConstantATI: procedure(dst: GLuint; const value: PGLfloat); stdcall = nil;
-
-function Load_GL_ATI_fragment_shader: Boolean;
-
-//***** GL_ATI_pn_triangles *****//
-const
-  GL_PN_TRIANGLES_ATI = $87F0;
-  GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI = $87F1;
-  GL_PN_TRIANGLES_POINT_MODE_ATI = $87F2;
-  GL_PN_TRIANGLES_NORMAL_MODE_ATI = $87F3;
-  GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI = $87F4;
-  GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI = $87F5;
-  GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI = $87F6;
-  GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI = $87F7;
-  GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI = $87F8;
-var
-  glPNTrianglesiATI: procedure(pname: GLenum; param: GLint); stdcall = nil;
-  glPNTrianglesfATI: procedure(pname: GLenum; param: GLfloat); stdcall = nil;
-
-function Load_GL_ATI_pn_triangles: Boolean;
-
-//***** GL_ATI_texture_mirror_once *****//
-const
-  GL_MIRROR_CLAMP_ATI = $8742;
-  GL_MIRROR_CLAMP_TO_EDGE_ATI = $8743;
-
-function Load_GL_ATI_texture_mirror_once: Boolean;
-
-//***** GL_ATI_vertex_array_object *****//
-const
-  GL_STATIC_ATI = $8760;
-  GL_DYNAMIC_ATI = $8761;
-  GL_PRESERVE_ATI = $8762;
-  GL_DISCARD_ATI = $8763;
-  GL_OBJECT_BUFFER_SIZE_ATI = $8764;
-  GL_OBJECT_BUFFER_USAGE_ATI = $8765;
-  GL_ARRAY_OBJECT_BUFFER_ATI = $8766;
-  GL_ARRAY_OBJECT_OFFSET_ATI = $8767;
-var
-  glNewObjectBufferATI: function(size: GLsizei; const pointer: PGLvoid; usage: GLenum): GLuint; stdcall = nil;
-  glIsObjectBufferATI: function(buffer: GLuint): GLboolean; stdcall = nil;
-  glUpdateObjectBufferATI: procedure(buffer: GLuint; offset: GLuint; size: GLsizei; const pointer: PGLvoid; preserve: GLenum); stdcall = nil;
-  glGetObjectBufferfvATI: procedure(buffer: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetObjectBufferivATI: procedure(buffer: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glDeleteObjectBufferATI: procedure(buffer: GLuint); stdcall = nil;
-  glArrayObjectATI: procedure(_array: GLenum; size: GLint; _type: GLenum; stride: GLsizei; buffer: GLuint; offset: GLuint); stdcall = nil;
-  glGetArrayObjectfvATI: procedure(_array: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetArrayObjectivATI: procedure(_array: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glVariantArrayObjectATI: procedure(id: GLuint; _type: GLenum; stride: GLsizei; buffer: GLuint; offset: GLuint); stdcall = nil;
-  glGetVariantArrayObjectfvATI: procedure(id: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetVariantArrayObjectivATI: procedure(id: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-
-function Load_GL_ATI_vertex_array_object: Boolean;
-
-//***** GL_ATI_vertex_streams *****//
-const
-  GL_MAX_VERTEX_STREAMS_ATI = $876B;
-  GL_VERTEX_STREAM0_ATI = $876C;
-  GL_VERTEX_STREAM1_ATI = $876D;
-  GL_VERTEX_STREAM2_ATI = $876E;
-  GL_VERTEX_STREAM3_ATI = $876F;
-  GL_VERTEX_STREAM4_ATI = $8770;
-  GL_VERTEX_STREAM5_ATI = $8771;
-  GL_VERTEX_STREAM6_ATI = $8772;
-  GL_VERTEX_STREAM7_ATI = $8773;
-  GL_VERTEX_SOURCE_ATI = $8774;
-var
-  glVertexStream1s: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream1i: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream1f: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream1d: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glVertexStream1sv: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream1iv: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream1fv: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream1dv: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glVertexStream2s: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream2i: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream2f: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream2d: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glVertexStream2sv: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream2iv: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream2fv: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream2dv: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glVertexStream3s: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream3i: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream3f: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream3d: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glVertexStream3sv: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream3iv: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream3fv: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream3dv: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glVertexStream4s: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream4i: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream4f: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream4d: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glVertexStream4sv: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glVertexStream4iv: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glVertexStream4fv: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glVertexStream4dv: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glNormalStream3b: procedure(stream: GLenum; coords: GLbyte); stdcall = nil;
-  glNormalStream3s: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glNormalStream3i: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glNormalStream3f: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glNormalStream3d: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glNormalStream3bv: procedure(stream: GLenum; coords: GLbyte); stdcall = nil;
-  glNormalStream3sv: procedure(stream: GLenum; coords: GLshort); stdcall = nil;
-  glNormalStream3iv: procedure(stream: GLenum; coords: GLint); stdcall = nil;
-  glNormalStream3fv: procedure(stream: GLenum; coords: GLfloat); stdcall = nil;
-  glNormalStream3dv: procedure(stream: GLenum; coords: GLdouble); stdcall = nil;
-  glClientActiveVertexStream: procedure(stream: GLenum); stdcall = nil;
-  glVertexBlendEnvi: procedure(pname: GLenum; param: GLint); stdcall = nil;
-  glVertexBlendEnvf: procedure(pname: GLenum; param: GLfloat); stdcall = nil;
-
-function Load_GL_ATI_vertex_streams: Boolean;
-
-//***** WGL_I3D_image_buffer *****//
-const
-  WGL_IMAGE_BUFFER_MIN_ACCESS_I3D = $0001;
-  WGL_IMAGE_BUFFER_LOCK_I3D = $0002;
-var
-  wglCreateImageBufferI3D: function(hDC: HDC; dwSize: DWORD; uFlags: UINT): PGLvoid; stdcall = nil;
-  wglDestroyImageBufferI3D: function(hDC: HDC; pAddress: PGLvoid): BOOL; stdcall = nil;
-  wglAssociateImageBufferEventsI3D: function(hdc: HDC; pEvent: PHandle; pAddress: PGLvoid; pSize: PDWORD; count: UINT): BOOL; stdcall = nil;
-  wglReleaseImageBufferEventsI3D: function(hdc: HDC; pAddress: PGLvoid; count: UINT): BOOL; stdcall = nil;
-
-function Load_WGL_I3D_image_buffer: Boolean;
-
-//***** WGL_I3D_swap_frame_lock *****//
-var
-  wglEnableFrameLockI3D: function(): BOOL; stdcall = nil;
-  wglDisableFrameLockI3D: function(): BOOL; stdcall = nil;
-  wglIsEnabledFrameLockI3D: function(pFlag: PBOOL): BOOL; stdcall = nil;
-  wglQueryFrameLockMasterI3D: function(pFlag: PBOOL): BOOL; stdcall = nil;
-
-function Load_WGL_I3D_swap_frame_lock: Boolean;
-
-//***** WGL_I3D_swap_frame_usage *****//
-var
-  wglGetFrameUsageI3D: function(pUsage: PGLfloat): BOOL; stdcall = nil;
-  wglBeginFrameTrackingI3D: function(): BOOL; stdcall = nil;
-  wglEndFrameTrackingI3D: function(): BOOL; stdcall = nil;
-  wglQueryFrameTrackingI3D: function(pFrameCount: PDWORD; pMissedFrames: PDWORD; pLastMissedUsage: PGLfloat): BOOL; stdcall = nil;
-
-function Load_WGL_I3D_swap_frame_usage: Boolean;
-
-//***** GL_3DFX_texture_compression_FXT1 *****//
-const
-  GL_COMPRESSED_RGB_FXT1_3DFX = $86B0;
-  GL_COMPRESSED_RGBA_FXT1_3DFX = $86B1;
-
-function Load_GL_3DFX_texture_compression_FXT1: Boolean;
-
-//***** GL_IBM_cull_vertex *****//
-const
-  GL_CULL_VERTEX_IBM = $1928A;
-
-function Load_GL_IBM_cull_vertex: Boolean;
-
-//***** GL_IBM_multimode_draw_arrays *****//
-var
-  glMultiModeDrawArraysIBM: procedure(mode: PGLenum; first: PGLint; count: PGLsizei; primcount: GLsizei; modestride: GLint); stdcall = nil;
-  glMultiModeDrawElementsIBM: procedure(mode: PGLenum; count: PGLsizei; _type: GLenum; const indices: PGLvoid; primcount: GLsizei; modestride: GLint); stdcall = nil;
-
-function Load_GL_IBM_multimode_draw_arrays: Boolean;
-
-//***** GL_IBM_raster_pos_clip *****//
-const
-  GL_RASTER_POSITION_UNCLIPPED_IBM = $19262;
-
-function Load_GL_IBM_raster_pos_clip: Boolean;
-
-//***** GL_IBM_texture_mirrored_repeat *****//
-const
-  GL_MIRRORED_REPEAT_IBM = $8370;
-
-function Load_GL_IBM_texture_mirrored_repeat: Boolean;
-
-//***** GL_IBM_vertex_array_lists *****//
-const
-  GL_VERTEX_ARRAY_LIST_IBM = $1929E;
-  GL_NORMAL_ARRAY_LIST_IBM = $1929F;
-  GL_COLOR_ARRAY_LIST_IBM = $192A0;
-  GL_INDEX_ARRAY_LIST_IBM = $192A1;
-  GL_TEXTURE_COORD_ARRAY_LIST_IBM = $192A2;
-  GL_EDGE_FLAG_ARRAY_LIST_IBM = $192A3;
-  GL_FOG_COORDINATE_ARRAY_LIST_IBM = $192A4;
-  GL_SECONDARY_COLOR_ARRAY_LIST_IBM = $192A5;
-  GL_VERTEX_ARRAY_LIST_STRIDE_IBM = $192A8;
-  GL_NORMAL_ARRAY_LIST_STRIDE_IBM = $192A9;
-  GL_COLOR_ARRAY_LIST_STRIDE_IBM = $192AA;
-  GL_INDEX_ARRAY_LIST_STRIDE_IBM = $192AB;
-  GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM = $192AC;
-  GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM = $192AD;
-  GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM = $192AE;
-  GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM = $192AF;
-var
-  glColorPointerListIBM: procedure(size: GLint; _type: GLenum; stride: GLint; const pointer: PGLvoid; ptrstride: GLint); stdcall = nil;
-  glSecondaryColorPointerListIBM: procedure(size: GLint; _type: GLenum; stride: GLint; const pointer: PGLvoid; ptrstride: GLint); stdcall = nil;
-  glEdgeFlagPointerListIBM: procedure(stride: GLint; const pointer: PGLboolean; ptrstride: GLint); stdcall = nil;
-  glFogCoordPointerListIBM: procedure(_type: GLenum; stride: GLint; const pointer: PGLvoid; ptrstride: GLint); stdcall = nil;
-  glNormalPointerListIBM: procedure(_type: GLenum; stride: GLint; const pointer: PGLvoid; ptrstride: GLint); stdcall = nil;
-  glTexCoordPointerListIBM: procedure(size: GLint; _type: GLenum; stride: GLint; const pointer: PGLvoid; ptrstride: GLint); stdcall = nil;
-  glVertexPointerListIBM: procedure(size: GLint; _type: GLenum; stride: GLint; const pointer: PGLvoid; ptrstride: GLint); stdcall = nil;
-
-function Load_GL_IBM_vertex_array_lists: Boolean;
-
-//***** GL_MESA_resize_buffers *****//
-var
-  glResizeBuffersMESA: procedure(); stdcall = nil;
-
-function Load_GL_MESA_resize_buffers: Boolean;
-
-//***** GL_MESA_window_pos *****//
-var
-  glWindowPos2dMESA: procedure(x: GLdouble; y: GLdouble); stdcall = nil;
-  glWindowPos2fMESA: procedure(x: GLfloat; y: GLfloat); stdcall = nil;
-  glWindowPos2iMESA: procedure(x: GLint; y: GLint); stdcall = nil;
-  glWindowPos2sMESA: procedure(x: GLshort; y: GLshort); stdcall = nil;
-  glWindowPos2ivMESA: procedure(const p: PGLint); stdcall = nil;
-  glWindowPos2svMESA: procedure(const p: PGLshort); stdcall = nil;
-  glWindowPos2fvMESA: procedure(const p: PGLfloat); stdcall = nil;
-  glWindowPos2dvMESA: procedure(const p: PGLdouble); stdcall = nil;
-  glWindowPos3iMESA: procedure(x: GLint; y: GLint; z: GLint); stdcall = nil;
-  glWindowPos3sMESA: procedure(x: GLshort; y: GLshort; z: GLshort); stdcall = nil;
-  glWindowPos3fMESA: procedure(x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glWindowPos3dMESA: procedure(x: GLdouble; y: GLdouble; z: GLdouble); stdcall = nil;
-  glWindowPos3ivMESA: procedure(const p: PGLint); stdcall = nil;
-  glWindowPos3svMESA: procedure(const p: PGLshort); stdcall = nil;
-  glWindowPos3fvMESA: procedure(const p: PGLfloat); stdcall = nil;
-  glWindowPos3dvMESA: procedure(const p: PGLdouble); stdcall = nil;
-  glWindowPos4iMESA: procedure(x: GLint; y: GLint; z: GLint; w: GLint); stdcall = nil;
-  glWindowPos4sMESA: procedure(x: GLshort; y: GLshort; z: GLshort; w: GLshort); stdcall = nil;
-  glWindowPos4fMESA: procedure(x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glWindowPos4dMESA: procedure(x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); stdcall = nil;
-  glWindowPos4ivMESA: procedure(const p: PGLint); stdcall = nil;
-  glWindowPos4svMESA: procedure(const p: PGLshort); stdcall = nil;
-  glWindowPos4fvMESA: procedure(const p: PGLfloat); stdcall = nil;
-  glWindowPos4dvMESA: procedure(const p: PGLdouble); stdcall = nil;
-
-function Load_GL_MESA_window_pos: Boolean;
-
-//***** GL_OML_interlace *****//
-const
-  GL_INTERLACE_OML = $8980;
-  GL_INTERLACE_READ_OML = $8981;
-
-function Load_GL_OML_interlace: Boolean;
-
-//***** GL_OML_resample *****//
-const
-  GL_PACK_RESAMPLE_OML = $8984;
-  GL_UNPACK_RESAMPLE_OML = $8985;
-  GL_RESAMPLE_REPLICATE_OML = $8986;
-  GL_RESAMPLE_ZERO_FILL_OML = $8987;
-  GL_RESAMPLE_AVERAGE_OML = $8988;
-  GL_RESAMPLE_DECIMATE_OML = $8989;
-  // GL_RESAMPLE_AVERAGE_OML  { already defined }
-
-function Load_GL_OML_resample: Boolean;
-
-//***** GL_OML_subsample *****//
-const
-  GL_FORMAT_SUBSAMPLE_24_24_OML = $8982;
-  GL_FORMAT_SUBSAMPLE_244_244_OML = $8983;
-
-function Load_GL_OML_subsample: Boolean;
-
-//***** GL_SGIS_generate_mipmap *****//
-const
-  GL_GENERATE_MIPMAP_SGIS = $8191;
-  GL_GENERATE_MIPMAP_HINT_SGIS = $8192;
-
-function Load_GL_SGIS_generate_mipmap: Boolean;
-
-//***** GL_SGIS_multisample *****//
-const
-  GLX_SAMPLE_BUFFERS_SGIS = $186A0;
-  GLX_SAMPLES_SGIS = $186A1;
-  GL_MULTISAMPLE_SGIS = $809D;
-  GL_SAMPLE_ALPHA_TO_MASK_SGIS = $809E;
-  GL_SAMPLE_ALPHA_TO_ONE_SGIS = $809F;
-  GL_SAMPLE_MASK_SGIS = $80A0;
-  GL_MULTISAMPLE_BIT_EXT = $20000000;
-  GL_1PASS_SGIS = $80A1;
-  GL_2PASS_0_SGIS = $80A2;
-  GL_2PASS_1_SGIS = $80A3;
-  GL_4PASS_0_SGIS = $80A4;
-  GL_4PASS_1_SGIS = $80A5;
-  GL_4PASS_2_SGIS = $80A6;
-  GL_4PASS_3_SGIS = $80A7;
-  GL_SAMPLE_BUFFERS_SGIS = $80A8;
-  GL_SAMPLES_SGIS = $80A9;
-  GL_SAMPLE_MASK_VALUE_SGIS = $80AA;
-  GL_SAMPLE_MASK_INVERT_SGIS = $80AB;
-  GL_SAMPLE_PATTERN_SGIS = $80AC;
-var
-  glSampleMaskSGIS: procedure(value: GLclampf; invert: GLboolean); stdcall = nil;
-  glSamplePatternSGIS: procedure(pattern: GLenum); stdcall = nil;
-
-function Load_GL_SGIS_multisample: Boolean;
-
-//***** GL_SGIS_pixel_texture *****//
-const
-  GL_PIXEL_TEXTURE_SGIS = $8353;
-  GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS = $8354;
-  GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS = $8355;
-  GL_PIXEL_GROUP_COLOR_SGIS = $8356;
-var
-  glPixelTexGenParameteriSGIS: procedure(pname: GLenum; param: GLint); stdcall = nil;
-  glPixelTexGenParameterfSGIS: procedure(pname: GLenum; param: GLfloat); stdcall = nil;
-  glGetPixelTexGenParameterivSGIS: procedure(pname: GLenum; params: GLint); stdcall = nil;
-  glGetPixelTexGenParameterfvSGIS: procedure(pname: GLenum; params: GLfloat); stdcall = nil;
-
-function Load_GL_SGIS_pixel_texture: Boolean;
-
-//***** GL_SGIS_texture_border_clamp *****//
-  // GL_CLAMP_TO_BORDER_SGIS  { already defined }
-
-function Load_GL_SGIS_texture_border_clamp: Boolean;
-
-//***** GL_SGIS_texture_color_mask *****//
-const
-  GL_TEXTURE_COLOR_WRITEMASK_SGIS = $81EF;
-var
-  glTextureColorMaskSGIS: procedure(r: GLboolean; g: GLboolean; b: GLboolean; a: GLboolean); stdcall = nil;
-
-function Load_GL_SGIS_texture_color_mask: Boolean;
-
-//***** GL_SGIS_texture_edge_clamp *****//
-const
-  GL_CLAMP_TO_EDGE_SGIS = $812F;
-
-function Load_GL_SGIS_texture_edge_clamp: Boolean;
-
-//***** GL_SGIS_texture_lod *****//
-const
-  GL_TEXTURE_MIN_LOD_SGIS = $813A;
-  GL_TEXTURE_MAX_LOD_SGIS = $813B;
-  GL_TEXTURE_BASE_LEVEL_SGIS = $813C;
-  GL_TEXTURE_MAX_LEVEL_SGIS = $813D;
-
-function Load_GL_SGIS_texture_lod: Boolean;
-
-//***** GL_SGIS_depth_texture *****//
-const
-  GL_DEPTH_COMPONENT16_SGIX = $81A5;
-  GL_DEPTH_COMPONENT24_SGIX = $81A6;
-  GL_DEPTH_COMPONENT32_SGIX = $81A7;
-
-function Load_GL_SGIS_depth_texture: Boolean;
-
-//***** GL_SGIX_fog_offset *****//
-const
-  GL_FOG_OFFSET_SGIX = $8198;
-  GL_FOG_OFFSET_VALUE_SGIX = $8199;
-
-function Load_GL_SGIX_fog_offset: Boolean;
-
-//***** GL_SGIX_interlace *****//
-const
-  GL_INTERLACE_SGIX = $8094;
-
-function Load_GL_SGIX_interlace: Boolean;
-
-//***** GL_SGIX_shadow_ambient *****//
-const
-  GL_SHADOW_AMBIENT_SGIX = $80BF;
-
-function Load_GL_SGIX_shadow_ambient: Boolean;
-
-//***** GL_SGI_color_matrix *****//
-const
-  GL_COLOR_MATRIX_SGI = $80B1;
-  GL_COLOR_MATRIX_STACK_DEPTH_SGI = $80B2;
-  GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI = $80B3;
-  GL_POST_COLOR_MATRIX_RED_SCALE_SGI = $80B4;
-  GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI = $80B5;
-  GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI = $80B6;
-  GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI = $80B7;
-  GL_POST_COLOR_MATRIX_RED_BIAS_SGI = $80B8;
-  GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI = $80B9;
-  GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI = $80BA;
-  GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI = $80BB;
-
-function Load_GL_SGI_color_matrix: Boolean;
-
-//***** GL_SGI_color_table *****//
-const
-  GL_COLOR_TABLE_SGI = $80D0;
-  GL_POST_CONVOLUTION_COLOR_TABLE_SGI = $80D1;
-  GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI = $80D2;
-  GL_PROXY_COLOR_TABLE_SGI = $80D3;
-  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI = $80D4;
-  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI = $80D5;
-  GL_COLOR_TABLE_SCALE_SGI = $80D6;
-  GL_COLOR_TABLE_BIAS_SGI = $80D7;
-  GL_COLOR_TABLE_FORMAT_SGI = $80D8;
-  GL_COLOR_TABLE_WIDTH_SGI = $80D9;
-  GL_COLOR_TABLE_RED_SIZE_SGI = $80DA;
-  GL_COLOR_TABLE_GREEN_SIZE_SGI = $80DB;
-  GL_COLOR_TABLE_BLUE_SIZE_SGI = $80DC;
-  GL_COLOR_TABLE_ALPHA_SIZE_SGI = $80DD;
-  GL_COLOR_TABLE_LUMINANCE_SIZE_SGI = $80DE;
-  GL_COLOR_TABLE_INTENSITY_SIZE_SGI = $80DF;
-var
-  glColorTableSGI: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; format: GLenum; _type: GLenum; const table: PGLvoid); stdcall = nil;
-  glCopyColorTableSGI: procedure(target: GLenum; internalformat: GLenum; x: GLint; y: GLint; width: GLsizei); stdcall = nil;
-  glColorTableParameterivSGI: procedure(target: GLenum; pname: GLenum; const params: PGLint); stdcall = nil;
-  glColorTableParameterfvSGI: procedure(target: GLenum; pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glGetColorTableSGI: procedure(target: GLenum; format: GLenum; _type: GLenum; table: PGLvoid); stdcall = nil;
-  glGetColorTableParameterivSGI: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetColorTableParameterfvSGI: procedure(target: GLenum; pname: GLenum; params: PGLfloat); stdcall = nil;
-
-function Load_GL_SGI_color_table: Boolean;
-
-//***** GL_SGI_texture_color_table *****//
-const
-  GL_TEXTURE_COLOR_TABLE_SGI = $80BC;
-  GL_PROXY_TEXTURE_COLOR_TABLE_SGI = $80BD;
-
-function Load_GL_SGI_texture_color_table: Boolean;
-
-//***** GL_SUN_vertex *****//
-var
-  glColor4ubVertex2fSUN: procedure(r: GLubyte; g: GLubyte; b: GLubyte; a: GLubyte; x: GLfloat; y: GLfloat); stdcall = nil;
-  glColor4ubVertex2fvSUN: procedure(const c: PGLubyte; const v: PGLfloat); stdcall = nil;
-  glColor4ubVertex3fSUN: procedure(r: GLubyte; g: GLubyte; b: GLubyte; a: GLubyte; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glColor4ubVertex3fvSUN: procedure(const c: PGLubyte; const v: PGLfloat); stdcall = nil;
-  glColor3fVertex3fSUN: procedure(r: GLfloat; g: GLfloat; b: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glColor3fVertex3fvSUN: procedure(const c: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glNormal3fVertex3fSUN: procedure(nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glNormal3fVertex3fvSUN: procedure(const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glColor4fNormal3fVertex3fSUN: procedure(r: GLfloat; g: GLfloat; b: GLfloat; a: GLfloat; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glColor4fNormal3fVertex3fvSUN: procedure(const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glTexCoord2fVertex3fSUN: procedure(s: GLfloat; t: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glTexCoord2fVertex3fvSUN: procedure(const tc: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glTexCoord4fVertex4fSUN: procedure(s: GLfloat; t: GLfloat; p: GLfloat; q: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glTexCoord4fVertex4fvSUN: procedure(const tc: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glTexCoord2fColor4ubVertex3fSUN: procedure(s: GLfloat; t: GLfloat; r: GLubyte; g: GLubyte; b: GLubyte; a: GLubyte; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glTexCoord2fColor4ubVertex3fvSUN: procedure(const tc: PGLfloat; const c: PGLubyte; const v: PGLfloat); stdcall = nil;
-  glTexCoord2fColor3fVertex3fSUN: procedure(s: GLfloat; t: GLfloat; r: GLfloat; g: GLfloat; b: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glTexCoord2fColor3fVertex3fvSUN: procedure(const tc: PGLfloat; const c: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glTexCoord2fNormal3fVertex3fSUN: procedure(s: GLfloat; t: GLfloat; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glTexCoord2fNormal3fVertex3fvSUN: procedure(const tc: PGLfloat; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glTexCoord2fColor4fNormal3fVertex3fSUN: procedure(s: GLfloat; t: GLfloat; r: GLfloat; g: GLfloat; b: GLfloat; a: GLfloat; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glTexCoord2fColor4fNormal3fVertex3fvSUN: procedure(const tc: PGLfloat; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glTexCoord4fColor4fNormal3fVertex4fSUN: procedure(s: GLfloat; t: GLfloat; p: GLfloat; q: GLfloat; r: GLfloat; g: GLfloat; b: GLfloat; a: GLfloat; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glTexCoord4fColor4fNormal3fVertex4fvSUN: procedure(const tc: PGLfloat; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiVertex3fSUN: procedure(rc: GLuint; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiVertex3fvSUN: procedure(const rc: PGLuint; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiColor4ubVertex3fSUN: procedure(rc: GLuint; r: GLubyte; g: GLubyte; b: GLubyte; a: GLubyte; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiColor4ubVertex3fvSUN: procedure(const rc: PGLuint; const c: PGLubyte; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiColor3fVertex3fSUN: procedure(rc: GLuint; r: GLfloat; g: GLfloat; b: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiColor3fVertex3fvSUN: procedure(const rc: PGLuint; const c: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiNormal3fVertex3fSUN: procedure(rc: GLuint; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiNormal3fVertex3fvSUN: procedure(const rc: PGLuint; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiColor4fNormal3fVertex3fSUN: procedure(rc: GLuint; r: GLfloat; g: GLfloat; b: GLfloat; a: GLfloat; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiColor4fNormal3fVertex3fvSUN: procedure(const rc: PGLuint; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiTexCoord2fVertex3fSUN: procedure(rc: GLuint; s: GLfloat; t: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiTexCoord2fVertex3fvSUN: procedure(const rc: PGLuint; const tc: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN: procedure(rc: GLuint; s: GLfloat; t: GLfloat; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN: procedure(const rc: PGLuint; const tc: PGLfloat; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-  glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN: procedure(rc: GLuint; s: GLfloat; t: GLfloat; r: GLfloat; g: GLfloat; b: GLfloat; a: GLfloat; nx: GLfloat; ny: GLfloat; nz: GLfloat; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN: procedure(const rc: PGLuint; const tc: PGLfloat; const c: PGLfloat; const n: PGLfloat; const v: PGLfloat); stdcall = nil;
-
-function Load_GL_SUN_vertex: Boolean;
-
-//***** GL_ARB_fragment_program *****//
-const
-  GL_FRAGMENT_PROGRAM_ARB = $8804;
-  // GL_PROGRAM_FORMAT_ASCII_ARB  { already defined }
-  // GL_PROGRAM_LENGTH_ARB  { already defined }
-  // GL_PROGRAM_FORMAT_ARB  { already defined }
-  // GL_PROGRAM_BINDING_ARB  { already defined }
-  // GL_PROGRAM_INSTRUCTIONS_ARB  { already defined }
-  // GL_MAX_PROGRAM_INSTRUCTIONS_ARB  { already defined }
-  // GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB  { already defined }
-  // GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB  { already defined }
-  // GL_PROGRAM_TEMPORARIES_ARB  { already defined }
-  // GL_MAX_PROGRAM_TEMPORARIES_ARB  { already defined }
-  // GL_PROGRAM_NATIVE_TEMPORARIES_ARB  { already defined }
-  // GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB  { already defined }
-  // GL_PROGRAM_PARAMETERS_ARB  { already defined }
-  // GL_MAX_PROGRAM_PARAMETERS_ARB  { already defined }
-  // GL_PROGRAM_NATIVE_PARAMETERS_ARB  { already defined }
-  // GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB  { already defined }
-  // GL_PROGRAM_ATTRIBS_ARB  { already defined }
-  // GL_MAX_PROGRAM_ATTRIBS_ARB  { already defined }
-  // GL_PROGRAM_NATIVE_ATTRIBS_ARB  { already defined }
-  // GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB  { already defined }
-  // GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB  { already defined }
-  // GL_MAX_PROGRAM_ENV_PARAMETERS_ARB  { already defined }
-  // GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB  { already defined }
-  GL_PROGRAM_ALU_INSTRUCTIONS_ARB = $8805;
-  GL_PROGRAM_TEX_INSTRUCTIONS_ARB = $8806;
-  GL_PROGRAM_TEX_INDIRECTIONS_ARB = $8807;
-  GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = $8808;
-  GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = $8809;
-  GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = $880A;
-  GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB = $880B;
-  GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB = $880C;
-  GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB = $880D;
-  GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = $880E;
-  GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = $880F;
-  GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = $8810;
-  // GL_PROGRAM_STRING_ARB  { already defined }
-  // GL_PROGRAM_ERROR_POSITION_ARB  { already defined }
-  // GL_CURRENT_MATRIX_ARB  { already defined }
-  // GL_TRANSPOSE_CURRENT_MATRIX_ARB  { already defined }
-  // GL_CURRENT_MATRIX_STACK_DEPTH_ARB  { already defined }
-  // GL_MAX_PROGRAM_MATRICES_ARB  { already defined }
-  // GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB  { already defined }
-  GL_MAX_TEXTURE_COORDS_ARB = $8871;
-  GL_MAX_TEXTURE_IMAGE_UNITS_ARB = $8872;
-  // GL_PROGRAM_ERROR_STRING_ARB  { already defined }
-  // GL_MATRIX0_ARB  { already defined }
-  // GL_MATRIX1_ARB  { already defined }
-  // GL_MATRIX2_ARB  { already defined }
-  // GL_MATRIX3_ARB  { already defined }
-  // GL_MATRIX4_ARB  { already defined }
-  // GL_MATRIX5_ARB  { already defined }
-  // GL_MATRIX6_ARB  { already defined }
-  // GL_MATRIX7_ARB  { already defined }
-  // GL_MATRIX8_ARB  { already defined }
-  // GL_MATRIX9_ARB  { already defined }
-  // GL_MATRIX10_ARB  { already defined }
-  // GL_MATRIX11_ARB  { already defined }
-  // GL_MATRIX12_ARB  { already defined }
-  // GL_MATRIX13_ARB  { already defined }
-  // GL_MATRIX14_ARB  { already defined }
-  // GL_MATRIX15_ARB  { already defined }
-  // GL_MATRIX16_ARB  { already defined }
-  // GL_MATRIX17_ARB  { already defined }
-  // GL_MATRIX18_ARB  { already defined }
-  // GL_MATRIX19_ARB  { already defined }
-  // GL_MATRIX20_ARB  { already defined }
-  // GL_MATRIX21_ARB  { already defined }
-  // GL_MATRIX22_ARB  { already defined }
-  // GL_MATRIX23_ARB  { already defined }
-  // GL_MATRIX24_ARB  { already defined }
-  // GL_MATRIX25_ARB  { already defined }
-  // GL_MATRIX26_ARB  { already defined }
-  // GL_MATRIX27_ARB  { already defined }
-  // GL_MATRIX28_ARB  { already defined }
-  // GL_MATRIX29_ARB  { already defined }
-  // GL_MATRIX30_ARB  { already defined }
-  // GL_MATRIX31_ARB  { already defined }
-  // glProgramStringARB  { already defined }
-  // glBindProgramARB  { already defined }
-  // glDeleteProgramsARB  { already defined }
-  // glGenProgramsARB  { already defined }
-  // glProgramEnvParameter4dARB  { already defined }
-  // glProgramEnvParameter4dvARB  { already defined }
-  // glProgramEnvParameter4fARB  { already defined }
-  // glProgramEnvParameter4fvARB  { already defined }
-  // glProgramLocalParameter4dARB  { already defined }
-  // glProgramLocalParameter4dvARB  { already defined }
-  // glProgramLocalParameter4fARB  { already defined }
-  // glProgramLocalParameter4fvARB  { already defined }
-  // glGetProgramEnvParameterdvARB  { already defined }
-  // glGetProgramEnvParameterfvARB  { already defined }
-  // glGetProgramLocalParameterdvARB  { already defined }
-  // glGetProgramLocalParameterfvARB  { already defined }
-  // glGetProgramivARB  { already defined }
-  // glGetProgramStringARB  { already defined }
-  // glIsProgramARB  { already defined }
-
-function Load_GL_ARB_fragment_program: Boolean;
-
-//***** GL_ATI_text_fragment_shader *****//
-const
-  GL_TEXT_FRAGMENT_SHADER_ATI = $8200;
-
-function Load_GL_ATI_text_fragment_shader: Boolean;
-
-//***** GL_APPLE_client_storage *****//
-const
-  GL_UNPACK_CLIENT_STORAGE_APPLE = $85B2;
-
-function Load_GL_APPLE_client_storage: Boolean;
-
-//***** GL_APPLE_element_array *****//
-const
-  GL_ELEMENT_ARRAY_APPLE = $8768;
-  GL_ELEMENT_ARRAY_TYPE_APPLE = $8769;
-  GL_ELEMENT_ARRAY_POINTER_APPLE = $876A;
-var
-  glElementPointerAPPLE: procedure(_type: GLenum; const pointer: PGLvoid); stdcall = nil;
-  glDrawElementArrayAPPLE: procedure(mode: GLenum; first: GLint; count: GLsizei); stdcall = nil;
-  glDrawRangeElementArrayAPPLE: procedure(mode: GLenum; start: GLuint; _end: GLuint; first: GLint; count: GLsizei); stdcall = nil;
-  glMultiDrawElementArrayAPPLE: procedure(mode: GLenum; const first: PGLint; const count: PGLsizei; primcount: GLsizei); stdcall = nil;
-  glMultiDrawRangeElementArrayAPPLE: procedure(mode: GLenum; start: GLuint; _end: GLuint; const first: PGLint; const count: PGLsizei; primcount: GLsizei); stdcall = nil;
-
-function Load_GL_APPLE_element_array: Boolean;
-
-//***** GL_APPLE_fence *****//
-const
-  GL_DRAW_PIXELS_APPLE = $8A0A;
-  GL_FENCE_APPLE = $8A0B;
-var
-  glGenFencesAPPLE: procedure(n: GLsizei; fences: PGLuint); stdcall = nil;
-  glDeleteFencesAPPLE: procedure(n: GLsizei; const fences: PGLuint); stdcall = nil;
-  glSetFenceAPPLE: procedure(fence: GLuint); stdcall = nil;
-  glIsFenceAPPLE: function(fence: GLuint): GLboolean; stdcall = nil;
-  glTestFenceAPPLE: function(fence: GLuint): GLboolean; stdcall = nil;
-  glFinishFenceAPPLE: procedure(fence: GLuint); stdcall = nil;
-  glTestObjectAPPLE: function(_object: GLenum; name: GLuint): GLboolean; stdcall = nil;
-  glFinishObjectAPPLE: procedure(_object: GLenum; name: GLint); stdcall = nil;
-
-function Load_GL_APPLE_fence: Boolean;
-
-//***** GL_APPLE_vertex_array_object *****//
-const
-  GL_VERTEX_ARRAY_BINDING_APPLE = $85B5;
-var
-  glBindVertexArrayAPPLE: procedure(_array: GLuint); stdcall = nil;
-  glDeleteVertexArraysAPPLE: procedure(n: GLsizei; const arrays: PGLuint); stdcall = nil;
-  glGenVertexArraysAPPLE: procedure(n: GLsizei; const arrays: PGLuint); stdcall = nil;
-  glIsVertexArrayAPPLE: function(_array: GLuint): GLboolean; stdcall = nil;
-
-function Load_GL_APPLE_vertex_array_object: Boolean;
-
-//***** GL_APPLE_vertex_array_range *****//
-const
-  GL_VERTEX_ARRAY_RANGE_APPLE = $851D;
-  GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE = $851E;
-  GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE = $8520;
-  GL_VERTEX_ARRAY_RANGE_POINTER_APPLE = $8521;
-  GL_VERTEX_ARRAY_STORAGE_HINT_APPLE = $851F;
-  GL_STORAGE_CACHED_APPLE = $85BE;
-  GL_STORAGE_SHARED_APPLE = $85BF;
-var
-  glVertexArrayRangeAPPLE: procedure(length: GLsizei; pointer: PGLvoid); stdcall = nil;
-  glFlushVertexArrayRangeAPPLE: procedure(length: GLsizei; pointer: PGLvoid); stdcall = nil;
-  glVertexArrayParameteriAPPLE: procedure(pname: GLenum; param: GLint); stdcall = nil;
-
-function Load_GL_APPLE_vertex_array_range: Boolean;
-
-//***** WGL_ARB_pixel_format *****//
-const
-  WGL_NUMBER_PIXEL_FORMATS_ARB = $2000;
-  WGL_DRAW_TO_WINDOW_ARB = $2001;
-  WGL_DRAW_TO_BITMAP_ARB = $2002;
-  WGL_ACCELERATION_ARB = $2003;
-  WGL_NEED_PALETTE_ARB = $2004;
-  WGL_NEED_SYSTEM_PALETTE_ARB = $2005;
-  WGL_SWAP_LAYER_BUFFERS_ARB = $2006;
-  WGL_SWAP_METHOD_ARB = $2007;
-  WGL_NUMBER_OVERLAYS_ARB = $2008;
-  WGL_NUMBER_UNDERLAYS_ARB = $2009;
-  WGL_TRANSPARENT_ARB = $200A;
-  WGL_TRANSPARENT_RED_VALUE_ARB = $2037;
-  WGL_TRANSPARENT_GREEN_VALUE_ARB = $2038;
-  WGL_TRANSPARENT_BLUE_VALUE_ARB = $2039;
-  WGL_TRANSPARENT_ALPHA_VALUE_ARB = $203A;
-  WGL_TRANSPARENT_INDEX_VALUE_ARB = $203B;
-  WGL_SHARE_DEPTH_ARB = $200C;
-  WGL_SHARE_STENCIL_ARB = $200D;
-  WGL_SHARE_ACCUM_ARB = $200E;
-  WGL_SUPPORT_GDI_ARB = $200F;
-  WGL_SUPPORT_OPENGL_ARB = $2010;
-  WGL_DOUBLE_BUFFER_ARB = $2011;
-  WGL_STEREO_ARB = $2012;
-  WGL_PIXEL_TYPE_ARB = $2013;
-  WGL_COLOR_BITS_ARB = $2014;
-  WGL_RED_BITS_ARB = $2015;
-  WGL_RED_SHIFT_ARB = $2016;
-  WGL_GREEN_BITS_ARB = $2017;
-  WGL_GREEN_SHIFT_ARB = $2018;
-  WGL_BLUE_BITS_ARB = $2019;
-  WGL_BLUE_SHIFT_ARB = $201A;
-  WGL_ALPHA_BITS_ARB = $201B;
-  WGL_ALPHA_SHIFT_ARB = $201C;
-  WGL_ACCUM_BITS_ARB = $201D;
-  WGL_ACCUM_RED_BITS_ARB = $201E;
-  WGL_ACCUM_GREEN_BITS_ARB = $201F;
-  WGL_ACCUM_BLUE_BITS_ARB = $2020;
-  WGL_ACCUM_ALPHA_BITS_ARB = $2021;
-  WGL_DEPTH_BITS_ARB = $2022;
-  WGL_STENCIL_BITS_ARB = $2023;
-  WGL_AUX_BUFFERS_ARB = $2024;
-  WGL_NO_ACCELERATION_ARB = $2025;
-  WGL_GENERIC_ACCELERATION_ARB = $2026;
-  WGL_FULL_ACCELERATION_ARB = $2027;
-  WGL_SWAP_EXCHANGE_ARB = $2028;
-  WGL_SWAP_COPY_ARB = $2029;
-  WGL_SWAP_UNDEFINED_ARB = $202A;
-  WGL_TYPE_RGBA_ARB = $202B;
-  WGL_TYPE_COLORINDEX_ARB = $202C;
-var
-  wglGetPixelFormatAttribivARB: function(hdc: HDC; iPixelFormat: GLint; iLayerPlane: GLint; nAttributes: GLuint; const piAttributes: PGLint; piValues: PGLint): BOOL; stdcall = nil;
-  wglGetPixelFormatAttribfvARB: function(hdc: HDC; iPixelFormat: GLint; iLayerPlane: GLint; nAttributes: GLuint; const piAttributes: PGLint; pfValues: PGLfloat): BOOL; stdcall = nil;
-  wglChoosePixelFormatARB: function(hdc: HDC; const piAttribIList: PGLint; const pfAttribFList: PGLfloat; nMaxFormats: GLuint; piFormats: PGLint; nNumFormats: PGLuint): BOOL; stdcall = nil;
-
-function Load_WGL_ARB_pixel_format: Boolean;
-
-//***** WGL_ARB_make_current_read *****//
-const
-  WGL_ERROR_INVALID_PIXEL_TYPE_ARB = $2043;
-  WGL_ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB = $2054;
-var
-  wglMakeContextCurrentARB: function(hDrawDC: HDC; hReadDC: HDC; hglrc: HGLRC): BOOL; stdcall = nil;
-  wglGetCurrentReadDCARB: function(): HDC; stdcall = nil;
-
-function Load_WGL_ARB_make_current_read: Boolean;
-
-//***** WGL_ARB_pbuffer *****//
-const
-  WGL_DRAW_TO_PBUFFER_ARB = $202D;
-  // WGL_DRAW_TO_PBUFFER_ARB  { already defined }
-  WGL_MAX_PBUFFER_PIXELS_ARB = $202E;
-  WGL_MAX_PBUFFER_WIDTH_ARB = $202F;
-  WGL_MAX_PBUFFER_HEIGHT_ARB = $2030;
-  WGL_PBUFFER_LARGEST_ARB = $2033;
-  WGL_PBUFFER_WIDTH_ARB = $2034;
-  WGL_PBUFFER_HEIGHT_ARB = $2035;
-  WGL_PBUFFER_LOST_ARB = $2036;
-var
-  wglCreatePbufferARB: function(hDC: HDC; iPixelFormat: GLint; iWidth: GLint; iHeight: GLint; const piAttribList: PGLint): THandle; stdcall = nil;
-  wglGetPbufferDCARB: function(hPbuffer: THandle): HDC; stdcall = nil;
-  wglReleasePbufferDCARB: function(hPbuffer: THandle; hDC: HDC): GLint; stdcall = nil;
-  wglDestroyPbufferARB: function(hPbuffer: THandle): BOOL; stdcall = nil;
-  wglQueryPbufferARB: function(hPbuffer: THandle; iAttribute: GLint; piValue: PGLint): BOOL; stdcall = nil;
-
-function Load_WGL_ARB_pbuffer: Boolean;
-
-//***** WGL_EXT_swap_control *****//
-var
-  wglSwapIntervalEXT: function(interval: GLint): BOOL; stdcall = nil;
-  wglGetSwapIntervalEXT: function(): GLint; stdcall = nil;
-
-function Load_WGL_EXT_swap_control: Boolean;
-
-//***** WGL_ARB_render_texture *****//
-const
-  WGL_BIND_TO_TEXTURE_RGB_ARB = $2070;
-  WGL_BIND_TO_TEXTURE_RGBA_ARB = $2071;
-  WGL_TEXTURE_FORMAT_ARB = $2072;
-  WGL_TEXTURE_TARGET_ARB = $2073;
-  WGL_MIPMAP_TEXTURE_ARB = $2074;
-  WGL_TEXTURE_RGB_ARB = $2075;
-  WGL_TEXTURE_RGBA_ARB = $2076;
-  WGL_NO_TEXTURE_ARB = $2077;
-  WGL_TEXTURE_CUBE_MAP_ARB = $2078;
-  WGL_TEXTURE_1D_ARB = $2079;
-  WGL_TEXTURE_2D_ARB = $207A;
-  // WGL_NO_TEXTURE_ARB  { already defined }
-  WGL_MIPMAP_LEVEL_ARB = $207B;
-  WGL_CUBE_MAP_FACE_ARB = $207C;
-  WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB = $207D;
-  WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB = $207E;
-  WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB = $207F;
-  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB = $2080;
-  WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB = $2081;
-  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB = $2082;
-  WGL_FRONT_LEFT_ARB = $2083;
-  WGL_FRONT_RIGHT_ARB = $2084;
-  WGL_BACK_LEFT_ARB = $2085;
-  WGL_BACK_RIGHT_ARB = $2086;
-  WGL_AUX0_ARB = $2087;
-  WGL_AUX1_ARB = $2088;
-  WGL_AUX2_ARB = $2089;
-  WGL_AUX3_ARB = $208A;
-  WGL_AUX4_ARB = $208B;
-  WGL_AUX5_ARB = $208C;
-  WGL_AUX6_ARB = $208D;
-  WGL_AUX7_ARB = $208E;
-  WGL_AUX8_ARB = $208F;
-  WGL_AUX9_ARB = $2090;
-var
-  wglBindTexImageARB: function(hPbuffer: THandle; iBuffer: GLint): BOOL; stdcall = nil;
-  wglReleaseTexImageARB: function(hPbuffer: THandle; iBuffer: GLint): BOOL; stdcall = nil;
-  wglSetPbufferAttribARB: function(hPbuffer: THandle; const piAttribList: PGLint): BOOL; stdcall = nil;
-
-function Load_WGL_ARB_render_texture: Boolean;
-
-//***** WGL_EXT_extensions_string *****//
-var
-  wglGetExtensionsStringEXT: function(): Pchar; stdcall = nil;
-
-function Load_WGL_EXT_extensions_string: Boolean;
-
-//***** WGL_EXT_make_current_read *****//
-var
-  wglMakeContextCurrentEXT: function(hDrawDC: HDC; hReadDC: HDC; hglrc: HGLRC): BOOL; stdcall = nil;
-  wglGetCurrentReadDCEXT: function(): HDC; stdcall = nil;
-
-function Load_WGL_EXT_make_current_read: Boolean;
-
-//***** WGL_EXT_pbuffer *****//
-const
-  WGL_DRAW_TO_PBUFFER_EXT = $202D;
-  WGL_MAX_PBUFFER_PIXELS_EXT = $202E;
-  WGL_MAX_PBUFFER_WIDTH_EXT = $202F;
-  WGL_MAX_PBUFFER_HEIGHT_EXT = $2030;
-  WGL_OPTIMAL_PBUFFER_WIDTH_EXT = $2031;
-  WGL_OPTIMAL_PBUFFER_HEIGHT_EXT = $2032;
-  WGL_PBUFFER_LARGEST_EXT = $2033;
-  WGL_PBUFFER_WIDTH_EXT = $2034;
-  WGL_PBUFFER_HEIGHT_EXT = $2035;
-var
-  wglCreatePbufferEXT: function(hDC: HDC; iPixelFormat: GLint; iWidth: GLint; iHeight: GLint; const piAttribList: PGLint): THandle; stdcall = nil;
-  wglGetPbufferDCEXT: function(hPbuffer: THandle): HDC; stdcall = nil;
-  wglReleasePbufferDCEXT: function(hPbuffer: THandle; hDC: HDC): GLint; stdcall = nil;
-  wglDestroyPbufferEXT: function(hPbuffer: THandle): BOOL; stdcall = nil;
-  wglQueryPbufferEXT: function(hPbuffer: THandle; iAttribute: GLint; piValue: PGLint): BOOL; stdcall = nil;
-
-function Load_WGL_EXT_pbuffer: Boolean;
-
-//***** WGL_EXT_pixel_format *****//
-const
-  WGL_NUMBER_PIXEL_FORMATS_EXT = $2000;
-  WGL_DRAW_TO_WINDOW_EXT = $2001;
-  WGL_DRAW_TO_BITMAP_EXT = $2002;
-  WGL_ACCELERATION_EXT = $2003;
-  WGL_NEED_PALETTE_EXT = $2004;
-  WGL_NEED_SYSTEM_PALETTE_EXT = $2005;
-  WGL_SWAP_LAYER_BUFFERS_EXT = $2006;
-  WGL_SWAP_METHOD_EXT = $2007;
-  WGL_NUMBER_OVERLAYS_EXT = $2008;
-  WGL_NUMBER_UNDERLAYS_EXT = $2009;
-  WGL_TRANSPARENT_EXT = $200A;
-  WGL_TRANSPARENT_VALUE_EXT = $200B;
-  WGL_SHARE_DEPTH_EXT = $200C;
-  WGL_SHARE_STENCIL_EXT = $200D;
-  WGL_SHARE_ACCUM_EXT = $200E;
-  WGL_SUPPORT_GDI_EXT = $200F;
-  WGL_SUPPORT_OPENGL_EXT = $2010;
-  WGL_DOUBLE_BUFFER_EXT = $2011;
-  WGL_STEREO_EXT = $2012;
-  WGL_PIXEL_TYPE_EXT = $2013;
-  WGL_COLOR_BITS_EXT = $2014;
-  WGL_RED_BITS_EXT = $2015;
-  WGL_RED_SHIFT_EXT = $2016;
-  WGL_GREEN_BITS_EXT = $2017;
-  WGL_GREEN_SHIFT_EXT = $2018;
-  WGL_BLUE_BITS_EXT = $2019;
-  WGL_BLUE_SHIFT_EXT = $201A;
-  WGL_ALPHA_BITS_EXT = $201B;
-  WGL_ALPHA_SHIFT_EXT = $201C;
-  WGL_ACCUM_BITS_EXT = $201D;
-  WGL_ACCUM_RED_BITS_EXT = $201E;
-  WGL_ACCUM_GREEN_BITS_EXT = $201F;
-  WGL_ACCUM_BLUE_BITS_EXT = $2020;
-  WGL_ACCUM_ALPHA_BITS_EXT = $2021;
-  WGL_DEPTH_BITS_EXT = $2022;
-  WGL_STENCIL_BITS_EXT = $2023;
-  WGL_AUX_BUFFERS_EXT = $2024;
-  WGL_NO_ACCELERATION_EXT = $2025;
-  WGL_GENERIC_ACCELERATION_EXT = $2026;
-  WGL_FULL_ACCELERATION_EXT = $2027;
-  WGL_SWAP_EXCHANGE_EXT = $2028;
-  WGL_SWAP_COPY_EXT = $2029;
-  WGL_SWAP_UNDEFINED_EXT = $202A;
-  WGL_TYPE_RGBA_EXT = $202B;
-  WGL_TYPE_COLORINDEX_EXT = $202C;
-var
-  wglGetPixelFormatAttribivEXT: function(hdc: HDC; iPixelFormat: GLint; iLayerPlane: GLint; nAttributes: GLuint; piAttributes: PGLint; piValues: PGLint): BOOL; stdcall = nil;
-  wglGetPixelFormatAttribfvEXT: function(hdc: HDC; iPixelFormat: GLint; iLayerPlane: GLint; nAttributes: GLuint; piAttributes: PGLint; pfValues: PGLfloat): BOOL; stdcall = nil;
-  wglChoosePixelFormatEXT: function(hdc: HDC; const piAttribIList: PGLint; const pfAttribFList: PGLfloat; nMaxFormats: GLuint; piFormats: PGLint; nNumFormats: PGLuint): BOOL; stdcall = nil;
-
-function Load_WGL_EXT_pixel_format: Boolean;
-
-//***** WGL_I3D_digital_video_control *****//
-const
-  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D = $2050;
-  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D = $2051;
-  WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D = $2052;
-  WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D = $2053;
-var
-  wglGetDigitalVideoParametersI3D: function(hDC: HDC; iAttribute: GLint; piValue: PGLint): BOOL; stdcall = nil;
-  wglSetDigitalVideoParametersI3D: function(hDC: HDC; iAttribute: GLint; const piValue: PGLint): BOOL; stdcall = nil;
-
-function Load_WGL_I3D_digital_video_control: Boolean;
-
-//***** WGL_I3D_gamma *****//
-const
-  WGL_GAMMA_TABLE_SIZE_I3D = $204E;
-  WGL_GAMMA_EXCLUDE_DESKTOP_I3D = $204F;
-  // WGL_GAMMA_EXCLUDE_DESKTOP_I3D  { already defined }
-var
-  wglGetGammaTableParametersI3D: function(hDC: HDC; iAttribute: GLint; piValue: PGLint): BOOL; stdcall = nil;
-  wglSetGammaTableParametersI3D: function(hDC: HDC; iAttribute: GLint; const piValue: PGLint): BOOL; stdcall = nil;
-  wglGetGammaTableI3D: function(hDC: HDC; iEntries: GLint; puRed: PGLUSHORT; puGreen: PGLUSHORT; puBlue: PGLUSHORT): BOOL; stdcall = nil;
-  wglSetGammaTableI3D: function(hDC: HDC; iEntries: GLint; const puRed: PGLUSHORT; const puGreen: PGLUSHORT; const puBlue: PGLUSHORT): BOOL; stdcall = nil;
-
-function Load_WGL_I3D_gamma: Boolean;
-
-//***** WGL_I3D_genlock *****//
-const
-  WGL_GENLOCK_SOURCE_MULTIVIEW_I3D = $2044;
-  WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D = $2045;
-  WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D = $2046;
-  WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D = $2047;
-  WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D = $2048;
-  WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D = $2049;
-  WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D = $204A;
-  WGL_GENLOCK_SOURCE_EDGE_RISING_I3D = $204B;
-  WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D = $204C;
-var
-  wglEnableGenlockI3D: function(hDC: HDC): BOOL; stdcall = nil;
-  wglDisableGenlockI3D: function(hDC: HDC): BOOL; stdcall = nil;
-  wglIsEnabledGenlockI3D: function(hDC: HDC; pFlag: PBOOL): BOOL; stdcall = nil;
-  wglGenlockSourceI3D: function(hDC: HDC; uSource: GLUINT): BOOL; stdcall = nil;
-  wglGetGenlockSourceI3D: function(hDC: HDC; uSource: PGLUINT): BOOL; stdcall = nil;
-  wglGenlockSourceEdgeI3D: function(hDC: HDC; uEdge: GLUINT): BOOL; stdcall = nil;
-  wglGetGenlockSourceEdgeI3D: function(hDC: HDC; uEdge: PGLUINT): BOOL; stdcall = nil;
-  wglGenlockSampleRateI3D: function(hDC: HDC; uRate: GLUINT): BOOL; stdcall = nil;
-  wglGetGenlockSampleRateI3D: function(hDC: HDC; uRate: PGLUINT): BOOL; stdcall = nil;
-  wglGenlockSourceDelayI3D: function(hDC: HDC; uDelay: GLUINT): BOOL; stdcall = nil;
-  wglGetGenlockSourceDelayI3D: function(hDC: HDC; uDelay: PGLUINT): BOOL; stdcall = nil;
-  wglQueryGenlockMaxSourceDelayI3D: function(hDC: HDC; uMaxLineDelay: PGLUINT; uMaxPixelDelay: PGLUINT): BOOL; stdcall = nil;
-
-function Load_WGL_I3D_genlock: Boolean;
-
-//***** GL_ARB_matrix_palette *****//
-const
-  GL_MATRIX_PALETTE_ARB = $8840;
-  GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB = $8841;
-  GL_MAX_PALETTE_MATRICES_ARB = $8842;
-  GL_CURRENT_PALETTE_MATRIX_ARB = $8843;
-  GL_MATRIX_INDEX_ARRAY_ARB = $8844;
-  GL_CURRENT_MATRIX_INDEX_ARB = $8845;
-  GL_MATRIX_INDEX_ARRAY_SIZE_ARB = $8846;
-  GL_MATRIX_INDEX_ARRAY_TYPE_ARB = $8847;
-  GL_MATRIX_INDEX_ARRAY_STRIDE_ARB = $8848;
-  GL_MATRIX_INDEX_ARRAY_POINTER_ARB = $8849;
-var
-  glCurrentPaletteMatrixARB: procedure(index: GLint); stdcall = nil;
-  glMatrixIndexubvARB: procedure(size: GLint; indices: PGLubyte); stdcall = nil;
-  glMatrixIndexusvARB: procedure(size: GLint; indices: PGLushort); stdcall = nil;
-  glMatrixIndexuivARB: procedure(size: GLint; indices: PGLuint); stdcall = nil;
-  glMatrixIndexPointerARB: procedure(size: GLint; _type: GLenum; stride: GLsizei; pointer: PGLvoid); stdcall = nil;
-
-function Load_GL_ARB_matrix_palette: Boolean;
-
-//***** GL_NV_element_array *****//
-const
-  GL_ELEMENT_ARRAY_TYPE_NV = $8769;
-  GL_ELEMENT_ARRAY_POINTER_NV = $876A;
-var
-  glElementPointerNV: procedure(_type: GLenum; const pointer: PGLvoid); stdcall = nil;
-  glDrawElementArrayNV: procedure(mode: GLenum; first: GLint; count: GLsizei); stdcall = nil;
-  glDrawRangeElementArrayNV: procedure(mode: GLenum; start: GLuint; _end: GLuint; first: GLint; count: GLsizei); stdcall = nil;
-  glMultiDrawElementArrayNV: procedure(mode: GLenum; const first: PGLint; const count: PGLsizei; primcount: GLsizei); stdcall = nil;
-  glMultiDrawRangeElementArrayNV: procedure(mode: GLenum; start: GLuint; _end: GLuint; const first: PGLint; const count: PGLsizei; primcount: GLsizei); stdcall = nil;
-
-function Load_GL_NV_element_array: Boolean;
-
-//***** GL_NV_float_buffer *****//
-const
-  GL_FLOAT_R_NV = $8880;
-  GL_FLOAT_RG_NV = $8881;
-  GL_FLOAT_RGB_NV = $8882;
-  GL_FLOAT_RGBA_NV = $8883;
-  GL_FLOAT_R16_NV = $8884;
-  GL_FLOAT_R32_NV = $8885;
-  GL_FLOAT_RG16_NV = $8886;
-  GL_FLOAT_RG32_NV = $8887;
-  GL_FLOAT_RGB16_NV = $8888;
-  GL_FLOAT_RGB32_NV = $8889;
-  GL_FLOAT_RGBA16_NV = $888A;
-  GL_FLOAT_RGBA32_NV = $888B;
-  GL_TEXTURE_FLOAT_COMPONENTS_NV = $888C;
-  GL_FLOAT_CLEAR_COLOR_VALUE_NV = $888D;
-  GL_FLOAT_RGBA_MODE_NV = $888E;
-  WGL_FLOAT_COMPONENTS_NV = $20B0;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV = $20B1;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV = $20B2;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV = $20B3;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV = $20B4;
-  WGL_TEXTURE_FLOAT_R_NV = $20B5;
-  WGL_TEXTURE_FLOAT_RG_NV = $20B6;
-  WGL_TEXTURE_FLOAT_RGB_NV = $20B7;
-  WGL_TEXTURE_FLOAT_RGBA_NV = $20B8;
-
-function Load_GL_NV_float_buffer: Boolean;
-
-//***** GL_NV_fragment_program *****//
-const
-  GL_FRAGMENT_PROGRAM_NV = $8870;
-  GL_MAX_TEXTURE_COORDS_NV = $8871;
-  GL_MAX_TEXTURE_IMAGE_UNITS_NV = $8872;
-  GL_FRAGMENT_PROGRAM_BINDING_NV = $8873;
-  GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV = $8868;
-  GL_PROGRAM_ERROR_STRING_NV = $8874;
-var
-  glProgramNamedParameter4fNV: procedure(id: GLuint; len: GLsizei; const name: PGLubyte; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glProgramNamedParameter4dNV: procedure(id: GLuint; len: GLsizei; const name: PGLubyte; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); stdcall = nil;
-  glGetProgramNamedParameterfvNV: procedure(id: GLuint; len: GLsizei; const name: PGLubyte; params: PGLfloat); stdcall = nil;
-  glGetProgramNamedParameterdvNV: procedure(id: GLuint; len: GLsizei; const name: PGLubyte; params: PGLdouble); stdcall = nil;
-  // glProgramLocalParameter4dARB  { already defined }
-  // glProgramLocalParameter4dvARB  { already defined }
-  // glProgramLocalParameter4fARB  { already defined }
-  // glProgramLocalParameter4fvARB  { already defined }
-  // glGetProgramLocalParameterdvARB  { already defined }
-  // glGetProgramLocalParameterfvARB  { already defined }
-
-function Load_GL_NV_fragment_program: Boolean;
-
-//***** GL_NV_primitive_restart *****//
-const
-  GL_PRIMITIVE_RESTART_NV = $8558;
-  GL_PRIMITIVE_RESTART_INDEX_NV = $8559;
-var
-  glPrimitiveRestartNV: procedure(); stdcall = nil;
-  glPrimitiveRestartIndexNV: procedure(index: GLuint); stdcall = nil;
-
-function Load_GL_NV_primitive_restart: Boolean;
-
-//***** GL_NV_vertex_program2 *****//
-
-function Load_GL_NV_vertex_program2: Boolean;
-
-//***** WGL_NV_render_texture_rectangle *****//
-const
-  WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV = $20A0;
-  WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV = $20A1;
-  WGL_TEXTURE_RECTANGLE_NV = $20A2;
-
-function Load_WGL_NV_render_texture_rectangle: Boolean;
-
-//***** GL_NV_pixel_data_range *****//
-const
-  GL_WRITE_PIXEL_DATA_RANGE_NV = $8878;
-  GL_READ_PIXEL_DATA_RANGE_NV = $8879;
-  GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV = $887A;
-  GL_READ_PIXEL_DATA_RANGE_LENGTH_NV = $887B;
-  GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV = $887C;
-  GL_READ_PIXEL_DATA_RANGE_POINTER_NV = $887D;
-var
-  glPixelDataRangeNV: procedure(target: GLenum; length: GLsizei; pointer: PGLvoid); stdcall = nil;
-  glFlushPixelDataRangeNV: procedure(target: GLenum); stdcall = nil;
-  // wglAllocateMemoryNV  { already defined }
-  // wglFreeMemoryNV  { already defined }
-
-function Load_GL_NV_pixel_data_range: Boolean;
-
-//***** GL_EXT_texture_rectangle *****//
-const
-  GL_TEXTURE_RECTANGLE_EXT = $84F5;
-  GL_TEXTURE_BINDING_RECTANGLE_EXT = $84F6;
-  GL_PROXY_TEXTURE_RECTANGLE_EXT = $84F7;
-  GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT = $84F8;
-
-function Load_GL_EXT_texture_rectangle: Boolean;
-
-//***** GL_S3_s3tc *****//
-const
-  GL_RGB_S3TC = $83A0;
-  GL_RGB4_S3TC = $83A1;
-  GL_RGBA_S3TC = $83A2;
-  GL_RGBA4_S3TC = $83A3;
-
-function Load_GL_S3_s3tc: Boolean;
-
-//***** GL_ATI_draw_buffers *****//
-const
-  GL_MAX_DRAW_BUFFERS_ATI = $8824;
-  GL_DRAW_BUFFER0_ATI = $8825;
-  GL_DRAW_BUFFER1_ATI = $8826;
-  GL_DRAW_BUFFER2_ATI = $8827;
-  GL_DRAW_BUFFER3_ATI = $8828;
-  GL_DRAW_BUFFER4_ATI = $8829;
-  GL_DRAW_BUFFER5_ATI = $882A;
-  GL_DRAW_BUFFER6_ATI = $882B;
-  GL_DRAW_BUFFER7_ATI = $882C;
-  GL_DRAW_BUFFER8_ATI = $882D;
-  GL_DRAW_BUFFER9_ATI = $882E;
-  GL_DRAW_BUFFER10_ATI = $882F;
-  GL_DRAW_BUFFER11_ATI = $8830;
-  GL_DRAW_BUFFER12_ATI = $8831;
-  GL_DRAW_BUFFER13_ATI = $8832;
-  GL_DRAW_BUFFER14_ATI = $8833;
-  GL_DRAW_BUFFER15_ATI = $8834;
-var
-  glDrawBuffersATI: procedure(n: GLsizei; const bufs: PGLenum); stdcall = nil;
-
-function Load_GL_ATI_draw_buffers: Boolean;
-
-//***** WGL_ATI_pixel_format_float *****//
-const
-  WGL_RGBA_FLOAT_MODE_ATI = $8820;
-  WGL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI = $8835;
-  WGL_TYPE_RGBA_FLOAT_ATI = $21A0;
-
-function Load_WGL_ATI_pixel_format_float: Boolean;
-
-//***** GL_ATI_texture_env_combine3 *****//
-const
-  GL_MODULATE_ADD_ATI = $8744;
-  GL_MODULATE_SIGNED_ADD_ATI = $8745;
-  GL_MODULATE_SUBTRACT_ATI = $8746;
-
-function Load_GL_ATI_texture_env_combine3: Boolean;
-
-//***** GL_ATI_texture_float *****//
-const
-  GL_RGBA_FLOAT32_ATI = $8814;
-  GL_RGB_FLOAT32_ATI = $8815;
-  GL_ALPHA_FLOAT32_ATI = $8816;
-  GL_INTENSITY_FLOAT32_ATI = $8817;
-  GL_LUMINANCE_FLOAT32_ATI = $8818;
-  GL_LUMINANCE_ALPHA_FLOAT32_ATI = $8819;
-  GL_RGBA_FLOAT16_ATI = $881A;
-  GL_RGB_FLOAT16_ATI = $881B;
-  GL_ALPHA_FLOAT16_ATI = $881C;
-  GL_INTENSITY_FLOAT16_ATI = $881D;
-  GL_LUMINANCE_FLOAT16_ATI = $881E;
-  GL_LUMINANCE_ALPHA_FLOAT16_ATI = $881F;
-
-function Load_GL_ATI_texture_float: Boolean;
-
-//***** GL_NV_texture_expand_normal *****//
-const
-  GL_TEXTURE_UNSIGNED_REMAP_MODE_NV = $888F;
-
-function Load_GL_NV_texture_expand_normal: Boolean;
-
-//***** GL_NV_half_float *****//
-const
-  GL_HALF_FLOAT_NV = $140B;
-var
-  glVertex2hNV: procedure(x: GLushort; y: GLushort); stdcall = nil;
-  glVertex2hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glVertex3hNV: procedure(x: GLushort; y: GLushort; z: GLushort); stdcall = nil;
-  glVertex3hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glVertex4hNV: procedure(x: GLushort; y: GLushort; z: GLushort; w: GLushort); stdcall = nil;
-  glVertex4hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glNormal3hNV: procedure(nx: GLushort; ny: GLushort; nz: GLushort); stdcall = nil;
-  glNormal3hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glColor3hNV: procedure(red: GLushort; green: GLushort; blue: GLushort); stdcall = nil;
-  glColor3hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glColor4hNV: procedure(red: GLushort; green: GLushort; blue: GLushort; alpha: GLushort); stdcall = nil;
-  glColor4hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glTexCoord1hNV: procedure(s: GLushort); stdcall = nil;
-  glTexCoord1hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glTexCoord2hNV: procedure(s: GLushort; t: GLushort); stdcall = nil;
-  glTexCoord2hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glTexCoord3hNV: procedure(s: GLushort; t: GLushort; r: GLushort); stdcall = nil;
-  glTexCoord3hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glTexCoord4hNV: procedure(s: GLushort; t: GLushort; r: GLushort; q: GLushort); stdcall = nil;
-  glTexCoord4hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glMultiTexCoord1hNV: procedure(target: GLenum; s: GLushort); stdcall = nil;
-  glMultiTexCoord1hvNV: procedure(target: GLenum; const v: PGLushort); stdcall = nil;
-  glMultiTexCoord2hNV: procedure(target: GLenum; s: GLushort; t: GLushort); stdcall = nil;
-  glMultiTexCoord2hvNV: procedure(target: GLenum; const v: PGLushort); stdcall = nil;
-  glMultiTexCoord3hNV: procedure(target: GLenum; s: GLushort; t: GLushort; r: GLushort); stdcall = nil;
-  glMultiTexCoord3hvNV: procedure(target: GLenum; const v: PGLushort); stdcall = nil;
-  glMultiTexCoord4hNV: procedure(target: GLenum; s: GLushort; t: GLushort; r: GLushort; q: GLushort); stdcall = nil;
-  glMultiTexCoord4hvNV: procedure(target: GLenum; const v: PGLushort); stdcall = nil;
-  glFogCoordhNV: procedure(fog: GLushort); stdcall = nil;
-  glFogCoordhvNV: procedure(const fog: PGLushort); stdcall = nil;
-  glSecondaryColor3hNV: procedure(red: GLushort; green: GLushort; blue: GLushort); stdcall = nil;
-  glSecondaryColor3hvNV: procedure(const v: PGLushort); stdcall = nil;
-  glVertexWeighthNV: procedure(weight: GLushort); stdcall = nil;
-  glVertexWeighthvNV: procedure(const weight: PGLushort); stdcall = nil;
-  glVertexAttrib1hNV: procedure(index: GLuint; x: GLushort); stdcall = nil;
-  glVertexAttrib1hvNV: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttrib2hNV: procedure(index: GLuint; x: GLushort; y: GLushort); stdcall = nil;
-  glVertexAttrib2hvNV: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttrib3hNV: procedure(index: GLuint; x: GLushort; y: GLushort; z: GLushort); stdcall = nil;
-  glVertexAttrib3hvNV: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttrib4hNV: procedure(index: GLuint; x: GLushort; y: GLushort; z: GLushort; w: GLushort); stdcall = nil;
-  glVertexAttrib4hvNV: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttribs1hvNV: procedure(index: GLuint; n: GLsizei; const v: PGLushort); stdcall = nil;
-  glVertexAttribs2hvNV: procedure(index: GLuint; n: GLsizei; const v: PGLushort); stdcall = nil;
-  glVertexAttribs3hvNV: procedure(index: GLuint; n: GLsizei; const v: PGLushort); stdcall = nil;
-  glVertexAttribs4hvNV: procedure(index: GLuint; n: GLsizei; const v: PGLushort); stdcall = nil;
-
-function Load_GL_NV_half_float: Boolean;
-
-//***** GL_ATI_map_object_buffer *****//
-var
-  glMapObjectBufferATI: function(buffer: GLuint): PGLvoid; stdcall = nil;
-  glUnmapObjectBufferATI: procedure(buffer: GLuint); stdcall = nil;
-
-function Load_GL_ATI_map_object_buffer: Boolean;
-
-//***** GL_ATI_separate_stencil *****//
-const
-  GL_KEEP = $1E00;
-  GL_ZERO = $0000;
-  GL_REPLACE = $1E01;
-  GL_INCR = $1E02;
-  GL_DECR = $1E03;
-  GL_INVERT = $150A;
-  GL_NEVER = $0200;
-  GL_LESS = $0201;
-  GL_LEQUAL = $0203;
-  GL_GREATER = $0204;
-  GL_GEQUAL = $0206;
-  GL_EQUAL = $0202;
-  GL_NOTEQUAL = $0205;
-  GL_ALWAYS = $0207;
-  GL_FRONT = $0404;
-  GL_BACK = $0405;
-  GL_FRONT_AND_BACK = $0408;
-  GL_STENCIL_BACK_FUNC_ATI = $8800;
-  GL_STENCIL_BACK_FAIL_ATI = $8801;
-  GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI = $8802;
-  GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI = $8803;
-var
-  glStencilOpSeparateATI: procedure(face: GLenum; sfail: GLenum; dpfail: GLenum; dppass: GLenum); stdcall = nil;
-  glStencilFuncSeparateATI: procedure(frontfunc: GLenum; backfunc: GLenum; ref: GLint; mask: GLuint); stdcall = nil;
-
-function Load_GL_ATI_separate_stencil: Boolean;
-
-//***** GL_ATI_vertex_attrib_array_object *****//
-var
-  glVertexAttribArrayObjectATI: procedure(index: GLuint; size: GLint; _type: GLenum; normalized: GLboolean; stride: GLsizei; buffer: GLuint; offset: GLuint); stdcall = nil;
-  glGetVertexAttribArrayObjectfvATI: procedure(index: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetVertexAttribArrayObjectivATI: procedure(index: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-
-function Load_GL_ATI_vertex_attrib_array_object: Boolean;
-
-//***** GL_ARB_vertex_buffer_object *****//
-const
-  GL_ARRAY_BUFFER_ARB = $8892;
-  GL_ELEMENT_ARRAY_BUFFER_ARB = $8893;
-  GL_ARRAY_BUFFER_BINDING_ARB = $8894;
-  GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB = $8895;
-  GL_VERTEX_ARRAY_BUFFER_BINDING_ARB = $8896;
-  GL_NORMAL_ARRAY_BUFFER_BINDING_ARB = $8897;
-  GL_COLOR_ARRAY_BUFFER_BINDING_ARB = $8898;
-  GL_INDEX_ARRAY_BUFFER_BINDING_ARB = $8899;
-  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB = $889A;
-  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB = $889B;
-  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB = $889C;
-  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB = $889D;
-  GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB = $889E;
-  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB = $889F;
-  GL_STREAM_DRAW_ARB = $88E0;
-  GL_STREAM_READ_ARB = $88E1;
-  GL_STREAM_COPY_ARB = $88E2;
-  GL_STATIC_DRAW_ARB = $88E4;
-  GL_STATIC_READ_ARB = $88E5;
-  GL_STATIC_COPY_ARB = $88E6;
-  GL_DYNAMIC_DRAW_ARB = $88E8;
-  GL_DYNAMIC_READ_ARB = $88E9;
-  GL_DYNAMIC_COPY_ARB = $88EA;
-  GL_READ_ONLY_ARB = $88B8;
-  GL_WRITE_ONLY_ARB = $88B9;
-  GL_READ_WRITE_ARB = $88BA;
-  GL_BUFFER_SIZE_ARB = $8764;
-  GL_BUFFER_USAGE_ARB = $8765;
-  GL_BUFFER_ACCESS_ARB = $88BB;
-  GL_BUFFER_MAPPED_ARB = $88BC;
-  GL_BUFFER_MAP_POINTER_ARB = $88BD;
-var
-  glBindBufferARB: procedure(target: GLenum; buffer: GLuint); stdcall = nil;
-  glDeleteBuffersARB: procedure(n: GLsizei; const buffers: PGLuint); stdcall = nil;
-  glGenBuffersARB: procedure(n: GLsizei; buffers: PGLuint); stdcall = nil;
-  glIsBufferARB: function(buffer: GLuint): GLboolean; stdcall = nil;
-  glBufferDataARB: procedure(target: GLenum; size: GLsizeiptrARB; const data: PGLvoid; usage: GLenum); stdcall = nil;
-  glBufferSubDataARB: procedure(target: GLenum; offset: GLintptrARB; size: GLsizeiptrARB; const data: PGLvoid); stdcall = nil;
-  glGetBufferSubDataARB: procedure(target: GLenum; offset: GLintptrARB; size: GLsizeiptrARB; data: PGLvoid); stdcall = nil;
-  glMapBufferARB: function(target: GLenum; access: GLenum): PGLvoid; stdcall = nil;
-  glUnmapBufferARB: function(target: GLenum): GLboolean; stdcall = nil;
-  glGetBufferParameterivARB: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetBufferPointervARB: procedure(target: GLenum; pname: GLenum; params: PGLvoid); stdcall = nil;
-
-function Load_GL_ARB_vertex_buffer_object: Boolean;
-
-//***** GL_ARB_occlusion_query *****//
-const
-  GL_SAMPLES_PASSED_ARB = $8914;
-  GL_QUERY_COUNTER_BITS_ARB = $8864;
-  GL_CURRENT_QUERY_ARB = $8865;
-  GL_QUERY_RESULT_ARB = $8866;
-  GL_QUERY_RESULT_AVAILABLE_ARB = $8867;
-var
-  glGenQueriesARB: procedure(n: GLsizei; ids: PGLuint); stdcall = nil;
-  glDeleteQueriesARB: procedure(n: GLsizei; const ids: PGLuint); stdcall = nil;
-  glIsQueryARB: function(id: GLuint): GLboolean; stdcall = nil;
-  glBeginQueryARB: procedure(target: GLenum; id: GLuint); stdcall = nil;
-  glEndQueryARB: procedure(target: GLenum); stdcall = nil;
-  glGetQueryivARB: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetQueryObjectivARB: procedure(id: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetQueryObjectuivARB: procedure(id: GLuint; pname: GLenum; params: PGLuint); stdcall = nil;
-
-function Load_GL_ARB_occlusion_query: Boolean;
-
-//***** GL_ARB_shader_objects *****//
-const
-  GL_PROGRAM_OBJECT_ARB = $8B40;
-  GL_OBJECT_TYPE_ARB = $8B4E;
-  GL_OBJECT_SUBTYPE_ARB = $8B4F;
-  GL_OBJECT_DELETE_STATUS_ARB = $8B80;
-  GL_OBJECT_COMPILE_STATUS_ARB = $8B81;
-  GL_OBJECT_LINK_STATUS_ARB = $8B82;
-  GL_OBJECT_VALIDATE_STATUS_ARB = $8B83;
-  GL_OBJECT_INFO_LOG_LENGTH_ARB = $8B84;
-  GL_OBJECT_ATTACHED_OBJECTS_ARB = $8B85;
-  GL_OBJECT_ACTIVE_UNIFORMS_ARB = $8B86;
-  GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB = $8B87;
-  GL_OBJECT_SHADER_SOURCE_LENGTH_ARB = $8B88;
-  GL_SHADER_OBJECT_ARB = $8B48;
-  GL_FLOAT = $1406;
-  GL_FLOAT_VEC2_ARB = $8B50;
-  GL_FLOAT_VEC3_ARB = $8B51;
-  GL_FLOAT_VEC4_ARB = $8B52;
-  GL_INT = $1404;
-  GL_INT_VEC2_ARB = $8B53;
-  GL_INT_VEC3_ARB = $8B54;
-  GL_INT_VEC4_ARB = $8B55;
-  GL_BOOL_ARB = $8B56;
-  GL_BOOL_VEC2_ARB = $8B57;
-  GL_BOOL_VEC3_ARB = $8B58;
-  GL_BOOL_VEC4_ARB = $8B59;
-  GL_FLOAT_MAT2_ARB = $8B5A;
-  GL_FLOAT_MAT3_ARB = $8B5B;
-  GL_FLOAT_MAT4_ARB = $8B5C;
-var
-  glDeleteObjectARB: procedure(obj: GLhandleARB); stdcall = nil;
-  glGetHandleARB: function(pname: GLenum): GLhandleARB; stdcall = nil;
-  glDetachObjectARB: procedure(containerObj: GLhandleARB; attachedObj: GLhandleARB); stdcall = nil;
-  glCreateShaderObjectARB: function(shaderType: GLenum): GLhandleARB; stdcall = nil;
-  glShaderSourceARB: procedure(shaderObj: GLhandleARB; count: GLsizei; const _string: PGLvoid; const length: PGLint); stdcall = nil;
-  glCompileShaderARB: procedure(shaderObj: GLhandleARB); stdcall = nil;
-  glCreateProgramObjectARB: function(): GLhandleARB; stdcall = nil;
-  glAttachObjectARB: procedure(containerObj: GLhandleARB; obj: GLhandleARB); stdcall = nil;
-  glLinkProgramARB: procedure(programObj: GLhandleARB); stdcall = nil;
-  glUseProgramObjectARB: procedure(programObj: GLhandleARB); stdcall = nil;
-  glValidateProgramARB: procedure(programObj: GLhandleARB); stdcall = nil;
-  glUniform1fARB: procedure(location: GLint; v0: GLfloat); stdcall = nil;
-  glUniform2fARB: procedure(location: GLint; v0: GLfloat; v1: GLfloat); stdcall = nil;
-  glUniform3fARB: procedure(location: GLint; v0: GLfloat; v1: GLfloat; v2: GLfloat); stdcall = nil;
-  glUniform4fARB: procedure(location: GLint; v0: GLfloat; v1: GLfloat; v2: GLfloat; v3: GLfloat); stdcall = nil;
-  glUniform1iARB: procedure(location: GLint; v0: GLint); stdcall = nil;
-  glUniform2iARB: procedure(location: GLint; v0: GLint; v1: GLint); stdcall = nil;
-  glUniform3iARB: procedure(location: GLint; v0: GLint; v1: GLint; v2: GLint); stdcall = nil;
-  glUniform4iARB: procedure(location: GLint; v0: GLint; v1: GLint; v2: GLint; v3: GLint); stdcall = nil;
-  glUniform1fvARB: procedure(location: GLint; count: GLsizei; value: PGLfloat); stdcall = nil;
-  glUniform2fvARB: procedure(location: GLint; count: GLsizei; value: PGLfloat); stdcall = nil;
-  glUniform3fvARB: procedure(location: GLint; count: GLsizei; value: PGLfloat); stdcall = nil;
-  glUniform4fvARB: procedure(location: GLint; count: GLsizei; value: PGLfloat); stdcall = nil;
-  glUniform1ivARB: procedure(location: GLint; count: GLsizei; value: PGLint); stdcall = nil;
-  glUniform2ivARB: procedure(location: GLint; count: GLsizei; value: PGLint); stdcall = nil;
-  glUniform3ivARB: procedure(location: GLint; count: GLsizei; value: PGLint); stdcall = nil;
-  glUniform4ivARB: procedure(location: GLint; count: GLsizei; value: PGLint); stdcall = nil;
-  glUniformMatrix2fvARB: procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); stdcall = nil;
-  glUniformMatrix3fvARB: procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); stdcall = nil;
-  glUniformMatrix4fvARB: procedure(location: GLint; count: GLsizei; transpose: GLboolean; value: PGLfloat); stdcall = nil;
-  glGetObjectParameterfvARB: procedure(obj: GLhandleARB; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetObjectParameterivARB: procedure(obj: GLhandleARB; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetInfoLogARB: procedure(obj: GLhandleARB; maxLength: GLsizei; length: PGLsizei; infoLog: PGLcharARB); stdcall = nil;
-  glGetAttachedObjectsARB: procedure(containerObj: GLhandleARB; maxCount: GLsizei; count: PGLsizei; obj: PGLhandleARB); stdcall = nil;
-  glGetUniformLocationARB: function(programObj: GLhandleARB; const name: PGLcharARB): GLint; stdcall = nil;
-  glGetActiveUniformARB: procedure(programObj: GLhandleARB; index: GLuint; maxLength: GLsizei; length: PGLsizei; size: PGLint; _type: PGLenum; name: PGLcharARB); stdcall = nil;
-  glGetUniformfvARB: procedure(programObj: GLhandleARB; location: GLint; params: PGLfloat); stdcall = nil;
-  glGetUniformivARB: procedure(programObj: GLhandleARB; location: GLint; params: PGLint); stdcall = nil;
-  glGetShaderSourceARB: procedure(obj: GLhandleARB; maxLength: GLsizei; length: PGLsizei; source: PGLcharARB); stdcall = nil;
-
-function Load_GL_ARB_shader_objects: Boolean;
-
-//***** GL_ARB_vertex_shader *****//
-const
-  GL_VERTEX_SHADER_ARB = $8B31;
-  GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB = $8B4A;
-  GL_MAX_VARYING_FLOATS_ARB = $8B4B;
-  // GL_MAX_VERTEX_ATTRIBS_ARB  { already defined }
-  // GL_MAX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
-  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB = $8B4C;
-  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB = $8B4D;
-  // GL_MAX_TEXTURE_COORDS_ARB  { already defined }
-  // GL_VERTEX_PROGRAM_POINT_SIZE_ARB  { already defined }
-  // GL_VERTEX_PROGRAM_TWO_SIDE_ARB  { already defined }
-  // GL_OBJECT_TYPE_ARB  { already defined }
-  // GL_OBJECT_SUBTYPE_ARB  { already defined }
-  GL_OBJECT_ACTIVE_ATTRIBUTES_ARB = $8B89;
-  GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB = $8B8A;
-  // GL_SHADER_OBJECT_ARB  { already defined }
-  // GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB  { already defined }
-  // GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB  { already defined }
-  // GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB  { already defined }
-  // GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB  { already defined }
-  // GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB  { already defined }
-  // GL_CURRENT_VERTEX_ATTRIB_ARB  { already defined }
-  // GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB  { already defined }
-  // GL_FLOAT  { already defined }
-  // GL_FLOAT_VEC2_ARB  { already defined }
-  // GL_FLOAT_VEC3_ARB  { already defined }
-  // GL_FLOAT_VEC4_ARB  { already defined }
-  // GL_FLOAT_MAT2_ARB  { already defined }
-  // GL_FLOAT_MAT3_ARB  { already defined }
-  // GL_FLOAT_MAT4_ARB  { already defined }
-  // glVertexAttrib1fARB  { already defined }
-  // glVertexAttrib1sARB  { already defined }
-  // glVertexAttrib1dARB  { already defined }
-  // glVertexAttrib2fARB  { already defined }
-  // glVertexAttrib2sARB  { already defined }
-  // glVertexAttrib2dARB  { already defined }
-  // glVertexAttrib3fARB  { already defined }
-  // glVertexAttrib3sARB  { already defined }
-  // glVertexAttrib3dARB  { already defined }
-  // glVertexAttrib4fARB  { already defined }
-  // glVertexAttrib4sARB  { already defined }
-  // glVertexAttrib4dARB  { already defined }
-  // glVertexAttrib4NubARB  { already defined }
-  // glVertexAttrib1fvARB  { already defined }
-  // glVertexAttrib1svARB  { already defined }
-  // glVertexAttrib1dvARB  { already defined }
-  // glVertexAttrib2fvARB  { already defined }
-  // glVertexAttrib2svARB  { already defined }
-  // glVertexAttrib2dvARB  { already defined }
-  // glVertexAttrib3fvARB  { already defined }
-  // glVertexAttrib3svARB  { already defined }
-  // glVertexAttrib3dvARB  { already defined }
-  // glVertexAttrib4fvARB  { already defined }
-  // glVertexAttrib4svARB  { already defined }
-  // glVertexAttrib4dvARB  { already defined }
-  // glVertexAttrib4ivARB  { already defined }
-  // glVertexAttrib4bvARB  { already defined }
-  // glVertexAttrib4ubvARB  { already defined }
-  // glVertexAttrib4usvARB  { already defined }
-  // glVertexAttrib4uivARB  { already defined }
-  // glVertexAttrib4NbvARB  { already defined }
-  // glVertexAttrib4NsvARB  { already defined }
-  // glVertexAttrib4NivARB  { already defined }
-  // glVertexAttrib4NubvARB  { already defined }
-  // glVertexAttrib4NusvARB  { already defined }
-  // glVertexAttrib4NuivARB  { already defined }
-  // glVertexAttribPointerARB  { already defined }
-  // glEnableVertexAttribArrayARB  { already defined }
-  // glDisableVertexAttribArrayARB  { already defined }
-var
-  glBindAttribLocationARB: procedure(programObj: GLhandleARB; index: GLuint; const name: PGLcharARB); stdcall = nil;
-  glGetActiveAttribARB: procedure(programObj: GLhandleARB; index: GLuint; maxLength: GLsizei; length: PGLsizei; size: PGLint; _type: PGLenum; name: PGLcharARB); stdcall = nil;
-  glGetAttribLocationARB: function(programObj: GLhandleARB; const name: PGLcharARB): GLint; stdcall = nil;
-  // glGetVertexAttribdvARB  { already defined }
-  // glGetVertexAttribfvARB  { already defined }
-  // glGetVertexAttribivARB  { already defined }
-  // glGetVertexAttribPointervARB  { already defined }
-
-function Load_GL_ARB_vertex_shader: Boolean;
-
-//***** GL_ARB_fragment_shader *****//
-const
-  GL_FRAGMENT_SHADER_ARB = $8B30;
-  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB = $8B49;
-  // GL_MAX_TEXTURE_COORDS_ARB  { already defined }
-  // GL_MAX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
-  // GL_OBJECT_TYPE_ARB  { already defined }
-  // GL_OBJECT_SUBTYPE_ARB  { already defined }
-  // GL_SHADER_OBJECT_ARB  { already defined }
-
-function Load_GL_ARB_fragment_shader: Boolean;
-
-//***** GL_ARB_shading_language_100 *****//
-const
-  GL_SHADING_LANGUAGE_VERSION_ARB = $8B8C;
-
-function Load_GL_ARB_shading_language_100: Boolean;
-
-//***** GL_ARB_texture_non_power_of_two *****//
-
-function Load_GL_ARB_texture_non_power_of_two: Boolean;
-
-//***** GL_ARB_point_sprite *****//
-const
-  GL_POINT_SPRITE_ARB = $8861;
-  GL_COORD_REPLACE_ARB = $8862;
-
-function Load_GL_ARB_point_sprite: Boolean;
-
-//***** GL_EXT_depth_bounds_test *****//
-const
-  GL_DEPTH_BOUNDS_TEST_EXT = $8890;
-  GL_DEPTH_BOUNDS_EXT = $8891;
-var
-  glDepthBoundsEXT: procedure(zmin: GLclampd; zmax: GLclampd); stdcall = nil;
-
-function Load_GL_EXT_depth_bounds_test: Boolean;
-
-//***** GL_EXT_secondary_color *****//
-const
-  GL_COLOR_SUM_EXT = $8458;
-  GL_CURRENT_SECONDARY_COLOR_EXT = $8459;
-  GL_SECONDARY_COLOR_ARRAY_SIZE_EXT = $845A;
-  GL_SECONDARY_COLOR_ARRAY_TYPE_EXT = $845B;
-  GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT = $845C;
-  GL_SECONDARY_COLOR_ARRAY_POINTER_EXT = $845D;
-  GL_SECONDARY_COLOR_ARRAY_EXT = $845E;
-var
-  glSecondaryColor3bEXT: procedure(r: GLbyte; g: GLbyte; b: GLbyte); stdcall = nil;
-  glSecondaryColor3sEXT: procedure(r: GLshort; g: GLshort; b: GLshort); stdcall = nil;
-  glSecondaryColor3iEXT: procedure(r: GLint; g: GLint; b: GLint); stdcall = nil;
-  glSecondaryColor3fEXT: procedure(r: GLfloat; g: GLfloat; b: GLfloat); stdcall = nil;
-  glSecondaryColor3dEXT: procedure(r: GLdouble; g: GLdouble; b: GLdouble); stdcall = nil;
-  glSecondaryColor3ubEXT: procedure(r: GLubyte; g: GLubyte; b: GLubyte); stdcall = nil;
-  glSecondaryColor3usEXT: procedure(r: GLushort; g: GLushort; b: GLushort); stdcall = nil;
-  glSecondaryColor3uiEXT: procedure(r: GLuint; g: GLuint; b: GLuint); stdcall = nil;
-  glSecondaryColor3bvEXT: procedure(components: PGLbyte); stdcall = nil;
-  glSecondaryColor3svEXT: procedure(components: PGLshort); stdcall = nil;
-  glSecondaryColor3ivEXT: procedure(components: PGLint); stdcall = nil;
-  glSecondaryColor3fvEXT: procedure(components: PGLfloat); stdcall = nil;
-  glSecondaryColor3dvEXT: procedure(components: PGLdouble); stdcall = nil;
-  glSecondaryColor3ubvEXT: procedure(components: PGLubyte); stdcall = nil;
-  glSecondaryColor3usvEXT: procedure(components: PGLushort); stdcall = nil;
-  glSecondaryColor3uivEXT: procedure(components: PGLuint); stdcall = nil;
-  glSecondaryColorPointerEXT: procedure(size: GLint; _type: GLenum; stride: GLsizei; pointer: PGLvoid); stdcall = nil;
-
-function Load_GL_EXT_secondary_color: Boolean;
-
-//***** GL_EXT_texture_mirror_clamp *****//
-const
-  GL_MIRROR_CLAMP_EXT = $8742;
-  GL_MIRROR_CLAMP_TO_EDGE_EXT = $8743;
-  GL_MIRROR_CLAMP_TO_BORDER_EXT = $8912;
-
-function Load_GL_EXT_texture_mirror_clamp: Boolean;
-
-//***** GL_EXT_blend_equation_separate *****//
-const
-  GL_BLEND_EQUATION_RGB_EXT = $8009;
-  GL_BLEND_EQUATION_ALPHA_EXT = $883D;
-var
-  glBlendEquationSeparateEXT: procedure(modeRGB: GLenum; modeAlpha: GLenum); stdcall = nil;
-
-function Load_GL_EXT_blend_equation_separate: Boolean;
-
-//***** GL_MESA_pack_invert *****//
-const
-  GL_PACK_INVERT_MESA = $8758;
-
-function Load_GL_MESA_pack_invert: Boolean;
-
-//***** GL_MESA_ycbcr_texture *****//
-const
-  GL_YCBCR_MESA = $8757;
-  GL_UNSIGNED_SHORT_8_8_MESA = $85BA;
-  GL_UNSIGNED_SHORT_8_8_REV_MESA = $85BB;
-
-function Load_GL_MESA_ycbcr_texture: Boolean;
-
-//***** GL_ARB_fragment_program_shadow *****//
-
-function Load_GL_ARB_fragment_program_shadow: Boolean;
-
-//***** GL_EXT_fog_coord *****//
-const
-  GL_FOG_COORDINATE_SOURCE_EXT = $8450;
-  GL_FOG_COORDINATE_EXT = $8451;
-  GL_FRAGMENT_DEPTH_EXT = $8452;
-  GL_CURRENT_FOG_COORDINATE_EXT = $8453;
-  GL_FOG_COORDINATE_ARRAY_TYPE_EXT = $8454;
-  GL_FOG_COORDINATE_ARRAY_STRIDE_EXT = $8455;
-  GL_FOG_COORDINATE_ARRAY_POINTER_EXT = $8456;
-  GL_FOG_COORDINATE_ARRAY_EXT = $8457;
-var
-  glFogCoordfEXT: procedure(coord: GLfloat); stdcall = nil;
-  glFogCoorddEXT: procedure(coord: GLdouble); stdcall = nil;
-  glFogCoordfvEXT: procedure(coord: PGLfloat); stdcall = nil;
-  glFogCoorddvEXT: procedure(coord: PGLdouble); stdcall = nil;
-  glFogCoordPointerEXT: procedure(_type: GLenum; stride: GLsizei; pointer: PGLvoid); stdcall = nil;
-
-function Load_GL_EXT_fog_coord: Boolean;
-
-//***** GL_NV_fragment_program_option *****//
-
-function Load_GL_NV_fragment_program_option: Boolean;
-
-//***** GL_EXT_pixel_buffer_object *****//
-const
-  GL_PIXEL_PACK_BUFFER_EXT = $88EB;
-  GL_PIXEL_UNPACK_BUFFER_EXT = $88EC;
-  GL_PIXEL_PACK_BUFFER_BINDING_EXT = $88ED;
-  GL_PIXEL_UNPACK_BUFFER_BINDING_EXT = $88EF;
-
-function Load_GL_EXT_pixel_buffer_object: Boolean;
-
-//***** GL_NV_fragment_program2 *****//
-const
-  GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV = $88F4;
-  GL_MAX_PROGRAM_CALL_DEPTH_NV = $88F5;
-  GL_MAX_PROGRAM_IF_DEPTH_NV = $88F6;
-  GL_MAX_PROGRAM_LOOP_DEPTH_NV = $88F7;
-  GL_MAX_PROGRAM_LOOP_COUNT_NV = $88F8;
-
-function Load_GL_NV_fragment_program2: Boolean;
-
-//***** GL_NV_vertex_program2_option *****//
-  // GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV  { already defined }
-  // GL_MAX_PROGRAM_CALL_DEPTH_NV  { already defined }
-
-function Load_GL_NV_vertex_program2_option: Boolean;
-
-//***** GL_NV_vertex_program3 *****//
-  // GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
-
-function Load_GL_NV_vertex_program3: Boolean;
-
-//***** GL_ARB_draw_buffers *****//
-const
-  GL_MAX_DRAW_BUFFERS_ARB = $8824;
-  GL_DRAW_BUFFER0_ARB = $8825;
-  GL_DRAW_BUFFER1_ARB = $8826;
-  GL_DRAW_BUFFER2_ARB = $8827;
-  GL_DRAW_BUFFER3_ARB = $8828;
-  GL_DRAW_BUFFER4_ARB = $8829;
-  GL_DRAW_BUFFER5_ARB = $882A;
-  GL_DRAW_BUFFER6_ARB = $882B;
-  GL_DRAW_BUFFER7_ARB = $882C;
-  GL_DRAW_BUFFER8_ARB = $882D;
-  GL_DRAW_BUFFER9_ARB = $882E;
-  GL_DRAW_BUFFER10_ARB = $882F;
-  GL_DRAW_BUFFER11_ARB = $8830;
-  GL_DRAW_BUFFER12_ARB = $8831;
-  GL_DRAW_BUFFER13_ARB = $8832;
-  GL_DRAW_BUFFER14_ARB = $8833;
-  GL_DRAW_BUFFER15_ARB = $8834;
-var
-  glDrawBuffersARB: procedure(n: GLsizei; const bufs: PGLenum); stdcall = nil;
-
-function Load_GL_ARB_draw_buffers: Boolean;
-
-//***** GL_ARB_texture_rectangle *****//
-const
-  GL_TEXTURE_RECTANGLE_ARB = $84F5;
-  GL_TEXTURE_BINDING_RECTANGLE_ARB = $84F6;
-  GL_PROXY_TEXTURE_RECTANGLE_ARB = $84F7;
-  GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB = $84F8;
-
-function Load_GL_ARB_texture_rectangle: Boolean;
-
-//***** GL_ARB_color_buffer_float *****//
-const
-  GL_RGBA_FLOAT_MODE_ARB = $8820;
-  GL_CLAMP_VERTEX_COLOR_ARB = $891A;
-  GL_CLAMP_FRAGMENT_COLOR_ARB = $891B;
-  GL_CLAMP_READ_COLOR_ARB = $891C;
-  GL_FIXED_ONLY_ARB = $891D;
-  WGL_TYPE_RGBA_FLOAT_ARB = $21A0;
-var
-  glClampColorARB: procedure(target: GLenum; clamp: GLenum); stdcall = nil;
-
-function Load_GL_ARB_color_buffer_float: Boolean;
-
-//***** GL_ARB_half_float_pixel *****//
-const
-  GL_HALF_FLOAT_ARB = $140B;
-
-function Load_GL_ARB_half_float_pixel: Boolean;
-
-//***** GL_ARB_texture_float *****//
-const
-  GL_TEXTURE_RED_TYPE_ARB = $8C10;
-  GL_TEXTURE_GREEN_TYPE_ARB = $8C11;
-  GL_TEXTURE_BLUE_TYPE_ARB = $8C12;
-  GL_TEXTURE_ALPHA_TYPE_ARB = $8C13;
-  GL_TEXTURE_LUMINANCE_TYPE_ARB = $8C14;
-  GL_TEXTURE_INTENSITY_TYPE_ARB = $8C15;
-  GL_TEXTURE_DEPTH_TYPE_ARB = $8C16;
-  GL_UNSIGNED_NORMALIZED_ARB = $8C17;
-  GL_RGBA32F_ARB = $8814;
-  GL_RGB32F_ARB = $8815;
-  GL_ALPHA32F_ARB = $8816;
-  GL_INTENSITY32F_ARB = $8817;
-  GL_LUMINANCE32F_ARB = $8818;
-  GL_LUMINANCE_ALPHA32F_ARB = $8819;
-  GL_RGBA16F_ARB = $881A;
-  GL_RGB16F_ARB = $881B;
-  GL_ALPHA16F_ARB = $881C;
-  GL_INTENSITY16F_ARB = $881D;
-  GL_LUMINANCE16F_ARB = $881E;
-  GL_LUMINANCE_ALPHA16F_ARB = $881F;
-
-function Load_GL_ARB_texture_float: Boolean;
-
-//***** GL_EXT_texture_compression_dxt1 *****//
-  // GL_COMPRESSED_RGB_S3TC_DXT1_EXT  { already defined }
-  // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  { already defined }
-
-function Load_GL_EXT_texture_compression_dxt1: Boolean;
-
-//***** GL_ARB_pixel_buffer_object *****//
-const
-  GL_PIXEL_PACK_BUFFER_ARB = $88EB;
-  GL_PIXEL_UNPACK_BUFFER_ARB = $88EC;
-  GL_PIXEL_PACK_BUFFER_BINDING_ARB = $88ED;
-  GL_PIXEL_UNPACK_BUFFER_BINDING_ARB = $88EF;
-
-function Load_GL_ARB_pixel_buffer_object: Boolean;
-
-//***** GL_EXT_framebuffer_object *****//
-const
-  GL_FRAMEBUFFER_EXT = $8D40;
-  GL_RENDERBUFFER_EXT = $8D41;
-  GL_STENCIL_INDEX_EXT = $8D45;
-  GL_STENCIL_INDEX1_EXT = $8D46;
-  GL_STENCIL_INDEX4_EXT = $8D47;
-  GL_STENCIL_INDEX8_EXT = $8D48;
-  GL_STENCIL_INDEX16_EXT = $8D49;
-  GL_RENDERBUFFER_WIDTH_EXT = $8D42;
-  GL_RENDERBUFFER_HEIGHT_EXT = $8D43;
-  GL_RENDERBUFFER_INTERNAL_FORMAT_EXT = $8D44;
-  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT = $8CD0;
-  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT = $8CD1;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT = $8CD2;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT = $8CD3;
-  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT = $8CD4;
-  GL_COLOR_ATTACHMENT0_EXT = $8CE0;
-  GL_COLOR_ATTACHMENT1_EXT = $8CE1;
-  GL_COLOR_ATTACHMENT2_EXT = $8CE2;
-  GL_COLOR_ATTACHMENT3_EXT = $8CE3;
-  GL_COLOR_ATTACHMENT4_EXT = $8CE4;
-  GL_COLOR_ATTACHMENT5_EXT = $8CE5;
-  GL_COLOR_ATTACHMENT6_EXT = $8CE6;
-  GL_COLOR_ATTACHMENT7_EXT = $8CE7;
-  GL_COLOR_ATTACHMENT8_EXT = $8CE8;
-  GL_COLOR_ATTACHMENT9_EXT = $8CE9;
-  GL_COLOR_ATTACHMENT10_EXT = $8CEA;
-  GL_COLOR_ATTACHMENT11_EXT = $8CEB;
-  GL_COLOR_ATTACHMENT12_EXT = $8CEC;
-  GL_COLOR_ATTACHMENT13_EXT = $8CED;
-  GL_COLOR_ATTACHMENT14_EXT = $8CEE;
-  GL_COLOR_ATTACHMENT15_EXT = $8CEF;
-  GL_DEPTH_ATTACHMENT_EXT = $8D00;
-  GL_STENCIL_ATTACHMENT_EXT = $8D20;
-  GL_FRAMEBUFFER_COMPLETE_EXT = $8CD5;
-  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT = $8CD6;
-  GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT = $8CD7;
-  GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT = $8CD8;
-  GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT = $8CD9;
-  GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT = $8CDA;
-  GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT = $8CDB;
-  GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT = $8CDC;
-  GL_FRAMEBUFFER_UNSUPPORTED_EXT = $8CDD;
-  GL_FRAMEBUFFER_STATUS_ERROR_EXT = $8CDE;
-  GL_FRAMEBUFFER_BINDING_EXT = $8CA6;
-  GL_RENDERBUFFER_BINDING_EXT = $8CA7;
-  GL_MAX_COLOR_ATTACHMENTS_EXT = $8CDF;
-  GL_MAX_RENDERBUFFER_SIZE_EXT = $84E8;
-  GL_INVALID_FRAMEBUFFER_OPERATION_EXT = $0506;
-var
-  glIsRenderbufferEXT: function(renderbuffer: GLuint): GLboolean; stdcall = nil;
-  glBindRenderbufferEXT: procedure(target: GLenum; renderbuffer: GLuint); stdcall = nil;
-  glDeleteRenderbuffersEXT: procedure(n: GLsizei; const renderbuffers: PGLuint); stdcall = nil;
-  glGenRenderbuffersEXT: procedure(n: GLsizei; renderbuffers: PGLuint); stdcall = nil;
-  glRenderbufferStorageEXT: procedure(target: GLenum; internalformat: GLenum; width: GLsizei; height: GLsizei); stdcall = nil;
-  glGetRenderbufferParameterivEXT: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glIsFramebufferEXT: function(framebuffer: GLuint): GLboolean; stdcall = nil;
-  glBindFramebufferEXT: procedure(target: GLenum; framebuffer: GLuint); stdcall = nil;
-  glDeleteFramebuffersEXT: procedure(n: GLsizei; const framebuffers: PGLuint); stdcall = nil;
-  glGenFramebuffersEXT: procedure(n: GLsizei; framebuffers: PGLuint); stdcall = nil;
-  glCheckFramebufferStatusEXT: function(target: GLenum): GLenum; stdcall = nil;
-  glFramebufferTexture1DEXT: procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); stdcall = nil;
-  glFramebufferTexture2DEXT: procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint); stdcall = nil;
-  glFramebufferTexture3DEXT: procedure(target: GLenum; attachment: GLenum; textarget: GLenum; texture: GLuint; level: GLint; zoffset: GLint); stdcall = nil;
-  glFramebufferRenderbufferEXT: procedure(target: GLenum; attachment: GLenum; renderbuffertarget: GLenum; renderbuffer: GLuint); stdcall = nil;
-  glGetFramebufferAttachmentParameterivEXT: procedure(target: GLenum; attachment: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGenerateMipmapEXT: procedure(target: GLenum); stdcall = nil;
-
-function Load_GL_EXT_framebuffer_object: Boolean;
-
-//***** GL_version_1_4 *****//
-const
-  GL_BLEND_DST_RGB = $80C8;
-  GL_BLEND_SRC_RGB = $80C9;
-  GL_BLEND_DST_ALPHA = $80CA;
-  GL_BLEND_SRC_ALPHA = $80CB;
-  GL_POINT_SIZE_MIN = $8126;
-  GL_POINT_SIZE_MAX = $8127;
-  GL_POINT_FADE_THRESHOLD_SIZE = $8128;
-  GL_POINT_DISTANCE_ATTENUATION = $8129;
-  GL_GENERATE_MIPMAP = $8191;
-  GL_GENERATE_MIPMAP_HINT = $8192;
-  GL_DEPTH_COMPONENT16 = $81A5;
-  GL_DEPTH_COMPONENT24 = $81A6;
-  GL_DEPTH_COMPONENT32 = $81A7;
-  GL_MIRRORED_REPEAT = $8370;
-  GL_FOG_COORDINATE_SOURCE = $8450;
-  GL_FOG_COORDINATE = $8451;
-  GL_FRAGMENT_DEPTH = $8452;
-  GL_CURRENT_FOG_COORDINATE = $8453;
-  GL_FOG_COORDINATE_ARRAY_TYPE = $8454;
-  GL_FOG_COORDINATE_ARRAY_STRIDE = $8455;
-  GL_FOG_COORDINATE_ARRAY_POINTER = $8456;
-  GL_FOG_COORDINATE_ARRAY = $8457;
-  GL_COLOR_SUM = $8458;
-  GL_CURRENT_SECONDARY_COLOR = $8459;
-  GL_SECONDARY_COLOR_ARRAY_SIZE = $845A;
-  GL_SECONDARY_COLOR_ARRAY_TYPE = $845B;
-  GL_SECONDARY_COLOR_ARRAY_STRIDE = $845C;
-  GL_SECONDARY_COLOR_ARRAY_POINTER = $845D;
-  GL_SECONDARY_COLOR_ARRAY = $845E;
-  GL_MAX_TEXTURE_LOD_BIAS = $84FD;
-  GL_TEXTURE_FILTER_CONTROL = $8500;
-  GL_TEXTURE_LOD_BIAS = $8501;
-  GL_INCR_WRAP = $8507;
-  GL_DECR_WRAP = $8508;
-  GL_TEXTURE_DEPTH_SIZE = $884A;
-  GL_DEPTH_TEXTURE_MODE = $884B;
-  GL_TEXTURE_COMPARE_MODE = $884C;
-  GL_TEXTURE_COMPARE_FUNC = $884D;
-  GL_COMPARE_R_TO_TEXTURE = $884E;
-var
-  glBlendFuncSeparate: procedure(sfactorRGB: GLenum; dfactorRGB: GLenum; sfactorAlpha: GLenum; dfactorAlpha: GLenum); stdcall = nil;
-  glFogCoordf: procedure(coord: GLfloat); stdcall = nil;
-  glFogCoordfv: procedure(const coord: PGLfloat); stdcall = nil;
-  glFogCoordd: procedure(coord: GLdouble); stdcall = nil;
-  glFogCoorddv: procedure(const coord: PGLdouble); stdcall = nil;
-  glFogCoordPointer: procedure(_type: GLenum; stride: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glMultiDrawArrays: procedure(mode: GLenum; first: PGLint; count: PGLsizei; primcount: GLsizei); stdcall = nil;
-  glMultiDrawElements: procedure(mode: GLenum; const count: PGLsizei; _type: GLenum; const indices: PGLvoid; primcount: GLsizei); stdcall = nil;
-  glPointParameterf: procedure(pname: GLenum; param: GLfloat); stdcall = nil;
-  glPointParameterfv: procedure(pname: GLenum; const params: PGLfloat); stdcall = nil;
-  glPointParameteri: procedure(pname: GLenum; param: GLint); stdcall = nil;
-  glPointParameteriv: procedure(pname: GLenum; const params: PGLint); stdcall = nil;
-  glSecondaryColor3b: procedure(red: GLbyte; green: GLbyte; blue: GLbyte); stdcall = nil;
-  glSecondaryColor3bv: procedure(const v: PGLbyte); stdcall = nil;
-  glSecondaryColor3d: procedure(red: GLdouble; green: GLdouble; blue: GLdouble); stdcall = nil;
-  glSecondaryColor3dv: procedure(const v: PGLdouble); stdcall = nil;
-  glSecondaryColor3f: procedure(red: GLfloat; green: GLfloat; blue: GLfloat); stdcall = nil;
-  glSecondaryColor3fv: procedure(const v: PGLfloat); stdcall = nil;
-  glSecondaryColor3i: procedure(red: GLint; green: GLint; blue: GLint); stdcall = nil;
-  glSecondaryColor3iv: procedure(const v: PGLint); stdcall = nil;
-  glSecondaryColor3s: procedure(red: GLshort; green: GLshort; blue: GLshort); stdcall = nil;
-  glSecondaryColor3sv: procedure(const v: PGLshort); stdcall = nil;
-  glSecondaryColor3ub: procedure(red: GLubyte; green: GLubyte; blue: GLubyte); stdcall = nil;
-  glSecondaryColor3ubv: procedure(const v: PGLubyte); stdcall = nil;
-  glSecondaryColor3ui: procedure(red: GLuint; green: GLuint; blue: GLuint); stdcall = nil;
-  glSecondaryColor3uiv: procedure(const v: PGLuint); stdcall = nil;
-  glSecondaryColor3us: procedure(red: GLushort; green: GLushort; blue: GLushort); stdcall = nil;
-  glSecondaryColor3usv: procedure(const v: PGLushort); stdcall = nil;
-  glSecondaryColorPointer: procedure(size: GLint; _type: GLenum; stride: GLsizei; const pointer: PGLvoid); stdcall = nil;
-  glWindowPos2d: procedure(x: GLdouble; y: GLdouble); stdcall = nil;
-  glWindowPos2dv: procedure(const v: PGLdouble); stdcall = nil;
-  glWindowPos2f: procedure(x: GLfloat; y: GLfloat); stdcall = nil;
-  glWindowPos2fv: procedure(const v: PGLfloat); stdcall = nil;
-  glWindowPos2i: procedure(x: GLint; y: GLint); stdcall = nil;
-  glWindowPos2iv: procedure(const v: PGLint); stdcall = nil;
-  glWindowPos2s: procedure(x: GLshort; y: GLshort); stdcall = nil;
-  glWindowPos2sv: procedure(const v: PGLshort); stdcall = nil;
-  glWindowPos3d: procedure(x: GLdouble; y: GLdouble; z: GLdouble); stdcall = nil;
-  glWindowPos3dv: procedure(const v: PGLdouble); stdcall = nil;
-  glWindowPos3f: procedure(x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glWindowPos3fv: procedure(const v: PGLfloat); stdcall = nil;
-  glWindowPos3i: procedure(x: GLint; y: GLint; z: GLint); stdcall = nil;
-  glWindowPos3iv: procedure(const v: PGLint); stdcall = nil;
-  glWindowPos3s: procedure(x: GLshort; y: GLshort; z: GLshort); stdcall = nil;
-  glWindowPos3sv: procedure(const v: PGLshort); stdcall = nil;
-
-function Load_GL_version_1_4: Boolean;
-
-//***** GL_version_1_5 *****//
-const
-  GL_BUFFER_SIZE = $8764;
-  GL_BUFFER_USAGE = $8765;
-  GL_QUERY_COUNTER_BITS = $8864;
-  GL_CURRENT_QUERY = $8865;
-  GL_QUERY_RESULT = $8866;
-  GL_QUERY_RESULT_AVAILABLE = $8867;
-  GL_ARRAY_BUFFER = $8892;
-  GL_ELEMENT_ARRAY_BUFFER = $8893;
-  GL_ARRAY_BUFFER_BINDING = $8894;
-  GL_ELEMENT_ARRAY_BUFFER_BINDING = $8895;
-  GL_VERTEX_ARRAY_BUFFER_BINDING = $8896;
-  GL_NORMAL_ARRAY_BUFFER_BINDING = $8897;
-  GL_COLOR_ARRAY_BUFFER_BINDING = $8898;
-  GL_INDEX_ARRAY_BUFFER_BINDING = $8899;
-  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = $889A;
-  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING = $889B;
-  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING = $889C;
-  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING = $889D;
-  GL_WEIGHT_ARRAY_BUFFER_BINDING = $889E;
-  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = $889F;
-  GL_READ_ONLY = $88B8;
-  GL_WRITE_ONLY = $88B9;
-  GL_READ_WRITE = $88BA;
-  GL_BUFFER_ACCESS = $88BB;
-  GL_BUFFER_MAPPED = $88BC;
-  GL_BUFFER_MAP_POINTER = $88BD;
-  GL_STREAM_DRAW = $88E0;
-  GL_STREAM_READ = $88E1;
-  GL_STREAM_COPY = $88E2;
-  GL_STATIC_DRAW = $88E4;
-  GL_STATIC_READ = $88E5;
-  GL_STATIC_COPY = $88E6;
-  GL_DYNAMIC_DRAW = $88E8;
-  GL_DYNAMIC_READ = $88E9;
-  GL_DYNAMIC_COPY = $88EA;
-  GL_SAMPLES_PASSED = $8914;
-  GL_FOG_COORD_SRC = $8450;
-  GL_FOG_COORD = $8451;
-  GL_CURRENT_FOG_COORD = $8453;
-  GL_FOG_COORD_ARRAY_TYPE = $8454;
-  GL_FOG_COORD_ARRAY_STRIDE = $8455;
-  GL_FOG_COORD_ARRAY_POINTER = $8456;
-  GL_FOG_COORD_ARRAY = $8457;
-  GL_FOG_COORD_ARRAY_BUFFER_BINDING = $889D;
-  GL_SRC0_RGB = $8580;
-  GL_SRC1_RGB = $8581;
-  GL_SRC2_RGB = $8582;
-  GL_SRC0_ALPHA = $8588;
-  GL_SRC1_ALPHA = $8589;
-  GL_SRC2_ALPHA = $858A;
-var
-  glGenQueries: procedure(n: GLsizei; ids: PGLuint); stdcall = nil;
-  glDeleteQueries: procedure(n: GLsizei; const ids: PGLuint); stdcall = nil;
-  glIsQuery: function(id: GLuint): GLboolean; stdcall = nil;
-  glBeginQuery: procedure(target: GLenum; id: GLuint); stdcall = nil;
-  glEndQuery: procedure(target: GLenum); stdcall = nil;
-  glGetQueryiv: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetQueryObjectiv: procedure(id: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetQueryObjectuiv: procedure(id: GLuint; pname: GLenum; params: PGLuint); stdcall = nil;
-  glBindBuffer: procedure(target: GLenum; buffer: GLuint); stdcall = nil;
-  glDeleteBuffers: procedure(n: GLsizei; const buffers: PGLuint); stdcall = nil;
-  glGenBuffers: procedure(n: GLsizei; buffers: PGLuint); stdcall = nil;
-  glIsBuffer: function(buffer: GLuint): GLboolean; stdcall = nil;
-  glBufferData: procedure(target: GLenum; size: GLsizeiptr; const data: PGLvoid; usage: GLenum); stdcall = nil;
-  glBufferSubData: procedure(target: GLenum; offset: GLintptr; size: GLsizeiptr; const data: PGLvoid); stdcall = nil;
-  glGetBufferSubData: procedure(target: GLenum; offset: GLintptr; size: GLsizeiptr; data: PGLvoid); stdcall = nil;
-  glMapBuffer: function(target: GLenum; access: GLenum): PGLvoid; stdcall = nil;
-  glUnmapBuffer: function(target: GLenum): GLboolean; stdcall = nil;
-  glGetBufferParameteriv: procedure(target: GLenum; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetBufferPointerv: procedure(target: GLenum; pname: GLenum; params: PGLvoid); stdcall = nil;
-
-function Load_GL_version_1_5: Boolean;
-
-//***** GL_version_2_0 *****//
-const
-  GL_BLEND_EQUATION_RGB = $8009;
-  GL_VERTEX_ATTRIB_ARRAY_ENABLED = $8622;
-  GL_VERTEX_ATTRIB_ARRAY_SIZE = $8623;
-  GL_VERTEX_ATTRIB_ARRAY_STRIDE = $8624;
-  GL_VERTEX_ATTRIB_ARRAY_TYPE = $8625;
-  GL_CURRENT_VERTEX_ATTRIB = $8626;
-  GL_VERTEX_PROGRAM_POINT_SIZE = $8642;
-  GL_VERTEX_PROGRAM_TWO_SIDE = $8643;
-  GL_VERTEX_ATTRIB_ARRAY_POINTER = $8645;
-  GL_STENCIL_BACK_FUNC = $8800;
-  GL_STENCIL_BACK_FAIL = $8801;
-  GL_STENCIL_BACK_PASS_DEPTH_FAIL = $8802;
-  GL_STENCIL_BACK_PASS_DEPTH_PASS = $8803;
-  GL_MAX_DRAW_BUFFERS = $8824;
-  GL_DRAW_BUFFER0 = $8825;
-  GL_DRAW_BUFFER1 = $8826;
-  GL_DRAW_BUFFER2 = $8827;
-  GL_DRAW_BUFFER3 = $8828;
-  GL_DRAW_BUFFER4 = $8829;
-  GL_DRAW_BUFFER5 = $882A;
-  GL_DRAW_BUFFER6 = $882B;
-  GL_DRAW_BUFFER7 = $882C;
-  GL_DRAW_BUFFER8 = $882D;
-  GL_DRAW_BUFFER9 = $882E;
-  GL_DRAW_BUFFER10 = $882F;
-  GL_DRAW_BUFFER11 = $8830;
-  GL_DRAW_BUFFER12 = $8831;
-  GL_DRAW_BUFFER13 = $8832;
-  GL_DRAW_BUFFER14 = $8833;
-  GL_DRAW_BUFFER15 = $8834;
-  GL_BLEND_EQUATION_ALPHA = $883D;
-  GL_POINT_SPRITE = $8861;
-  GL_COORD_REPLACE = $8862;
-  GL_MAX_VERTEX_ATTRIBS = $8869;
-  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED = $886A;
-  GL_MAX_TEXTURE_COORDS = $8871;
-  GL_MAX_TEXTURE_IMAGE_UNITS = $8872;
-  GL_FRAGMENT_SHADER = $8B30;
-  GL_VERTEX_SHADER = $8B31;
-  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = $8B49;
-  GL_MAX_VERTEX_UNIFORM_COMPONENTS = $8B4A;
-  GL_MAX_VARYING_FLOATS = $8B4B;
-  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = $8B4C;
-  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = $8B4D;
-  GL_SHADER_TYPE = $8B4F;
-  GL_FLOAT_VEC2 = $8B50;
-  GL_FLOAT_VEC3 = $8B51;
-  GL_FLOAT_VEC4 = $8B52;
-  GL_INT_VEC2 = $8B53;
-  GL_INT_VEC3 = $8B54;
-  GL_INT_VEC4 = $8B55;
-  GL_BOOL = $8B56;
-  GL_BOOL_VEC2 = $8B57;
-  GL_BOOL_VEC3 = $8B58;
-  GL_BOOL_VEC4 = $8B59;
-  GL_FLOAT_MAT2 = $8B5A;
-  GL_FLOAT_MAT3 = $8B5B;
-  GL_FLOAT_MAT4 = $8B5C;
-  GL_SAMPLER_1D = $8B5D;
-  GL_SAMPLER_2D = $8B5E;
-  GL_SAMPLER_3D = $8B5F;
-  GL_SAMPLER_CUBE = $8B60;
-  GL_SAMPLER_1D_SHADOW = $8B61;
-  GL_SAMPLER_2D_SHADOW = $8B62;
-  GL_DELETE_STATUS = $8B80;
-  GL_COMPILE_STATUS = $8B81;
-  GL_LINK_STATUS = $8B82;
-  GL_VALIDATE_STATUS = $8B83;
-  GL_INFO_LOG_LENGTH = $8B84;
-  GL_ATTACHED_SHADERS = $8B85;
-  GL_ACTIVE_UNIFORMS = $8B86;
-  GL_ACTIVE_UNIFORM_MAX_LENGTH = $8B87;
-  GL_SHADER_SOURCE_LENGTH = $8B88;
-  GL_ACTIVE_ATTRIBUTES = $8B89;
-  GL_ACTIVE_ATTRIBUTE_MAX_LENGTH = $8B8A;
-  GL_FRAGMENT_SHADER_DERIVATIVE_HINT = $8B8B;
-  GL_SHADING_LANGUAGE_VERSION = $8B8C;
-  GL_CURRENT_PROGRAM = $8B8D;
-  GL_POINT_SPRITE_COORD_ORIGIN = $8CA0;
-  GL_LOWER_LEFT = $8CA1;
-  GL_UPPER_LEFT = $8CA2;
-  GL_STENCIL_BACK_REF = $8CA3;
-  GL_STENCIL_BACK_VALUE_MASK = $8CA4;
-  GL_STENCIL_BACK_WRITEMASK = $8CA5;
-var
-  glBlendEquationSeparate: procedure(modeRGB: GLenum; modeAlpha: GLenum); stdcall = nil;
-  glDrawBuffers: procedure(n: GLsizei; const bufs: PGLenum); stdcall = nil;
-  glStencilOpSeparate: procedure(face: GLenum; sfail: GLenum; dpfail: GLenum; dppass: GLenum); stdcall = nil;
-  glStencilFuncSeparate: procedure(frontfunc: GLenum; backfunc: GLenum; ref: GLint; mask: GLuint); stdcall = nil;
-  glStencilMaskSeparate: procedure(face: GLenum; mask: GLuint); stdcall = nil;
-  glAttachShader: procedure(_program: GLuint; shader: GLuint); stdcall = nil;
-  glBindAttribLocation: procedure(_program: GLuint; index: GLuint; const name: PGLchar); stdcall = nil;
-  glCompileShader: procedure(shader: GLuint); stdcall = nil;
-  glCreateProgram: function(): GLuint; stdcall = nil;
-  glCreateShader: function(_type: GLenum): GLuint; stdcall = nil;
-  glDeleteProgram: procedure(_program: GLuint); stdcall = nil;
-  glDeleteShader: procedure(shader: GLuint); stdcall = nil;
-  glDetachShader: procedure(_program: GLuint; shader: GLuint); stdcall = nil;
-  glDisableVertexAttribArray: procedure(index: GLuint); stdcall = nil;
-  glEnableVertexAttribArray: procedure(index: GLuint); stdcall = nil;
-  glGetActiveAttrib: procedure(_program: GLuint; index: GLuint; bufSize: GLsizei; length: PGLsizei; size: PGLint; _type: PGLenum; name: PGLchar); stdcall = nil;
-  glGetActiveUniform: procedure(_program: GLuint; index: GLuint; bufSize: GLsizei; length: PGLsizei; size: PGLint; _type: PGLenum; name: PGLchar); stdcall = nil;
-  glGetAttachedShaders: procedure(_program: GLuint; maxCount: GLsizei; count: PGLsizei; obj: PGLuint); stdcall = nil;
-  glGetAttribLocation: function(_program: GLuint; const name: PGLchar): GLint; stdcall = nil;
-  glGetProgramiv: procedure(_program: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetProgramInfoLog: procedure(_program: GLuint; bufSize: GLsizei; length: PGLsizei; infoLog: PGLchar); stdcall = nil;
-  glGetShaderiv: procedure(shader: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetShaderInfoLog: procedure(shader: GLuint; bufSize: GLsizei; length: PGLsizei; infoLog: PGLchar); stdcall = nil;
-  glGetShaderSource: procedure(shader: GLuint; bufSize: GLsizei; length: PGLsizei; source: PGLchar); stdcall = nil;
-  glGetUniformLocation: function(_program: GLuint; const name: PGLchar): GLint; stdcall = nil;
-  glGetUniformfv: procedure(_program: GLuint; location: GLint; params: PGLfloat); stdcall = nil;
-  glGetUniformiv: procedure(_program: GLuint; location: GLint; params: PGLint); stdcall = nil;
-  glGetVertexAttribdv: procedure(index: GLuint; pname: GLenum; params: PGLdouble); stdcall = nil;
-  glGetVertexAttribfv: procedure(index: GLuint; pname: GLenum; params: PGLfloat); stdcall = nil;
-  glGetVertexAttribiv: procedure(index: GLuint; pname: GLenum; params: PGLint); stdcall = nil;
-  glGetVertexAttribPointerv: procedure(index: GLuint; pname: GLenum; pointer: PGLvoid); stdcall = nil;
-  glIsProgram: function(_program: GLuint): GLboolean; stdcall = nil;
-  glIsShader: function(shader: GLuint): GLboolean; stdcall = nil;
-  glLinkProgram: procedure(_program: GLuint); stdcall = nil;
-  glShaderSource: procedure(shader: GLuint; count: GLsizei; const _string: PGLchar; const length: PGLint); stdcall = nil;
-  glUseProgram: procedure(_program: GLuint); stdcall = nil;
-  glUniform1f: procedure(location: GLint; v0: GLfloat); stdcall = nil;
-  glUniform2f: procedure(location: GLint; v0: GLfloat; v1: GLfloat); stdcall = nil;
-  glUniform3f: procedure(location: GLint; v0: GLfloat; v1: GLfloat; v2: GLfloat); stdcall = nil;
-  glUniform4f: procedure(location: GLint; v0: GLfloat; v1: GLfloat; v2: GLfloat; v3: GLfloat); stdcall = nil;
-  glUniform1i: procedure(location: GLint; v0: GLint); stdcall = nil;
-  glUniform2i: procedure(location: GLint; v0: GLint; v1: GLint); stdcall = nil;
-  glUniform3i: procedure(location: GLint; v0: GLint; v1: GLint; v2: GLint); stdcall = nil;
-  glUniform4i: procedure(location: GLint; v0: GLint; v1: GLint; v2: GLint; v3: GLint); stdcall = nil;
-  glUniform1fv: procedure(location: GLint; count: GLsizei; const value: PGLfloat); stdcall = nil;
-  glUniform2fv: procedure(location: GLint; count: GLsizei; const value: PGLfloat); stdcall = nil;
-  glUniform3fv: procedure(location: GLint; count: GLsizei; const value: PGLfloat); stdcall = nil;
-  glUniform4fv: procedure(location: GLint; count: GLsizei; const value: PGLfloat); stdcall = nil;
-  glUniform1iv: procedure(location: GLint; count: GLsizei; const value: PGLint); stdcall = nil;
-  glUniform2iv: procedure(location: GLint; count: GLsizei; const value: PGLint); stdcall = nil;
-  glUniform3iv: procedure(location: GLint; count: GLsizei; const value: PGLint); stdcall = nil;
-  glUniform4iv: procedure(location: GLint; count: GLsizei; const value: PGLint); stdcall = nil;
-  glUniformMatrix2fv: procedure(location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); stdcall = nil;
-  glUniformMatrix3fv: procedure(location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); stdcall = nil;
-  glUniformMatrix4fv: procedure(location: GLint; count: GLsizei; transpose: GLboolean; const value: PGLfloat); stdcall = nil;
-  glValidateProgram: procedure(_program: GLuint); stdcall = nil;
-  glVertexAttrib1d: procedure(index: GLuint; x: GLdouble); stdcall = nil;
-  glVertexAttrib1dv: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib1f: procedure(index: GLuint; x: GLfloat); stdcall = nil;
-  glVertexAttrib1fv: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib1s: procedure(index: GLuint; x: GLshort); stdcall = nil;
-  glVertexAttrib1sv: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib2d: procedure(index: GLuint; x: GLdouble; y: GLdouble); stdcall = nil;
-  glVertexAttrib2dv: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib2f: procedure(index: GLuint; x: GLfloat; y: GLfloat); stdcall = nil;
-  glVertexAttrib2fv: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib2s: procedure(index: GLuint; x: GLshort; y: GLshort); stdcall = nil;
-  glVertexAttrib2sv: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib3d: procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble); stdcall = nil;
-  glVertexAttrib3dv: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib3f: procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat); stdcall = nil;
-  glVertexAttrib3fv: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib3s: procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort); stdcall = nil;
-  glVertexAttrib3sv: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib4Nbv: procedure(index: GLuint; const v: PGLbyte); stdcall = nil;
-  glVertexAttrib4Niv: procedure(index: GLuint; const v: PGLint); stdcall = nil;
-  glVertexAttrib4Nsv: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib4Nub: procedure(index: GLuint; x: GLubyte; y: GLubyte; z: GLubyte; w: GLubyte); stdcall = nil;
-  glVertexAttrib4Nubv: procedure(index: GLuint; const v: PGLubyte); stdcall = nil;
-  glVertexAttrib4Nuiv: procedure(index: GLuint; const v: PGLuint); stdcall = nil;
-  glVertexAttrib4Nusv: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttrib4bv: procedure(index: GLuint; const v: PGLbyte); stdcall = nil;
-  glVertexAttrib4d: procedure(index: GLuint; x: GLdouble; y: GLdouble; z: GLdouble; w: GLdouble); stdcall = nil;
-  glVertexAttrib4dv: procedure(index: GLuint; const v: PGLdouble); stdcall = nil;
-  glVertexAttrib4f: procedure(index: GLuint; x: GLfloat; y: GLfloat; z: GLfloat; w: GLfloat); stdcall = nil;
-  glVertexAttrib4fv: procedure(index: GLuint; const v: PGLfloat); stdcall = nil;
-  glVertexAttrib4iv: procedure(index: GLuint; const v: PGLint); stdcall = nil;
-  glVertexAttrib4s: procedure(index: GLuint; x: GLshort; y: GLshort; z: GLshort; w: GLshort); stdcall = nil;
-  glVertexAttrib4sv: procedure(index: GLuint; const v: PGLshort); stdcall = nil;
-  glVertexAttrib4ubv: procedure(index: GLuint; const v: PGLubyte); stdcall = nil;
-  glVertexAttrib4uiv: procedure(index: GLuint; const v: PGLuint); stdcall = nil;
-  glVertexAttrib4usv: procedure(index: GLuint; const v: PGLushort); stdcall = nil;
-  glVertexAttribPointer: procedure(index: GLuint; size: GLint; _type: GLenum; normalized: GLboolean; stride: GLsizei; const pointer: PGLvoid); stdcall = nil;
-
-function Load_GL_version_2_0: Boolean;
-
-implementation
-
-function glext_ExtensionSupported(const extension: String; const searchIn: String): Boolean;
-var
-  extensions: PChar;
-  start: PChar;
-  where, terminator: PChar;
-begin
-
-  if (Pos(' ', extension) <> 0) or (extension = '') then
-  begin
-    Result := FALSE;
-    Exit;
-  end;
-
-  if searchIn = '' then extensions := PChar(glGetString(GL_EXTENSIONS))
-  else extensions := PChar(searchIn);
-  start := extensions;
-  while TRUE do
-  begin
-    where := StrPos(start, PChar(extension));
-    if where = nil then Break;
-    terminator := Pointer(Integer(where) + Length(extension));
-    if (where = start) or (PChar(Integer(where) - 1)^ = ' ') then
-    begin
-      if (terminator^ = ' ') or (terminator^ = #0) then
-      begin
-       Result := TRUE;
-       Exit;
-      end;
-    end;
-    start := terminator;
-  end;
-  Result := FALSE;
-
-end;
-
-function Load_GL_version_1_2: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-    glDrawRangeElements := wglGetProcAddress('glDrawRangeElements');
-    if not Assigned(glDrawRangeElements) then Exit;
-    glTexImage3D := wglGetProcAddress('glTexImage3D');
-    if not Assigned(glTexImage3D) then Exit;
-    glTexSubImage3D := wglGetProcAddress('glTexSubImage3D');
-    if not Assigned(glTexSubImage3D) then Exit;
-    glCopyTexSubImage3D := wglGetProcAddress('glCopyTexSubImage3D');
-    if not Assigned(glCopyTexSubImage3D) then Exit;
-    Result := TRUE;
-
-end;
-
-function Load_GL_ARB_imaging: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_imaging', extstring) then
-  begin
-    glColorTable := wglGetProcAddress('glColorTable');
-    if not Assigned(glColorTable) then Exit;
-    glColorTableParameterfv := wglGetProcAddress('glColorTableParameterfv');
-    if not Assigned(glColorTableParameterfv) then Exit;
-    glColorTableParameteriv := wglGetProcAddress('glColorTableParameteriv');
-    if not Assigned(glColorTableParameteriv) then Exit;
-    glCopyColorTable := wglGetProcAddress('glCopyColorTable');
-    if not Assigned(glCopyColorTable) then Exit;
-    glGetColorTable := wglGetProcAddress('glGetColorTable');
-    if not Assigned(glGetColorTable) then Exit;
-    glGetColorTableParameterfv := wglGetProcAddress('glGetColorTableParameterfv');
-    if not Assigned(glGetColorTableParameterfv) then Exit;
-    glGetColorTableParameteriv := wglGetProcAddress('glGetColorTableParameteriv');
-    if not Assigned(glGetColorTableParameteriv) then Exit;
-    glColorSubTable := wglGetProcAddress('glColorSubTable');
-    if not Assigned(glColorSubTable) then Exit;
-    glCopyColorSubTable := wglGetProcAddress('glCopyColorSubTable');
-    if not Assigned(glCopyColorSubTable) then Exit;
-    glConvolutionFilter1D := wglGetProcAddress('glConvolutionFilter1D');
-    if not Assigned(glConvolutionFilter1D) then Exit;
-    glConvolutionFilter2D := wglGetProcAddress('glConvolutionFilter2D');
-    if not Assigned(glConvolutionFilter2D) then Exit;
-    glConvolutionParameterf := wglGetProcAddress('glConvolutionParameterf');
-    if not Assigned(glConvolutionParameterf) then Exit;
-    glConvolutionParameterfv := wglGetProcAddress('glConvolutionParameterfv');
-    if not Assigned(glConvolutionParameterfv) then Exit;
-    glConvolutionParameteri := wglGetProcAddress('glConvolutionParameteri');
-    if not Assigned(glConvolutionParameteri) then Exit;
-    glConvolutionParameteriv := wglGetProcAddress('glConvolutionParameteriv');
-    if not Assigned(glConvolutionParameteriv) then Exit;
-    glCopyConvolutionFilter1D := wglGetProcAddress('glCopyConvolutionFilter1D');
-    if not Assigned(glCopyConvolutionFilter1D) then Exit;
-    glCopyConvolutionFilter2D := wglGetProcAddress('glCopyConvolutionFilter2D');
-    if not Assigned(glCopyConvolutionFilter2D) then Exit;
-    glGetConvolutionFilter := wglGetProcAddress('glGetConvolutionFilter');
-    if not Assigned(glGetConvolutionFilter) then Exit;
-    glGetConvolutionParameterfv := wglGetProcAddress('glGetConvolutionParameterfv');
-    if not Assigned(glGetConvolutionParameterfv) then Exit;
-    glGetConvolutionParameteriv := wglGetProcAddress('glGetConvolutionParameteriv');
-    if not Assigned(glGetConvolutionParameteriv) then Exit;
-    glGetSeparableFilter := wglGetProcAddress('glGetSeparableFilter');
-    if not Assigned(glGetSeparableFilter) then Exit;
-    glSeparableFilter2D := wglGetProcAddress('glSeparableFilter2D');
-    if not Assigned(glSeparableFilter2D) then Exit;
-    glGetHistogram := wglGetProcAddress('glGetHistogram');
-    if not Assigned(glGetHistogram) then Exit;
-    glGetHistogramParameterfv := wglGetProcAddress('glGetHistogramParameterfv');
-    if not Assigned(glGetHistogramParameterfv) then Exit;
-    glGetHistogramParameteriv := wglGetProcAddress('glGetHistogramParameteriv');
-    if not Assigned(glGetHistogramParameteriv) then Exit;
-    glGetMinmax := wglGetProcAddress('glGetMinmax');
-    if not Assigned(glGetMinmax) then Exit;
-    glGetMinmaxParameterfv := wglGetProcAddress('glGetMinmaxParameterfv');
-    if not Assigned(glGetMinmaxParameterfv) then Exit;
-    glGetMinmaxParameteriv := wglGetProcAddress('glGetMinmaxParameteriv');
-    if not Assigned(glGetMinmaxParameteriv) then Exit;
-    glHistogram := wglGetProcAddress('glHistogram');
-    if not Assigned(glHistogram) then Exit;
-    glMinmax := wglGetProcAddress('glMinmax');
-    if not Assigned(glMinmax) then Exit;
-    glResetHistogram := wglGetProcAddress('glResetHistogram');
-    if not Assigned(glResetHistogram) then Exit;
-    glResetMinmax := wglGetProcAddress('glResetMinmax');
-    if not Assigned(glResetMinmax) then Exit;
-    glBlendEquation := wglGetProcAddress('glBlendEquation');
-    if not Assigned(glBlendEquation) then Exit;
-    glBlendColor := wglGetProcAddress('glBlendColor');
-    if not Assigned(glBlendColor) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_version_1_3: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-    glActiveTexture := wglGetProcAddress('glActiveTexture');
-    if not Assigned(glActiveTexture) then Exit;
-    glClientActiveTexture := wglGetProcAddress('glClientActiveTexture');
-    if not Assigned(glClientActiveTexture) then Exit;
-    glMultiTexCoord1d := wglGetProcAddress('glMultiTexCoord1d');
-    if not Assigned(glMultiTexCoord1d) then Exit;
-    glMultiTexCoord1dv := wglGetProcAddress('glMultiTexCoord1dv');
-    if not Assigned(glMultiTexCoord1dv) then Exit;
-    glMultiTexCoord1f := wglGetProcAddress('glMultiTexCoord1f');
-    if not Assigned(glMultiTexCoord1f) then Exit;
-    glMultiTexCoord1fv := wglGetProcAddress('glMultiTexCoord1fv');
-    if not Assigned(glMultiTexCoord1fv) then Exit;
-    glMultiTexCoord1i := wglGetProcAddress('glMultiTexCoord1i');
-    if not Assigned(glMultiTexCoord1i) then Exit;
-    glMultiTexCoord1iv := wglGetProcAddress('glMultiTexCoord1iv');
-    if not Assigned(glMultiTexCoord1iv) then Exit;
-    glMultiTexCoord1s := wglGetProcAddress('glMultiTexCoord1s');
-    if not Assigned(glMultiTexCoord1s) then Exit;
-    glMultiTexCoord1sv := wglGetProcAddress('glMultiTexCoord1sv');
-    if not Assigned(glMultiTexCoord1sv) then Exit;
-    glMultiTexCoord2d := wglGetProcAddress('glMultiTexCoord2d');
-    if not Assigned(glMultiTexCoord2d) then Exit;
-    glMultiTexCoord2dv := wglGetProcAddress('glMultiTexCoord2dv');
-    if not Assigned(glMultiTexCoord2dv) then Exit;
-    glMultiTexCoord2f := wglGetProcAddress('glMultiTexCoord2f');
-    if not Assigned(glMultiTexCoord2f) then Exit;
-    glMultiTexCoord2fv := wglGetProcAddress('glMultiTexCoord2fv');
-    if not Assigned(glMultiTexCoord2fv) then Exit;
-    glMultiTexCoord2i := wglGetProcAddress('glMultiTexCoord2i');
-    if not Assigned(glMultiTexCoord2i) then Exit;
-    glMultiTexCoord2iv := wglGetProcAddress('glMultiTexCoord2iv');
-    if not Assigned(glMultiTexCoord2iv) then Exit;
-    glMultiTexCoord2s := wglGetProcAddress('glMultiTexCoord2s');
-    if not Assigned(glMultiTexCoord2s) then Exit;
-    glMultiTexCoord2sv := wglGetProcAddress('glMultiTexCoord2sv');
-    if not Assigned(glMultiTexCoord2sv) then Exit;
-    glMultiTexCoord3d := wglGetProcAddress('glMultiTexCoord3d');
-    if not Assigned(glMultiTexCoord3d) then Exit;
-    glMultiTexCoord3dv := wglGetProcAddress('glMultiTexCoord3dv');
-    if not Assigned(glMultiTexCoord3dv) then Exit;
-    glMultiTexCoord3f := wglGetProcAddress('glMultiTexCoord3f');
-    if not Assigned(glMultiTexCoord3f) then Exit;
-    glMultiTexCoord3fv := wglGetProcAddress('glMultiTexCoord3fv');
-    if not Assigned(glMultiTexCoord3fv) then Exit;
-    glMultiTexCoord3i := wglGetProcAddress('glMultiTexCoord3i');
-    if not Assigned(glMultiTexCoord3i) then Exit;
-    glMultiTexCoord3iv := wglGetProcAddress('glMultiTexCoord3iv');
-    if not Assigned(glMultiTexCoord3iv) then Exit;
-    glMultiTexCoord3s := wglGetProcAddress('glMultiTexCoord3s');
-    if not Assigned(glMultiTexCoord3s) then Exit;
-    glMultiTexCoord3sv := wglGetProcAddress('glMultiTexCoord3sv');
-    if not Assigned(glMultiTexCoord3sv) then Exit;
-    glMultiTexCoord4d := wglGetProcAddress('glMultiTexCoord4d');
-    if not Assigned(glMultiTexCoord4d) then Exit;
-    glMultiTexCoord4dv := wglGetProcAddress('glMultiTexCoord4dv');
-    if not Assigned(glMultiTexCoord4dv) then Exit;
-    glMultiTexCoord4f := wglGetProcAddress('glMultiTexCoord4f');
-    if not Assigned(glMultiTexCoord4f) then Exit;
-    glMultiTexCoord4fv := wglGetProcAddress('glMultiTexCoord4fv');
-    if not Assigned(glMultiTexCoord4fv) then Exit;
-    glMultiTexCoord4i := wglGetProcAddress('glMultiTexCoord4i');
-    if not Assigned(glMultiTexCoord4i) then Exit;
-    glMultiTexCoord4iv := wglGetProcAddress('glMultiTexCoord4iv');
-    if not Assigned(glMultiTexCoord4iv) then Exit;
-    glMultiTexCoord4s := wglGetProcAddress('glMultiTexCoord4s');
-    if not Assigned(glMultiTexCoord4s) then Exit;
-    glMultiTexCoord4sv := wglGetProcAddress('glMultiTexCoord4sv');
-    if not Assigned(glMultiTexCoord4sv) then Exit;
-    glLoadTransposeMatrixf := wglGetProcAddress('glLoadTransposeMatrixf');
-    if not Assigned(glLoadTransposeMatrixf) then Exit;
-    glLoadTransposeMatrixd := wglGetProcAddress('glLoadTransposeMatrixd');
-    if not Assigned(glLoadTransposeMatrixd) then Exit;
-    glMultTransposeMatrixf := wglGetProcAddress('glMultTransposeMatrixf');
-    if not Assigned(glMultTransposeMatrixf) then Exit;
-    glMultTransposeMatrixd := wglGetProcAddress('glMultTransposeMatrixd');
-    if not Assigned(glMultTransposeMatrixd) then Exit;
-    glSampleCoverage := wglGetProcAddress('glSampleCoverage');
-    if not Assigned(glSampleCoverage) then Exit;
-    glCompressedTexImage3D := wglGetProcAddress('glCompressedTexImage3D');
-    if not Assigned(glCompressedTexImage3D) then Exit;
-    glCompressedTexImage2D := wglGetProcAddress('glCompressedTexImage2D');
-    if not Assigned(glCompressedTexImage2D) then Exit;
-    glCompressedTexImage1D := wglGetProcAddress('glCompressedTexImage1D');
-    if not Assigned(glCompressedTexImage1D) then Exit;
-    glCompressedTexSubImage3D := wglGetProcAddress('glCompressedTexSubImage3D');
-    if not Assigned(glCompressedTexSubImage3D) then Exit;
-    glCompressedTexSubImage2D := wglGetProcAddress('glCompressedTexSubImage2D');
-    if not Assigned(glCompressedTexSubImage2D) then Exit;
-    glCompressedTexSubImage1D := wglGetProcAddress('glCompressedTexSubImage1D');
-    if not Assigned(glCompressedTexSubImage1D) then Exit;
-    glGetCompressedTexImage := wglGetProcAddress('glGetCompressedTexImage');
-    if not Assigned(glGetCompressedTexImage) then Exit;
-    Result := TRUE;
-
-end;
-
-function Load_GL_ARB_multitexture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_multitexture', extstring) then
-  begin
-    glActiveTextureARB := wglGetProcAddress('glActiveTextureARB');
-    if not Assigned(glActiveTextureARB) then Exit;
-    glClientActiveTextureARB := wglGetProcAddress('glClientActiveTextureARB');
-    if not Assigned(glClientActiveTextureARB) then Exit;
-    glMultiTexCoord1dARB := wglGetProcAddress('glMultiTexCoord1dARB');
-    if not Assigned(glMultiTexCoord1dARB) then Exit;
-    glMultiTexCoord1dvARB := wglGetProcAddress('glMultiTexCoord1dvARB');
-    if not Assigned(glMultiTexCoord1dvARB) then Exit;
-    glMultiTexCoord1fARB := wglGetProcAddress('glMultiTexCoord1fARB');
-    if not Assigned(glMultiTexCoord1fARB) then Exit;
-    glMultiTexCoord1fvARB := wglGetProcAddress('glMultiTexCoord1fvARB');
-    if not Assigned(glMultiTexCoord1fvARB) then Exit;
-    glMultiTexCoord1iARB := wglGetProcAddress('glMultiTexCoord1iARB');
-    if not Assigned(glMultiTexCoord1iARB) then Exit;
-    glMultiTexCoord1ivARB := wglGetProcAddress('glMultiTexCoord1ivARB');
-    if not Assigned(glMultiTexCoord1ivARB) then Exit;
-    glMultiTexCoord1sARB := wglGetProcAddress('glMultiTexCoord1sARB');
-    if not Assigned(glMultiTexCoord1sARB) then Exit;
-    glMultiTexCoord1svARB := wglGetProcAddress('glMultiTexCoord1svARB');
-    if not Assigned(glMultiTexCoord1svARB) then Exit;
-    glMultiTexCoord2dARB := wglGetProcAddress('glMultiTexCoord2dARB');
-    if not Assigned(glMultiTexCoord2dARB) then Exit;
-    glMultiTexCoord2dvARB := wglGetProcAddress('glMultiTexCoord2dvARB');
-    if not Assigned(glMultiTexCoord2dvARB) then Exit;
-    glMultiTexCoord2fARB := wglGetProcAddress('glMultiTexCoord2fARB');
-    if not Assigned(glMultiTexCoord2fARB) then Exit;
-    glMultiTexCoord2fvARB := wglGetProcAddress('glMultiTexCoord2fvARB');
-    if not Assigned(glMultiTexCoord2fvARB) then Exit;
-    glMultiTexCoord2iARB := wglGetProcAddress('glMultiTexCoord2iARB');
-    if not Assigned(glMultiTexCoord2iARB) then Exit;
-    glMultiTexCoord2ivARB := wglGetProcAddress('glMultiTexCoord2ivARB');
-    if not Assigned(glMultiTexCoord2ivARB) then Exit;
-    glMultiTexCoord2sARB := wglGetProcAddress('glMultiTexCoord2sARB');
-    if not Assigned(glMultiTexCoord2sARB) then Exit;
-    glMultiTexCoord2svARB := wglGetProcAddress('glMultiTexCoord2svARB');
-    if not Assigned(glMultiTexCoord2svARB) then Exit;
-    glMultiTexCoord3dARB := wglGetProcAddress('glMultiTexCoord3dARB');
-    if not Assigned(glMultiTexCoord3dARB) then Exit;
-    glMultiTexCoord3dvARB := wglGetProcAddress('glMultiTexCoord3dvARB');
-    if not Assigned(glMultiTexCoord3dvARB) then Exit;
-    glMultiTexCoord3fARB := wglGetProcAddress('glMultiTexCoord3fARB');
-    if not Assigned(glMultiTexCoord3fARB) then Exit;
-    glMultiTexCoord3fvARB := wglGetProcAddress('glMultiTexCoord3fvARB');
-    if not Assigned(glMultiTexCoord3fvARB) then Exit;
-    glMultiTexCoord3iARB := wglGetProcAddress('glMultiTexCoord3iARB');
-    if not Assigned(glMultiTexCoord3iARB) then Exit;
-    glMultiTexCoord3ivARB := wglGetProcAddress('glMultiTexCoord3ivARB');
-    if not Assigned(glMultiTexCoord3ivARB) then Exit;
-    glMultiTexCoord3sARB := wglGetProcAddress('glMultiTexCoord3sARB');
-    if not Assigned(glMultiTexCoord3sARB) then Exit;
-    glMultiTexCoord3svARB := wglGetProcAddress('glMultiTexCoord3svARB');
-    if not Assigned(glMultiTexCoord3svARB) then Exit;
-    glMultiTexCoord4dARB := wglGetProcAddress('glMultiTexCoord4dARB');
-    if not Assigned(glMultiTexCoord4dARB) then Exit;
-    glMultiTexCoord4dvARB := wglGetProcAddress('glMultiTexCoord4dvARB');
-    if not Assigned(glMultiTexCoord4dvARB) then Exit;
-    glMultiTexCoord4fARB := wglGetProcAddress('glMultiTexCoord4fARB');
-    if not Assigned(glMultiTexCoord4fARB) then Exit;
-    glMultiTexCoord4fvARB := wglGetProcAddress('glMultiTexCoord4fvARB');
-    if not Assigned(glMultiTexCoord4fvARB) then Exit;
-    glMultiTexCoord4iARB := wglGetProcAddress('glMultiTexCoord4iARB');
-    if not Assigned(glMultiTexCoord4iARB) then Exit;
-    glMultiTexCoord4ivARB := wglGetProcAddress('glMultiTexCoord4ivARB');
-    if not Assigned(glMultiTexCoord4ivARB) then Exit;
-    glMultiTexCoord4sARB := wglGetProcAddress('glMultiTexCoord4sARB');
-    if not Assigned(glMultiTexCoord4sARB) then Exit;
-    glMultiTexCoord4svARB := wglGetProcAddress('glMultiTexCoord4svARB');
-    if not Assigned(glMultiTexCoord4svARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_transpose_matrix: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_transpose_matrix', extstring) then
-  begin
-    glLoadTransposeMatrixfARB := wglGetProcAddress('glLoadTransposeMatrixfARB');
-    if not Assigned(glLoadTransposeMatrixfARB) then Exit;
-    glLoadTransposeMatrixdARB := wglGetProcAddress('glLoadTransposeMatrixdARB');
-    if not Assigned(glLoadTransposeMatrixdARB) then Exit;
-    glMultTransposeMatrixfARB := wglGetProcAddress('glMultTransposeMatrixfARB');
-    if not Assigned(glMultTransposeMatrixfARB) then Exit;
-    glMultTransposeMatrixdARB := wglGetProcAddress('glMultTransposeMatrixdARB');
-    if not Assigned(glMultTransposeMatrixdARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_multisample: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_multisample', extstring) then
-  begin
-    glSampleCoverageARB := wglGetProcAddress('glSampleCoverageARB');
-    if not Assigned(glSampleCoverageARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_env_add: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_env_add', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_ARB_extensions_string: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_ARB_extensions_string', extstring) then
-  begin
-    wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-    if not Assigned(wglGetExtensionsStringARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_ARB_buffer_region: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_ARB_buffer_region', extstring) then
-  begin
-    wglCreateBufferRegionARB := wglGetProcAddress('wglCreateBufferRegionARB');
-    if not Assigned(wglCreateBufferRegionARB) then Exit;
-    wglDeleteBufferRegionARB := wglGetProcAddress('wglDeleteBufferRegionARB');
-    if not Assigned(wglDeleteBufferRegionARB) then Exit;
-    wglSaveBufferRegionARB := wglGetProcAddress('wglSaveBufferRegionARB');
-    if not Assigned(wglSaveBufferRegionARB) then Exit;
-    wglRestoreBufferRegionARB := wglGetProcAddress('wglRestoreBufferRegionARB');
-    if not Assigned(wglRestoreBufferRegionARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_cube_map: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_cube_map', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_depth_texture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_depth_texture', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_point_parameters: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_point_parameters', extstring) then
-  begin
-    glPointParameterfARB := wglGetProcAddress('glPointParameterfARB');
-    if not Assigned(glPointParameterfARB) then Exit;
-    glPointParameterfvARB := wglGetProcAddress('glPointParameterfvARB');
-    if not Assigned(glPointParameterfvARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_shadow: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_shadow', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_shadow_ambient: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_shadow_ambient', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_border_clamp: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_border_clamp', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_compression: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_compression', extstring) then
-  begin
-    glCompressedTexImage3DARB := wglGetProcAddress('glCompressedTexImage3DARB');
-    if not Assigned(glCompressedTexImage3DARB) then Exit;
-    glCompressedTexImage2DARB := wglGetProcAddress('glCompressedTexImage2DARB');
-    if not Assigned(glCompressedTexImage2DARB) then Exit;
-    glCompressedTexImage1DARB := wglGetProcAddress('glCompressedTexImage1DARB');
-    if not Assigned(glCompressedTexImage1DARB) then Exit;
-    glCompressedTexSubImage3DARB := wglGetProcAddress('glCompressedTexSubImage3DARB');
-    if not Assigned(glCompressedTexSubImage3DARB) then Exit;
-    glCompressedTexSubImage2DARB := wglGetProcAddress('glCompressedTexSubImage2DARB');
-    if not Assigned(glCompressedTexSubImage2DARB) then Exit;
-    glCompressedTexSubImage1DARB := wglGetProcAddress('glCompressedTexSubImage1DARB');
-    if not Assigned(glCompressedTexSubImage1DARB) then Exit;
-    glGetCompressedTexImageARB := wglGetProcAddress('glGetCompressedTexImageARB');
-    if not Assigned(glGetCompressedTexImageARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_env_combine: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_env_combine', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_env_crossbar: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_env_crossbar', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_env_dot3: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_env_dot3', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_mirrored_repeat: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_mirrored_repeat', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_vertex_blend: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_vertex_blend', extstring) then
-  begin
-    glWeightbvARB := wglGetProcAddress('glWeightbvARB');
-    if not Assigned(glWeightbvARB) then Exit;
-    glWeightsvARB := wglGetProcAddress('glWeightsvARB');
-    if not Assigned(glWeightsvARB) then Exit;
-    glWeightivARB := wglGetProcAddress('glWeightivARB');
-    if not Assigned(glWeightivARB) then Exit;
-    glWeightfvARB := wglGetProcAddress('glWeightfvARB');
-    if not Assigned(glWeightfvARB) then Exit;
-    glWeightdvARB := wglGetProcAddress('glWeightdvARB');
-    if not Assigned(glWeightdvARB) then Exit;
-    glWeightvARB := wglGetProcAddress('glWeightvARB');
-    if not Assigned(glWeightvARB) then Exit;
-    glWeightubvARB := wglGetProcAddress('glWeightubvARB');
-    if not Assigned(glWeightubvARB) then Exit;
-    glWeightusvARB := wglGetProcAddress('glWeightusvARB');
-    if not Assigned(glWeightusvARB) then Exit;
-    glWeightuivARB := wglGetProcAddress('glWeightuivARB');
-    if not Assigned(glWeightuivARB) then Exit;
-    glWeightPointerARB := wglGetProcAddress('glWeightPointerARB');
-    if not Assigned(glWeightPointerARB) then Exit;
-    glVertexBlendARB := wglGetProcAddress('glVertexBlendARB');
-    if not Assigned(glVertexBlendARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_vertex_program: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_vertex_program', extstring) then
-  begin
-    glVertexAttrib1sARB := wglGetProcAddress('glVertexAttrib1sARB');
-    if not Assigned(glVertexAttrib1sARB) then Exit;
-    glVertexAttrib1fARB := wglGetProcAddress('glVertexAttrib1fARB');
-    if not Assigned(glVertexAttrib1fARB) then Exit;
-    glVertexAttrib1dARB := wglGetProcAddress('glVertexAttrib1dARB');
-    if not Assigned(glVertexAttrib1dARB) then Exit;
-    glVertexAttrib2sARB := wglGetProcAddress('glVertexAttrib2sARB');
-    if not Assigned(glVertexAttrib2sARB) then Exit;
-    glVertexAttrib2fARB := wglGetProcAddress('glVertexAttrib2fARB');
-    if not Assigned(glVertexAttrib2fARB) then Exit;
-    glVertexAttrib2dARB := wglGetProcAddress('glVertexAttrib2dARB');
-    if not Assigned(glVertexAttrib2dARB) then Exit;
-    glVertexAttrib3sARB := wglGetProcAddress('glVertexAttrib3sARB');
-    if not Assigned(glVertexAttrib3sARB) then Exit;
-    glVertexAttrib3fARB := wglGetProcAddress('glVertexAttrib3fARB');
-    if not Assigned(glVertexAttrib3fARB) then Exit;
-    glVertexAttrib3dARB := wglGetProcAddress('glVertexAttrib3dARB');
-    if not Assigned(glVertexAttrib3dARB) then Exit;
-    glVertexAttrib4sARB := wglGetProcAddress('glVertexAttrib4sARB');
-    if not Assigned(glVertexAttrib4sARB) then Exit;
-    glVertexAttrib4fARB := wglGetProcAddress('glVertexAttrib4fARB');
-    if not Assigned(glVertexAttrib4fARB) then Exit;
-    glVertexAttrib4dARB := wglGetProcAddress('glVertexAttrib4dARB');
-    if not Assigned(glVertexAttrib4dARB) then Exit;
-    glVertexAttrib4NubARB := wglGetProcAddress('glVertexAttrib4NubARB');
-    if not Assigned(glVertexAttrib4NubARB) then Exit;
-    glVertexAttrib1svARB := wglGetProcAddress('glVertexAttrib1svARB');
-    if not Assigned(glVertexAttrib1svARB) then Exit;
-    glVertexAttrib1fvARB := wglGetProcAddress('glVertexAttrib1fvARB');
-    if not Assigned(glVertexAttrib1fvARB) then Exit;
-    glVertexAttrib1dvARB := wglGetProcAddress('glVertexAttrib1dvARB');
-    if not Assigned(glVertexAttrib1dvARB) then Exit;
-    glVertexAttrib2svARB := wglGetProcAddress('glVertexAttrib2svARB');
-    if not Assigned(glVertexAttrib2svARB) then Exit;
-    glVertexAttrib2fvARB := wglGetProcAddress('glVertexAttrib2fvARB');
-    if not Assigned(glVertexAttrib2fvARB) then Exit;
-    glVertexAttrib2dvARB := wglGetProcAddress('glVertexAttrib2dvARB');
-    if not Assigned(glVertexAttrib2dvARB) then Exit;
-    glVertexAttrib3svARB := wglGetProcAddress('glVertexAttrib3svARB');
-    if not Assigned(glVertexAttrib3svARB) then Exit;
-    glVertexAttrib3fvARB := wglGetProcAddress('glVertexAttrib3fvARB');
-    if not Assigned(glVertexAttrib3fvARB) then Exit;
-    glVertexAttrib3dvARB := wglGetProcAddress('glVertexAttrib3dvARB');
-    if not Assigned(glVertexAttrib3dvARB) then Exit;
-    glVertexAttrib4bvARB := wglGetProcAddress('glVertexAttrib4bvARB');
-    if not Assigned(glVertexAttrib4bvARB) then Exit;
-    glVertexAttrib4svARB := wglGetProcAddress('glVertexAttrib4svARB');
-    if not Assigned(glVertexAttrib4svARB) then Exit;
-    glVertexAttrib4ivARB := wglGetProcAddress('glVertexAttrib4ivARB');
-    if not Assigned(glVertexAttrib4ivARB) then Exit;
-    glVertexAttrib4ubvARB := wglGetProcAddress('glVertexAttrib4ubvARB');
-    if not Assigned(glVertexAttrib4ubvARB) then Exit;
-    glVertexAttrib4usvARB := wglGetProcAddress('glVertexAttrib4usvARB');
-    if not Assigned(glVertexAttrib4usvARB) then Exit;
-    glVertexAttrib4uivARB := wglGetProcAddress('glVertexAttrib4uivARB');
-    if not Assigned(glVertexAttrib4uivARB) then Exit;
-    glVertexAttrib4fvARB := wglGetProcAddress('glVertexAttrib4fvARB');
-    if not Assigned(glVertexAttrib4fvARB) then Exit;
-    glVertexAttrib4dvARB := wglGetProcAddress('glVertexAttrib4dvARB');
-    if not Assigned(glVertexAttrib4dvARB) then Exit;
-    glVertexAttrib4NbvARB := wglGetProcAddress('glVertexAttrib4NbvARB');
-    if not Assigned(glVertexAttrib4NbvARB) then Exit;
-    glVertexAttrib4NsvARB := wglGetProcAddress('glVertexAttrib4NsvARB');
-    if not Assigned(glVertexAttrib4NsvARB) then Exit;
-    glVertexAttrib4NivARB := wglGetProcAddress('glVertexAttrib4NivARB');
-    if not Assigned(glVertexAttrib4NivARB) then Exit;
-    glVertexAttrib4NubvARB := wglGetProcAddress('glVertexAttrib4NubvARB');
-    if not Assigned(glVertexAttrib4NubvARB) then Exit;
-    glVertexAttrib4NusvARB := wglGetProcAddress('glVertexAttrib4NusvARB');
-    if not Assigned(glVertexAttrib4NusvARB) then Exit;
-    glVertexAttrib4NuivARB := wglGetProcAddress('glVertexAttrib4NuivARB');
-    if not Assigned(glVertexAttrib4NuivARB) then Exit;
-    glVertexAttribPointerARB := wglGetProcAddress('glVertexAttribPointerARB');
-    if not Assigned(glVertexAttribPointerARB) then Exit;
-    glEnableVertexAttribArrayARB := wglGetProcAddress('glEnableVertexAttribArrayARB');
-    if not Assigned(glEnableVertexAttribArrayARB) then Exit;
-    glDisableVertexAttribArrayARB := wglGetProcAddress('glDisableVertexAttribArrayARB');
-    if not Assigned(glDisableVertexAttribArrayARB) then Exit;
-    glProgramStringARB := wglGetProcAddress('glProgramStringARB');
-    if not Assigned(glProgramStringARB) then Exit;
-    glBindProgramARB := wglGetProcAddress('glBindProgramARB');
-    if not Assigned(glBindProgramARB) then Exit;
-    glDeleteProgramsARB := wglGetProcAddress('glDeleteProgramsARB');
-    if not Assigned(glDeleteProgramsARB) then Exit;
-    glGenProgramsARB := wglGetProcAddress('glGenProgramsARB');
-    if not Assigned(glGenProgramsARB) then Exit;
-    glProgramEnvParameter4dARB := wglGetProcAddress('glProgramEnvParameter4dARB');
-    if not Assigned(glProgramEnvParameter4dARB) then Exit;
-    glProgramEnvParameter4dvARB := wglGetProcAddress('glProgramEnvParameter4dvARB');
-    if not Assigned(glProgramEnvParameter4dvARB) then Exit;
-    glProgramEnvParameter4fARB := wglGetProcAddress('glProgramEnvParameter4fARB');
-    if not Assigned(glProgramEnvParameter4fARB) then Exit;
-    glProgramEnvParameter4fvARB := wglGetProcAddress('glProgramEnvParameter4fvARB');
-    if not Assigned(glProgramEnvParameter4fvARB) then Exit;
-    glProgramLocalParameter4dARB := wglGetProcAddress('glProgramLocalParameter4dARB');
-    if not Assigned(glProgramLocalParameter4dARB) then Exit;
-    glProgramLocalParameter4dvARB := wglGetProcAddress('glProgramLocalParameter4dvARB');
-    if not Assigned(glProgramLocalParameter4dvARB) then Exit;
-    glProgramLocalParameter4fARB := wglGetProcAddress('glProgramLocalParameter4fARB');
-    if not Assigned(glProgramLocalParameter4fARB) then Exit;
-    glProgramLocalParameter4fvARB := wglGetProcAddress('glProgramLocalParameter4fvARB');
-    if not Assigned(glProgramLocalParameter4fvARB) then Exit;
-    glGetProgramEnvParameterdvARB := wglGetProcAddress('glGetProgramEnvParameterdvARB');
-    if not Assigned(glGetProgramEnvParameterdvARB) then Exit;
-    glGetProgramEnvParameterfvARB := wglGetProcAddress('glGetProgramEnvParameterfvARB');
-    if not Assigned(glGetProgramEnvParameterfvARB) then Exit;
-    glGetProgramLocalParameterdvARB := wglGetProcAddress('glGetProgramLocalParameterdvARB');
-    if not Assigned(glGetProgramLocalParameterdvARB) then Exit;
-    glGetProgramLocalParameterfvARB := wglGetProcAddress('glGetProgramLocalParameterfvARB');
-    if not Assigned(glGetProgramLocalParameterfvARB) then Exit;
-    glGetProgramivARB := wglGetProcAddress('glGetProgramivARB');
-    if not Assigned(glGetProgramivARB) then Exit;
-    glGetProgramStringARB := wglGetProcAddress('glGetProgramStringARB');
-    if not Assigned(glGetProgramStringARB) then Exit;
-    glGetVertexAttribdvARB := wglGetProcAddress('glGetVertexAttribdvARB');
-    if not Assigned(glGetVertexAttribdvARB) then Exit;
-    glGetVertexAttribfvARB := wglGetProcAddress('glGetVertexAttribfvARB');
-    if not Assigned(glGetVertexAttribfvARB) then Exit;
-    glGetVertexAttribivARB := wglGetProcAddress('glGetVertexAttribivARB');
-    if not Assigned(glGetVertexAttribivARB) then Exit;
-    glGetVertexAttribPointervARB := wglGetProcAddress('glGetVertexAttribPointervARB');
-    if not Assigned(glGetVertexAttribPointervARB) then Exit;
-    glIsProgramARB := wglGetProcAddress('glIsProgramARB');
-    if not Assigned(glIsProgramARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_window_pos: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_window_pos', extstring) then
-  begin
-    glWindowPos2dARB := wglGetProcAddress('glWindowPos2dARB');
-    if not Assigned(glWindowPos2dARB) then Exit;
-    glWindowPos2fARB := wglGetProcAddress('glWindowPos2fARB');
-    if not Assigned(glWindowPos2fARB) then Exit;
-    glWindowPos2iARB := wglGetProcAddress('glWindowPos2iARB');
-    if not Assigned(glWindowPos2iARB) then Exit;
-    glWindowPos2sARB := wglGetProcAddress('glWindowPos2sARB');
-    if not Assigned(glWindowPos2sARB) then Exit;
-    glWindowPos2dvARB := wglGetProcAddress('glWindowPos2dvARB');
-    if not Assigned(glWindowPos2dvARB) then Exit;
-    glWindowPos2fvARB := wglGetProcAddress('glWindowPos2fvARB');
-    if not Assigned(glWindowPos2fvARB) then Exit;
-    glWindowPos2ivARB := wglGetProcAddress('glWindowPos2ivARB');
-    if not Assigned(glWindowPos2ivARB) then Exit;
-    glWindowPos2svARB := wglGetProcAddress('glWindowPos2svARB');
-    if not Assigned(glWindowPos2svARB) then Exit;
-    glWindowPos3dARB := wglGetProcAddress('glWindowPos3dARB');
-    if not Assigned(glWindowPos3dARB) then Exit;
-    glWindowPos3fARB := wglGetProcAddress('glWindowPos3fARB');
-    if not Assigned(glWindowPos3fARB) then Exit;
-    glWindowPos3iARB := wglGetProcAddress('glWindowPos3iARB');
-    if not Assigned(glWindowPos3iARB) then Exit;
-    glWindowPos3sARB := wglGetProcAddress('glWindowPos3sARB');
-    if not Assigned(glWindowPos3sARB) then Exit;
-    glWindowPos3dvARB := wglGetProcAddress('glWindowPos3dvARB');
-    if not Assigned(glWindowPos3dvARB) then Exit;
-    glWindowPos3fvARB := wglGetProcAddress('glWindowPos3fvARB');
-    if not Assigned(glWindowPos3fvARB) then Exit;
-    glWindowPos3ivARB := wglGetProcAddress('glWindowPos3ivARB');
-    if not Assigned(glWindowPos3ivARB) then Exit;
-    glWindowPos3svARB := wglGetProcAddress('glWindowPos3svARB');
-    if not Assigned(glWindowPos3svARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_422_pixels: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_422_pixels', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_abgr: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_abgr', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_bgra: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_bgra', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_blend_color: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_blend_color', extstring) then
-  begin
-    glBlendColorEXT := wglGetProcAddress('glBlendColorEXT');
-    if not Assigned(glBlendColorEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_blend_func_separate: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_blend_func_separate', extstring) then
-  begin
-    glBlendFuncSeparateEXT := wglGetProcAddress('glBlendFuncSeparateEXT');
-    if not Assigned(glBlendFuncSeparateEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_blend_logic_op: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_blend_logic_op', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_blend_minmax: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_blend_minmax', extstring) then
-  begin
-    glBlendEquationEXT := wglGetProcAddress('glBlendEquationEXT');
-    if not Assigned(glBlendEquationEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_blend_subtract: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_blend_subtract', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_clip_volume_hint: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_clip_volume_hint', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_color_subtable: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_color_subtable', extstring) then
-  begin
-    glColorSubTableEXT := wglGetProcAddress('glColorSubTableEXT');
-    if not Assigned(glColorSubTableEXT) then Exit;
-    glCopyColorSubTableEXT := wglGetProcAddress('glCopyColorSubTableEXT');
-    if not Assigned(glCopyColorSubTableEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_compiled_vertex_array: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_compiled_vertex_array', extstring) then
-  begin
-    glLockArraysEXT := wglGetProcAddress('glLockArraysEXT');
-    if not Assigned(glLockArraysEXT) then Exit;
-    glUnlockArraysEXT := wglGetProcAddress('glUnlockArraysEXT');
-    if not Assigned(glUnlockArraysEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_convolution: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_convolution', extstring) then
-  begin
-    glConvolutionFilter1DEXT := wglGetProcAddress('glConvolutionFilter1DEXT');
-    if not Assigned(glConvolutionFilter1DEXT) then Exit;
-    glConvolutionFilter2DEXT := wglGetProcAddress('glConvolutionFilter2DEXT');
-    if not Assigned(glConvolutionFilter2DEXT) then Exit;
-    glCopyConvolutionFilter1DEXT := wglGetProcAddress('glCopyConvolutionFilter1DEXT');
-    if not Assigned(glCopyConvolutionFilter1DEXT) then Exit;
-    glCopyConvolutionFilter2DEXT := wglGetProcAddress('glCopyConvolutionFilter2DEXT');
-    if not Assigned(glCopyConvolutionFilter2DEXT) then Exit;
-    glGetConvolutionFilterEXT := wglGetProcAddress('glGetConvolutionFilterEXT');
-    if not Assigned(glGetConvolutionFilterEXT) then Exit;
-    glSeparableFilter2DEXT := wglGetProcAddress('glSeparableFilter2DEXT');
-    if not Assigned(glSeparableFilter2DEXT) then Exit;
-    glGetSeparableFilterEXT := wglGetProcAddress('glGetSeparableFilterEXT');
-    if not Assigned(glGetSeparableFilterEXT) then Exit;
-    glConvolutionParameteriEXT := wglGetProcAddress('glConvolutionParameteriEXT');
-    if not Assigned(glConvolutionParameteriEXT) then Exit;
-    glConvolutionParameterivEXT := wglGetProcAddress('glConvolutionParameterivEXT');
-    if not Assigned(glConvolutionParameterivEXT) then Exit;
-    glConvolutionParameterfEXT := wglGetProcAddress('glConvolutionParameterfEXT');
-    if not Assigned(glConvolutionParameterfEXT) then Exit;
-    glConvolutionParameterfvEXT := wglGetProcAddress('glConvolutionParameterfvEXT');
-    if not Assigned(glConvolutionParameterfvEXT) then Exit;
-    glGetConvolutionParameterivEXT := wglGetProcAddress('glGetConvolutionParameterivEXT');
-    if not Assigned(glGetConvolutionParameterivEXT) then Exit;
-    glGetConvolutionParameterfvEXT := wglGetProcAddress('glGetConvolutionParameterfvEXT');
-    if not Assigned(glGetConvolutionParameterfvEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_histogram: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_histogram', extstring) then
-  begin
-    glHistogramEXT := wglGetProcAddress('glHistogramEXT');
-    if not Assigned(glHistogramEXT) then Exit;
-    glResetHistogramEXT := wglGetProcAddress('glResetHistogramEXT');
-    if not Assigned(glResetHistogramEXT) then Exit;
-    glGetHistogramEXT := wglGetProcAddress('glGetHistogramEXT');
-    if not Assigned(glGetHistogramEXT) then Exit;
-    glGetHistogramParameterivEXT := wglGetProcAddress('glGetHistogramParameterivEXT');
-    if not Assigned(glGetHistogramParameterivEXT) then Exit;
-    glGetHistogramParameterfvEXT := wglGetProcAddress('glGetHistogramParameterfvEXT');
-    if not Assigned(glGetHistogramParameterfvEXT) then Exit;
-    glMinmaxEXT := wglGetProcAddress('glMinmaxEXT');
-    if not Assigned(glMinmaxEXT) then Exit;
-    glResetMinmaxEXT := wglGetProcAddress('glResetMinmaxEXT');
-    if not Assigned(glResetMinmaxEXT) then Exit;
-    glGetMinmaxEXT := wglGetProcAddress('glGetMinmaxEXT');
-    if not Assigned(glGetMinmaxEXT) then Exit;
-    glGetMinmaxParameterivEXT := wglGetProcAddress('glGetMinmaxParameterivEXT');
-    if not Assigned(glGetMinmaxParameterivEXT) then Exit;
-    glGetMinmaxParameterfvEXT := wglGetProcAddress('glGetMinmaxParameterfvEXT');
-    if not Assigned(glGetMinmaxParameterfvEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_multi_draw_arrays: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_multi_draw_arrays', extstring) then
-  begin
-    glMultiDrawArraysEXT := wglGetProcAddress('glMultiDrawArraysEXT');
-    if not Assigned(glMultiDrawArraysEXT) then Exit;
-    glMultiDrawElementsEXT := wglGetProcAddress('glMultiDrawElementsEXT');
-    if not Assigned(glMultiDrawElementsEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_packed_pixels: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_packed_pixels', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_paletted_texture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_paletted_texture', extstring) then
-  begin
-    glColorTableEXT := wglGetProcAddress('glColorTableEXT');
-    if not Assigned(glColorTableEXT) then Exit;
-    glColorSubTableEXT := wglGetProcAddress('glColorSubTableEXT');
-    if not Assigned(glColorSubTableEXT) then Exit;
-    glGetColorTableEXT := wglGetProcAddress('glGetColorTableEXT');
-    if not Assigned(glGetColorTableEXT) then Exit;
-    glGetColorTableParameterivEXT := wglGetProcAddress('glGetColorTableParameterivEXT');
-    if not Assigned(glGetColorTableParameterivEXT) then Exit;
-    glGetColorTableParameterfvEXT := wglGetProcAddress('glGetColorTableParameterfvEXT');
-    if not Assigned(glGetColorTableParameterfvEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_point_parameters: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_point_parameters', extstring) then
-  begin
-    glPointParameterfEXT := wglGetProcAddress('glPointParameterfEXT');
-    if not Assigned(glPointParameterfEXT) then Exit;
-    glPointParameterfvEXT := wglGetProcAddress('glPointParameterfvEXT');
-    if not Assigned(glPointParameterfvEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_polygon_offset: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_polygon_offset', extstring) then
-  begin
-    glPolygonOffsetEXT := wglGetProcAddress('glPolygonOffsetEXT');
-    if not Assigned(glPolygonOffsetEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_separate_specular_color: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_separate_specular_color', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_shadow_funcs: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_shadow_funcs', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_shared_texture_palette: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_shared_texture_palette', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_stencil_two_side: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_stencil_two_side', extstring) then
-  begin
-    glActiveStencilFaceEXT := wglGetProcAddress('glActiveStencilFaceEXT');
-    if not Assigned(glActiveStencilFaceEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_stencil_wrap: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_stencil_wrap', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_subtexture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_subtexture', extstring) then
-  begin
-    glTexSubImage1DEXT := wglGetProcAddress('glTexSubImage1DEXT');
-    if not Assigned(glTexSubImage1DEXT) then Exit;
-    glTexSubImage2DEXT := wglGetProcAddress('glTexSubImage2DEXT');
-    if not Assigned(glTexSubImage2DEXT) then Exit;
-    glTexSubImage3DEXT := wglGetProcAddress('glTexSubImage3DEXT');
-    if not Assigned(glTexSubImage3DEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture3D: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture3D', extstring) then
-  begin
-    glTexImage3DEXT := wglGetProcAddress('glTexImage3DEXT');
-    if not Assigned(glTexImage3DEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_compression_s3tc: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_compression_s3tc', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_env_add: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_env_add', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_env_combine: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_env_combine', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_env_dot3: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_env_dot3', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_filter_anisotropic: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_filter_anisotropic', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_lod_bias: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_lod_bias', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_object', extstring) then
-  begin
-    glGenTexturesEXT := wglGetProcAddress('glGenTexturesEXT');
-    if not Assigned(glGenTexturesEXT) then Exit;
-    glDeleteTexturesEXT := wglGetProcAddress('glDeleteTexturesEXT');
-    if not Assigned(glDeleteTexturesEXT) then Exit;
-    glBindTextureEXT := wglGetProcAddress('glBindTextureEXT');
-    if not Assigned(glBindTextureEXT) then Exit;
-    glPrioritizeTexturesEXT := wglGetProcAddress('glPrioritizeTexturesEXT');
-    if not Assigned(glPrioritizeTexturesEXT) then Exit;
-    glAreTexturesResidentEXT := wglGetProcAddress('glAreTexturesResidentEXT');
-    if not Assigned(glAreTexturesResidentEXT) then Exit;
-    glIsTextureEXT := wglGetProcAddress('glIsTextureEXT');
-    if not Assigned(glIsTextureEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_vertex_array: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_vertex_array', extstring) then
-  begin
-    glArrayElementEXT := wglGetProcAddress('glArrayElementEXT');
-    if not Assigned(glArrayElementEXT) then Exit;
-    glDrawArraysEXT := wglGetProcAddress('glDrawArraysEXT');
-    if not Assigned(glDrawArraysEXT) then Exit;
-    glVertexPointerEXT := wglGetProcAddress('glVertexPointerEXT');
-    if not Assigned(glVertexPointerEXT) then Exit;
-    glNormalPointerEXT := wglGetProcAddress('glNormalPointerEXT');
-    if not Assigned(glNormalPointerEXT) then Exit;
-    glColorPointerEXT := wglGetProcAddress('glColorPointerEXT');
-    if not Assigned(glColorPointerEXT) then Exit;
-    glIndexPointerEXT := wglGetProcAddress('glIndexPointerEXT');
-    if not Assigned(glIndexPointerEXT) then Exit;
-    glTexCoordPointerEXT := wglGetProcAddress('glTexCoordPointerEXT');
-    if not Assigned(glTexCoordPointerEXT) then Exit;
-    glEdgeFlagPointerEXT := wglGetProcAddress('glEdgeFlagPointerEXT');
-    if not Assigned(glEdgeFlagPointerEXT) then Exit;
-    glGetPointervEXT := wglGetProcAddress('glGetPointervEXT');
-    if not Assigned(glGetPointervEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_vertex_shader: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_vertex_shader', extstring) then
-  begin
-    glBeginVertexShaderEXT := wglGetProcAddress('glBeginVertexShaderEXT');
-    if not Assigned(glBeginVertexShaderEXT) then Exit;
-    glEndVertexShaderEXT := wglGetProcAddress('glEndVertexShaderEXT');
-    if not Assigned(glEndVertexShaderEXT) then Exit;
-    glBindVertexShaderEXT := wglGetProcAddress('glBindVertexShaderEXT');
-    if not Assigned(glBindVertexShaderEXT) then Exit;
-    glGenVertexShadersEXT := wglGetProcAddress('glGenVertexShadersEXT');
-    if not Assigned(glGenVertexShadersEXT) then Exit;
-    glDeleteVertexShaderEXT := wglGetProcAddress('glDeleteVertexShaderEXT');
-    if not Assigned(glDeleteVertexShaderEXT) then Exit;
-    glShaderOp1EXT := wglGetProcAddress('glShaderOp1EXT');
-    if not Assigned(glShaderOp1EXT) then Exit;
-    glShaderOp2EXT := wglGetProcAddress('glShaderOp2EXT');
-    if not Assigned(glShaderOp2EXT) then Exit;
-    glShaderOp3EXT := wglGetProcAddress('glShaderOp3EXT');
-    if not Assigned(glShaderOp3EXT) then Exit;
-    glSwizzleEXT := wglGetProcAddress('glSwizzleEXT');
-    if not Assigned(glSwizzleEXT) then Exit;
-    glWriteMaskEXT := wglGetProcAddress('glWriteMaskEXT');
-    if not Assigned(glWriteMaskEXT) then Exit;
-    glInsertComponentEXT := wglGetProcAddress('glInsertComponentEXT');
-    if not Assigned(glInsertComponentEXT) then Exit;
-    glExtractComponentEXT := wglGetProcAddress('glExtractComponentEXT');
-    if not Assigned(glExtractComponentEXT) then Exit;
-    glGenSymbolsEXT := wglGetProcAddress('glGenSymbolsEXT');
-    if not Assigned(glGenSymbolsEXT) then Exit;
-    glSetInvariantEXT := wglGetProcAddress('glSetInvariantEXT');
-    if not Assigned(glSetInvariantEXT) then Exit;
-    glSetLocalConstantEXT := wglGetProcAddress('glSetLocalConstantEXT');
-    if not Assigned(glSetLocalConstantEXT) then Exit;
-    glVariantbvEXT := wglGetProcAddress('glVariantbvEXT');
-    if not Assigned(glVariantbvEXT) then Exit;
-    glVariantsvEXT := wglGetProcAddress('glVariantsvEXT');
-    if not Assigned(glVariantsvEXT) then Exit;
-    glVariantivEXT := wglGetProcAddress('glVariantivEXT');
-    if not Assigned(glVariantivEXT) then Exit;
-    glVariantfvEXT := wglGetProcAddress('glVariantfvEXT');
-    if not Assigned(glVariantfvEXT) then Exit;
-    glVariantdvEXT := wglGetProcAddress('glVariantdvEXT');
-    if not Assigned(glVariantdvEXT) then Exit;
-    glVariantubvEXT := wglGetProcAddress('glVariantubvEXT');
-    if not Assigned(glVariantubvEXT) then Exit;
-    glVariantusvEXT := wglGetProcAddress('glVariantusvEXT');
-    if not Assigned(glVariantusvEXT) then Exit;
-    glVariantuivEXT := wglGetProcAddress('glVariantuivEXT');
-    if not Assigned(glVariantuivEXT) then Exit;
-    glVariantPointerEXT := wglGetProcAddress('glVariantPointerEXT');
-    if not Assigned(glVariantPointerEXT) then Exit;
-    glEnableVariantClientStateEXT := wglGetProcAddress('glEnableVariantClientStateEXT');
-    if not Assigned(glEnableVariantClientStateEXT) then Exit;
-    glDisableVariantClientStateEXT := wglGetProcAddress('glDisableVariantClientStateEXT');
-    if not Assigned(glDisableVariantClientStateEXT) then Exit;
-    glBindLightParameterEXT := wglGetProcAddress('glBindLightParameterEXT');
-    if not Assigned(glBindLightParameterEXT) then Exit;
-    glBindMaterialParameterEXT := wglGetProcAddress('glBindMaterialParameterEXT');
-    if not Assigned(glBindMaterialParameterEXT) then Exit;
-    glBindTexGenParameterEXT := wglGetProcAddress('glBindTexGenParameterEXT');
-    if not Assigned(glBindTexGenParameterEXT) then Exit;
-    glBindTextureUnitParameterEXT := wglGetProcAddress('glBindTextureUnitParameterEXT');
-    if not Assigned(glBindTextureUnitParameterEXT) then Exit;
-    glBindParameterEXT := wglGetProcAddress('glBindParameterEXT');
-    if not Assigned(glBindParameterEXT) then Exit;
-    glIsVariantEnabledEXT := wglGetProcAddress('glIsVariantEnabledEXT');
-    if not Assigned(glIsVariantEnabledEXT) then Exit;
-    glGetVariantBooleanvEXT := wglGetProcAddress('glGetVariantBooleanvEXT');
-    if not Assigned(glGetVariantBooleanvEXT) then Exit;
-    glGetVariantIntegervEXT := wglGetProcAddress('glGetVariantIntegervEXT');
-    if not Assigned(glGetVariantIntegervEXT) then Exit;
-    glGetVariantFloatvEXT := wglGetProcAddress('glGetVariantFloatvEXT');
-    if not Assigned(glGetVariantFloatvEXT) then Exit;
-    glGetVariantPointervEXT := wglGetProcAddress('glGetVariantPointervEXT');
-    if not Assigned(glGetVariantPointervEXT) then Exit;
-    glGetInvariantBooleanvEXT := wglGetProcAddress('glGetInvariantBooleanvEXT');
-    if not Assigned(glGetInvariantBooleanvEXT) then Exit;
-    glGetInvariantIntegervEXT := wglGetProcAddress('glGetInvariantIntegervEXT');
-    if not Assigned(glGetInvariantIntegervEXT) then Exit;
-    glGetInvariantFloatvEXT := wglGetProcAddress('glGetInvariantFloatvEXT');
-    if not Assigned(glGetInvariantFloatvEXT) then Exit;
-    glGetLocalConstantBooleanvEXT := wglGetProcAddress('glGetLocalConstantBooleanvEXT');
-    if not Assigned(glGetLocalConstantBooleanvEXT) then Exit;
-    glGetLocalConstantIntegervEXT := wglGetProcAddress('glGetLocalConstantIntegervEXT');
-    if not Assigned(glGetLocalConstantIntegervEXT) then Exit;
-    glGetLocalConstantFloatvEXT := wglGetProcAddress('glGetLocalConstantFloatvEXT');
-    if not Assigned(glGetLocalConstantFloatvEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_vertex_weighting: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_vertex_weighting', extstring) then
-  begin
-    glVertexWeightfEXT := wglGetProcAddress('glVertexWeightfEXT');
-    if not Assigned(glVertexWeightfEXT) then Exit;
-    glVertexWeightfvEXT := wglGetProcAddress('glVertexWeightfvEXT');
-    if not Assigned(glVertexWeightfvEXT) then Exit;
-    glVertexWeightPointerEXT := wglGetProcAddress('glVertexWeightPointerEXT');
-    if not Assigned(glVertexWeightPointerEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_HP_occlusion_test: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_HP_occlusion_test', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_blend_square: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_blend_square', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_copy_depth_to_color: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_copy_depth_to_color', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_depth_clamp: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_depth_clamp', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_evaluators: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_evaluators', extstring) then
-  begin
-    glMapControlPointsNV := wglGetProcAddress('glMapControlPointsNV');
-    if not Assigned(glMapControlPointsNV) then Exit;
-    glMapParameterivNV := wglGetProcAddress('glMapParameterivNV');
-    if not Assigned(glMapParameterivNV) then Exit;
-    glMapParameterfvNV := wglGetProcAddress('glMapParameterfvNV');
-    if not Assigned(glMapParameterfvNV) then Exit;
-    glGetMapControlPointsNV := wglGetProcAddress('glGetMapControlPointsNV');
-    if not Assigned(glGetMapControlPointsNV) then Exit;
-    glGetMapParameterivNV := wglGetProcAddress('glGetMapParameterivNV');
-    if not Assigned(glGetMapParameterivNV) then Exit;
-    glGetMapParameterfvNV := wglGetProcAddress('glGetMapParameterfvNV');
-    if not Assigned(glGetMapParameterfvNV) then Exit;
-    glGetMapAttribParameterivNV := wglGetProcAddress('glGetMapAttribParameterivNV');
-    if not Assigned(glGetMapAttribParameterivNV) then Exit;
-    glGetMapAttribParameterfvNV := wglGetProcAddress('glGetMapAttribParameterfvNV');
-    if not Assigned(glGetMapAttribParameterfvNV) then Exit;
-    glEvalMapsNV := wglGetProcAddress('glEvalMapsNV');
-    if not Assigned(glEvalMapsNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_fence: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_fence', extstring) then
-  begin
-    glGenFencesNV := wglGetProcAddress('glGenFencesNV');
-    if not Assigned(glGenFencesNV) then Exit;
-    glDeleteFencesNV := wglGetProcAddress('glDeleteFencesNV');
-    if not Assigned(glDeleteFencesNV) then Exit;
-    glSetFenceNV := wglGetProcAddress('glSetFenceNV');
-    if not Assigned(glSetFenceNV) then Exit;
-    glTestFenceNV := wglGetProcAddress('glTestFenceNV');
-    if not Assigned(glTestFenceNV) then Exit;
-    glFinishFenceNV := wglGetProcAddress('glFinishFenceNV');
-    if not Assigned(glFinishFenceNV) then Exit;
-    glIsFenceNV := wglGetProcAddress('glIsFenceNV');
-    if not Assigned(glIsFenceNV) then Exit;
-    glGetFenceivNV := wglGetProcAddress('glGetFenceivNV');
-    if not Assigned(glGetFenceivNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_fog_distance: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_fog_distance', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_light_max_exponent: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_light_max_exponent', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_multisample_filter_hint: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_multisample_filter_hint', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_occlusion_query: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_occlusion_query', extstring) then
-  begin
-    glGenOcclusionQueriesNV := wglGetProcAddress('glGenOcclusionQueriesNV');
-    if not Assigned(glGenOcclusionQueriesNV) then Exit;
-    glDeleteOcclusionQueriesNV := wglGetProcAddress('glDeleteOcclusionQueriesNV');
-    if not Assigned(glDeleteOcclusionQueriesNV) then Exit;
-    glIsOcclusionQueryNV := wglGetProcAddress('glIsOcclusionQueryNV');
-    if not Assigned(glIsOcclusionQueryNV) then Exit;
-    glBeginOcclusionQueryNV := wglGetProcAddress('glBeginOcclusionQueryNV');
-    if not Assigned(glBeginOcclusionQueryNV) then Exit;
-    glEndOcclusionQueryNV := wglGetProcAddress('glEndOcclusionQueryNV');
-    if not Assigned(glEndOcclusionQueryNV) then Exit;
-    glGetOcclusionQueryivNV := wglGetProcAddress('glGetOcclusionQueryivNV');
-    if not Assigned(glGetOcclusionQueryivNV) then Exit;
-    glGetOcclusionQueryuivNV := wglGetProcAddress('glGetOcclusionQueryuivNV');
-    if not Assigned(glGetOcclusionQueryuivNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_packed_depth_stencil: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_packed_depth_stencil', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_point_sprite: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_point_sprite', extstring) then
-  begin
-    glPointParameteriNV := wglGetProcAddress('glPointParameteriNV');
-    if not Assigned(glPointParameteriNV) then Exit;
-    glPointParameterivNV := wglGetProcAddress('glPointParameterivNV');
-    if not Assigned(glPointParameterivNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_register_combiners: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_register_combiners', extstring) then
-  begin
-    glCombinerParameterfvNV := wglGetProcAddress('glCombinerParameterfvNV');
-    if not Assigned(glCombinerParameterfvNV) then Exit;
-    glCombinerParameterivNV := wglGetProcAddress('glCombinerParameterivNV');
-    if not Assigned(glCombinerParameterivNV) then Exit;
-    glCombinerParameterfNV := wglGetProcAddress('glCombinerParameterfNV');
-    if not Assigned(glCombinerParameterfNV) then Exit;
-    glCombinerParameteriNV := wglGetProcAddress('glCombinerParameteriNV');
-    if not Assigned(glCombinerParameteriNV) then Exit;
-    glCombinerInputNV := wglGetProcAddress('glCombinerInputNV');
-    if not Assigned(glCombinerInputNV) then Exit;
-    glCombinerOutputNV := wglGetProcAddress('glCombinerOutputNV');
-    if not Assigned(glCombinerOutputNV) then Exit;
-    glFinalCombinerInputNV := wglGetProcAddress('glFinalCombinerInputNV');
-    if not Assigned(glFinalCombinerInputNV) then Exit;
-    glGetCombinerInputParameterfvNV := wglGetProcAddress('glGetCombinerInputParameterfvNV');
-    if not Assigned(glGetCombinerInputParameterfvNV) then Exit;
-    glGetCombinerInputParameterivNV := wglGetProcAddress('glGetCombinerInputParameterivNV');
-    if not Assigned(glGetCombinerInputParameterivNV) then Exit;
-    glGetCombinerOutputParameterfvNV := wglGetProcAddress('glGetCombinerOutputParameterfvNV');
-    if not Assigned(glGetCombinerOutputParameterfvNV) then Exit;
-    glGetCombinerOutputParameterivNV := wglGetProcAddress('glGetCombinerOutputParameterivNV');
-    if not Assigned(glGetCombinerOutputParameterivNV) then Exit;
-    glGetFinalCombinerInputParameterfvNV := wglGetProcAddress('glGetFinalCombinerInputParameterfvNV');
-    if not Assigned(glGetFinalCombinerInputParameterfvNV) then Exit;
-    glGetFinalCombinerInputParameterivNV := wglGetProcAddress('glGetFinalCombinerInputParameterivNV');
-    if not Assigned(glGetFinalCombinerInputParameterivNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_register_combiners2: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_register_combiners2', extstring) then
-  begin
-    glCombinerStageParameterfvNV := wglGetProcAddress('glCombinerStageParameterfvNV');
-    if not Assigned(glCombinerStageParameterfvNV) then Exit;
-    glGetCombinerStageParameterfvNV := wglGetProcAddress('glGetCombinerStageParameterfvNV');
-    if not Assigned(glGetCombinerStageParameterfvNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texgen_emboss: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texgen_emboss', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texgen_reflection: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texgen_reflection', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texture_compression_vtc: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texture_compression_vtc', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texture_env_combine4: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texture_env_combine4', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texture_rectangle: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texture_rectangle', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texture_shader: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texture_shader', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texture_shader2: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texture_shader2', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texture_shader3: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texture_shader3', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_vertex_array_range: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_vertex_array_range', extstring) then
-  begin
-    glVertexArrayRangeNV := wglGetProcAddress('glVertexArrayRangeNV');
-    if not Assigned(glVertexArrayRangeNV) then Exit;
-    glFlushVertexArrayRangeNV := wglGetProcAddress('glFlushVertexArrayRangeNV');
-    if not Assigned(glFlushVertexArrayRangeNV) then Exit;
-    wglAllocateMemoryNV := wglGetProcAddress('wglAllocateMemoryNV');
-    if not Assigned(wglAllocateMemoryNV) then Exit;
-    wglFreeMemoryNV := wglGetProcAddress('wglFreeMemoryNV');
-    if not Assigned(wglFreeMemoryNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_vertex_array_range2: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_vertex_array_range2', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_vertex_program: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_vertex_program', extstring) then
-  begin
-    glBindProgramNV := wglGetProcAddress('glBindProgramNV');
-    if not Assigned(glBindProgramNV) then Exit;
-    glDeleteProgramsNV := wglGetProcAddress('glDeleteProgramsNV');
-    if not Assigned(glDeleteProgramsNV) then Exit;
-    glExecuteProgramNV := wglGetProcAddress('glExecuteProgramNV');
-    if not Assigned(glExecuteProgramNV) then Exit;
-    glGenProgramsNV := wglGetProcAddress('glGenProgramsNV');
-    if not Assigned(glGenProgramsNV) then Exit;
-    glAreProgramsResidentNV := wglGetProcAddress('glAreProgramsResidentNV');
-    if not Assigned(glAreProgramsResidentNV) then Exit;
-    glRequestResidentProgramsNV := wglGetProcAddress('glRequestResidentProgramsNV');
-    if not Assigned(glRequestResidentProgramsNV) then Exit;
-    glGetProgramParameterfvNV := wglGetProcAddress('glGetProgramParameterfvNV');
-    if not Assigned(glGetProgramParameterfvNV) then Exit;
-    glGetProgramParameterdvNV := wglGetProcAddress('glGetProgramParameterdvNV');
-    if not Assigned(glGetProgramParameterdvNV) then Exit;
-    glGetProgramivNV := wglGetProcAddress('glGetProgramivNV');
-    if not Assigned(glGetProgramivNV) then Exit;
-    glGetProgramStringNV := wglGetProcAddress('glGetProgramStringNV');
-    if not Assigned(glGetProgramStringNV) then Exit;
-    glGetTrackMatrixivNV := wglGetProcAddress('glGetTrackMatrixivNV');
-    if not Assigned(glGetTrackMatrixivNV) then Exit;
-    glGetVertexAttribdvNV := wglGetProcAddress('glGetVertexAttribdvNV');
-    if not Assigned(glGetVertexAttribdvNV) then Exit;
-    glGetVertexAttribfvNV := wglGetProcAddress('glGetVertexAttribfvNV');
-    if not Assigned(glGetVertexAttribfvNV) then Exit;
-    glGetVertexAttribivNV := wglGetProcAddress('glGetVertexAttribivNV');
-    if not Assigned(glGetVertexAttribivNV) then Exit;
-    glGetVertexAttribPointervNV := wglGetProcAddress('glGetVertexAttribPointervNV');
-    if not Assigned(glGetVertexAttribPointervNV) then Exit;
-    glIsProgramNV := wglGetProcAddress('glIsProgramNV');
-    if not Assigned(glIsProgramNV) then Exit;
-    glLoadProgramNV := wglGetProcAddress('glLoadProgramNV');
-    if not Assigned(glLoadProgramNV) then Exit;
-    glProgramParameter4fNV := wglGetProcAddress('glProgramParameter4fNV');
-    if not Assigned(glProgramParameter4fNV) then Exit;
-    glProgramParameter4fvNV := wglGetProcAddress('glProgramParameter4fvNV');
-    if not Assigned(glProgramParameter4fvNV) then Exit;
-    glProgramParameters4dvNV := wglGetProcAddress('glProgramParameters4dvNV');
-    if not Assigned(glProgramParameters4dvNV) then Exit;
-    glProgramParameters4fvNV := wglGetProcAddress('glProgramParameters4fvNV');
-    if not Assigned(glProgramParameters4fvNV) then Exit;
-    glTrackMatrixNV := wglGetProcAddress('glTrackMatrixNV');
-    if not Assigned(glTrackMatrixNV) then Exit;
-    glVertexAttribPointerNV := wglGetProcAddress('glVertexAttribPointerNV');
-    if not Assigned(glVertexAttribPointerNV) then Exit;
-    glVertexAttrib1sNV := wglGetProcAddress('glVertexAttrib1sNV');
-    if not Assigned(glVertexAttrib1sNV) then Exit;
-    glVertexAttrib1fNV := wglGetProcAddress('glVertexAttrib1fNV');
-    if not Assigned(glVertexAttrib1fNV) then Exit;
-    glVertexAttrib1dNV := wglGetProcAddress('glVertexAttrib1dNV');
-    if not Assigned(glVertexAttrib1dNV) then Exit;
-    glVertexAttrib2sNV := wglGetProcAddress('glVertexAttrib2sNV');
-    if not Assigned(glVertexAttrib2sNV) then Exit;
-    glVertexAttrib2fNV := wglGetProcAddress('glVertexAttrib2fNV');
-    if not Assigned(glVertexAttrib2fNV) then Exit;
-    glVertexAttrib2dNV := wglGetProcAddress('glVertexAttrib2dNV');
-    if not Assigned(glVertexAttrib2dNV) then Exit;
-    glVertexAttrib3sNV := wglGetProcAddress('glVertexAttrib3sNV');
-    if not Assigned(glVertexAttrib3sNV) then Exit;
-    glVertexAttrib3fNV := wglGetProcAddress('glVertexAttrib3fNV');
-    if not Assigned(glVertexAttrib3fNV) then Exit;
-    glVertexAttrib3dNV := wglGetProcAddress('glVertexAttrib3dNV');
-    if not Assigned(glVertexAttrib3dNV) then Exit;
-    glVertexAttrib4sNV := wglGetProcAddress('glVertexAttrib4sNV');
-    if not Assigned(glVertexAttrib4sNV) then Exit;
-    glVertexAttrib4fNV := wglGetProcAddress('glVertexAttrib4fNV');
-    if not Assigned(glVertexAttrib4fNV) then Exit;
-    glVertexAttrib4dNV := wglGetProcAddress('glVertexAttrib4dNV');
-    if not Assigned(glVertexAttrib4dNV) then Exit;
-    glVertexAttrib4ubNV := wglGetProcAddress('glVertexAttrib4ubNV');
-    if not Assigned(glVertexAttrib4ubNV) then Exit;
-    glVertexAttrib1svNV := wglGetProcAddress('glVertexAttrib1svNV');
-    if not Assigned(glVertexAttrib1svNV) then Exit;
-    glVertexAttrib1fvNV := wglGetProcAddress('glVertexAttrib1fvNV');
-    if not Assigned(glVertexAttrib1fvNV) then Exit;
-    glVertexAttrib1dvNV := wglGetProcAddress('glVertexAttrib1dvNV');
-    if not Assigned(glVertexAttrib1dvNV) then Exit;
-    glVertexAttrib2svNV := wglGetProcAddress('glVertexAttrib2svNV');
-    if not Assigned(glVertexAttrib2svNV) then Exit;
-    glVertexAttrib2fvNV := wglGetProcAddress('glVertexAttrib2fvNV');
-    if not Assigned(glVertexAttrib2fvNV) then Exit;
-    glVertexAttrib2dvNV := wglGetProcAddress('glVertexAttrib2dvNV');
-    if not Assigned(glVertexAttrib2dvNV) then Exit;
-    glVertexAttrib3svNV := wglGetProcAddress('glVertexAttrib3svNV');
-    if not Assigned(glVertexAttrib3svNV) then Exit;
-    glVertexAttrib3fvNV := wglGetProcAddress('glVertexAttrib3fvNV');
-    if not Assigned(glVertexAttrib3fvNV) then Exit;
-    glVertexAttrib3dvNV := wglGetProcAddress('glVertexAttrib3dvNV');
-    if not Assigned(glVertexAttrib3dvNV) then Exit;
-    glVertexAttrib4svNV := wglGetProcAddress('glVertexAttrib4svNV');
-    if not Assigned(glVertexAttrib4svNV) then Exit;
-    glVertexAttrib4fvNV := wglGetProcAddress('glVertexAttrib4fvNV');
-    if not Assigned(glVertexAttrib4fvNV) then Exit;
-    glVertexAttrib4dvNV := wglGetProcAddress('glVertexAttrib4dvNV');
-    if not Assigned(glVertexAttrib4dvNV) then Exit;
-    glVertexAttrib4ubvNV := wglGetProcAddress('glVertexAttrib4ubvNV');
-    if not Assigned(glVertexAttrib4ubvNV) then Exit;
-    glVertexAttribs1svNV := wglGetProcAddress('glVertexAttribs1svNV');
-    if not Assigned(glVertexAttribs1svNV) then Exit;
-    glVertexAttribs1fvNV := wglGetProcAddress('glVertexAttribs1fvNV');
-    if not Assigned(glVertexAttribs1fvNV) then Exit;
-    glVertexAttribs1dvNV := wglGetProcAddress('glVertexAttribs1dvNV');
-    if not Assigned(glVertexAttribs1dvNV) then Exit;
-    glVertexAttribs2svNV := wglGetProcAddress('glVertexAttribs2svNV');
-    if not Assigned(glVertexAttribs2svNV) then Exit;
-    glVertexAttribs2fvNV := wglGetProcAddress('glVertexAttribs2fvNV');
-    if not Assigned(glVertexAttribs2fvNV) then Exit;
-    glVertexAttribs2dvNV := wglGetProcAddress('glVertexAttribs2dvNV');
-    if not Assigned(glVertexAttribs2dvNV) then Exit;
-    glVertexAttribs3svNV := wglGetProcAddress('glVertexAttribs3svNV');
-    if not Assigned(glVertexAttribs3svNV) then Exit;
-    glVertexAttribs3fvNV := wglGetProcAddress('glVertexAttribs3fvNV');
-    if not Assigned(glVertexAttribs3fvNV) then Exit;
-    glVertexAttribs3dvNV := wglGetProcAddress('glVertexAttribs3dvNV');
-    if not Assigned(glVertexAttribs3dvNV) then Exit;
-    glVertexAttribs4svNV := wglGetProcAddress('glVertexAttribs4svNV');
-    if not Assigned(glVertexAttribs4svNV) then Exit;
-    glVertexAttribs4fvNV := wglGetProcAddress('glVertexAttribs4fvNV');
-    if not Assigned(glVertexAttribs4fvNV) then Exit;
-    glVertexAttribs4dvNV := wglGetProcAddress('glVertexAttribs4dvNV');
-    if not Assigned(glVertexAttribs4dvNV) then Exit;
-    glVertexAttribs4ubvNV := wglGetProcAddress('glVertexAttribs4ubvNV');
-    if not Assigned(glVertexAttribs4ubvNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_vertex_program1_1: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_vertex_program1_1', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_element_array: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_element_array', extstring) then
-  begin
-    glElementPointerATI := wglGetProcAddress('glElementPointerATI');
-    if not Assigned(glElementPointerATI) then Exit;
-    glDrawElementArrayATI := wglGetProcAddress('glDrawElementArrayATI');
-    if not Assigned(glDrawElementArrayATI) then Exit;
-    glDrawRangeElementArrayATI := wglGetProcAddress('glDrawRangeElementArrayATI');
-    if not Assigned(glDrawRangeElementArrayATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_envmap_bumpmap: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_envmap_bumpmap', extstring) then
-  begin
-    glTexBumpParameterivATI := wglGetProcAddress('glTexBumpParameterivATI');
-    if not Assigned(glTexBumpParameterivATI) then Exit;
-    glTexBumpParameterfvATI := wglGetProcAddress('glTexBumpParameterfvATI');
-    if not Assigned(glTexBumpParameterfvATI) then Exit;
-    glGetTexBumpParameterivATI := wglGetProcAddress('glGetTexBumpParameterivATI');
-    if not Assigned(glGetTexBumpParameterivATI) then Exit;
-    glGetTexBumpParameterfvATI := wglGetProcAddress('glGetTexBumpParameterfvATI');
-    if not Assigned(glGetTexBumpParameterfvATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_fragment_shader: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_fragment_shader', extstring) then
-  begin
-    glGenFragmentShadersATI := wglGetProcAddress('glGenFragmentShadersATI');
-    if not Assigned(glGenFragmentShadersATI) then Exit;
-    glBindFragmentShaderATI := wglGetProcAddress('glBindFragmentShaderATI');
-    if not Assigned(glBindFragmentShaderATI) then Exit;
-    glDeleteFragmentShaderATI := wglGetProcAddress('glDeleteFragmentShaderATI');
-    if not Assigned(glDeleteFragmentShaderATI) then Exit;
-    glBeginFragmentShaderATI := wglGetProcAddress('glBeginFragmentShaderATI');
-    if not Assigned(glBeginFragmentShaderATI) then Exit;
-    glEndFragmentShaderATI := wglGetProcAddress('glEndFragmentShaderATI');
-    if not Assigned(glEndFragmentShaderATI) then Exit;
-    glPassTexCoordATI := wglGetProcAddress('glPassTexCoordATI');
-    if not Assigned(glPassTexCoordATI) then Exit;
-    glSampleMapATI := wglGetProcAddress('glSampleMapATI');
-    if not Assigned(glSampleMapATI) then Exit;
-    glColorFragmentOp1ATI := wglGetProcAddress('glColorFragmentOp1ATI');
-    if not Assigned(glColorFragmentOp1ATI) then Exit;
-    glColorFragmentOp2ATI := wglGetProcAddress('glColorFragmentOp2ATI');
-    if not Assigned(glColorFragmentOp2ATI) then Exit;
-    glColorFragmentOp3ATI := wglGetProcAddress('glColorFragmentOp3ATI');
-    if not Assigned(glColorFragmentOp3ATI) then Exit;
-    glAlphaFragmentOp1ATI := wglGetProcAddress('glAlphaFragmentOp1ATI');
-    if not Assigned(glAlphaFragmentOp1ATI) then Exit;
-    glAlphaFragmentOp2ATI := wglGetProcAddress('glAlphaFragmentOp2ATI');
-    if not Assigned(glAlphaFragmentOp2ATI) then Exit;
-    glAlphaFragmentOp3ATI := wglGetProcAddress('glAlphaFragmentOp3ATI');
-    if not Assigned(glAlphaFragmentOp3ATI) then Exit;
-    glSetFragmentShaderConstantATI := wglGetProcAddress('glSetFragmentShaderConstantATI');
-    if not Assigned(glSetFragmentShaderConstantATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_pn_triangles: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_pn_triangles', extstring) then
-  begin
-    glPNTrianglesiATI := wglGetProcAddress('glPNTrianglesiATI');
-    if not Assigned(glPNTrianglesiATI) then Exit;
-    glPNTrianglesfATI := wglGetProcAddress('glPNTrianglesfATI');
-    if not Assigned(glPNTrianglesfATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_texture_mirror_once: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_texture_mirror_once', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_vertex_array_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_vertex_array_object', extstring) then
-  begin
-    glNewObjectBufferATI := wglGetProcAddress('glNewObjectBufferATI');
-    if not Assigned(glNewObjectBufferATI) then Exit;
-    glIsObjectBufferATI := wglGetProcAddress('glIsObjectBufferATI');
-    if not Assigned(glIsObjectBufferATI) then Exit;
-    glUpdateObjectBufferATI := wglGetProcAddress('glUpdateObjectBufferATI');
-    if not Assigned(glUpdateObjectBufferATI) then Exit;
-    glGetObjectBufferfvATI := wglGetProcAddress('glGetObjectBufferfvATI');
-    if not Assigned(glGetObjectBufferfvATI) then Exit;
-    glGetObjectBufferivATI := wglGetProcAddress('glGetObjectBufferivATI');
-    if not Assigned(glGetObjectBufferivATI) then Exit;
-    glDeleteObjectBufferATI := wglGetProcAddress('glDeleteObjectBufferATI');
-    if not Assigned(glDeleteObjectBufferATI) then Exit;
-    glArrayObjectATI := wglGetProcAddress('glArrayObjectATI');
-    if not Assigned(glArrayObjectATI) then Exit;
-    glGetArrayObjectfvATI := wglGetProcAddress('glGetArrayObjectfvATI');
-    if not Assigned(glGetArrayObjectfvATI) then Exit;
-    glGetArrayObjectivATI := wglGetProcAddress('glGetArrayObjectivATI');
-    if not Assigned(glGetArrayObjectivATI) then Exit;
-    glVariantArrayObjectATI := wglGetProcAddress('glVariantArrayObjectATI');
-    if not Assigned(glVariantArrayObjectATI) then Exit;
-    glGetVariantArrayObjectfvATI := wglGetProcAddress('glGetVariantArrayObjectfvATI');
-    if not Assigned(glGetVariantArrayObjectfvATI) then Exit;
-    glGetVariantArrayObjectivATI := wglGetProcAddress('glGetVariantArrayObjectivATI');
-    if not Assigned(glGetVariantArrayObjectivATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_vertex_streams: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_vertex_streams', extstring) then
-  begin
-    glVertexStream1s := wglGetProcAddress('glVertexStream1s');
-    if not Assigned(glVertexStream1s) then Exit;
-    glVertexStream1i := wglGetProcAddress('glVertexStream1i');
-    if not Assigned(glVertexStream1i) then Exit;
-    glVertexStream1f := wglGetProcAddress('glVertexStream1f');
-    if not Assigned(glVertexStream1f) then Exit;
-    glVertexStream1d := wglGetProcAddress('glVertexStream1d');
-    if not Assigned(glVertexStream1d) then Exit;
-    glVertexStream1sv := wglGetProcAddress('glVertexStream1sv');
-    if not Assigned(glVertexStream1sv) then Exit;
-    glVertexStream1iv := wglGetProcAddress('glVertexStream1iv');
-    if not Assigned(glVertexStream1iv) then Exit;
-    glVertexStream1fv := wglGetProcAddress('glVertexStream1fv');
-    if not Assigned(glVertexStream1fv) then Exit;
-    glVertexStream1dv := wglGetProcAddress('glVertexStream1dv');
-    if not Assigned(glVertexStream1dv) then Exit;
-    glVertexStream2s := wglGetProcAddress('glVertexStream2s');
-    if not Assigned(glVertexStream2s) then Exit;
-    glVertexStream2i := wglGetProcAddress('glVertexStream2i');
-    if not Assigned(glVertexStream2i) then Exit;
-    glVertexStream2f := wglGetProcAddress('glVertexStream2f');
-    if not Assigned(glVertexStream2f) then Exit;
-    glVertexStream2d := wglGetProcAddress('glVertexStream2d');
-    if not Assigned(glVertexStream2d) then Exit;
-    glVertexStream2sv := wglGetProcAddress('glVertexStream2sv');
-    if not Assigned(glVertexStream2sv) then Exit;
-    glVertexStream2iv := wglGetProcAddress('glVertexStream2iv');
-    if not Assigned(glVertexStream2iv) then Exit;
-    glVertexStream2fv := wglGetProcAddress('glVertexStream2fv');
-    if not Assigned(glVertexStream2fv) then Exit;
-    glVertexStream2dv := wglGetProcAddress('glVertexStream2dv');
-    if not Assigned(glVertexStream2dv) then Exit;
-    glVertexStream3s := wglGetProcAddress('glVertexStream3s');
-    if not Assigned(glVertexStream3s) then Exit;
-    glVertexStream3i := wglGetProcAddress('glVertexStream3i');
-    if not Assigned(glVertexStream3i) then Exit;
-    glVertexStream3f := wglGetProcAddress('glVertexStream3f');
-    if not Assigned(glVertexStream3f) then Exit;
-    glVertexStream3d := wglGetProcAddress('glVertexStream3d');
-    if not Assigned(glVertexStream3d) then Exit;
-    glVertexStream3sv := wglGetProcAddress('glVertexStream3sv');
-    if not Assigned(glVertexStream3sv) then Exit;
-    glVertexStream3iv := wglGetProcAddress('glVertexStream3iv');
-    if not Assigned(glVertexStream3iv) then Exit;
-    glVertexStream3fv := wglGetProcAddress('glVertexStream3fv');
-    if not Assigned(glVertexStream3fv) then Exit;
-    glVertexStream3dv := wglGetProcAddress('glVertexStream3dv');
-    if not Assigned(glVertexStream3dv) then Exit;
-    glVertexStream4s := wglGetProcAddress('glVertexStream4s');
-    if not Assigned(glVertexStream4s) then Exit;
-    glVertexStream4i := wglGetProcAddress('glVertexStream4i');
-    if not Assigned(glVertexStream4i) then Exit;
-    glVertexStream4f := wglGetProcAddress('glVertexStream4f');
-    if not Assigned(glVertexStream4f) then Exit;
-    glVertexStream4d := wglGetProcAddress('glVertexStream4d');
-    if not Assigned(glVertexStream4d) then Exit;
-    glVertexStream4sv := wglGetProcAddress('glVertexStream4sv');
-    if not Assigned(glVertexStream4sv) then Exit;
-    glVertexStream4iv := wglGetProcAddress('glVertexStream4iv');
-    if not Assigned(glVertexStream4iv) then Exit;
-    glVertexStream4fv := wglGetProcAddress('glVertexStream4fv');
-    if not Assigned(glVertexStream4fv) then Exit;
-    glVertexStream4dv := wglGetProcAddress('glVertexStream4dv');
-    if not Assigned(glVertexStream4dv) then Exit;
-    glNormalStream3b := wglGetProcAddress('glNormalStream3b');
-    if not Assigned(glNormalStream3b) then Exit;
-    glNormalStream3s := wglGetProcAddress('glNormalStream3s');
-    if not Assigned(glNormalStream3s) then Exit;
-    glNormalStream3i := wglGetProcAddress('glNormalStream3i');
-    if not Assigned(glNormalStream3i) then Exit;
-    glNormalStream3f := wglGetProcAddress('glNormalStream3f');
-    if not Assigned(glNormalStream3f) then Exit;
-    glNormalStream3d := wglGetProcAddress('glNormalStream3d');
-    if not Assigned(glNormalStream3d) then Exit;
-    glNormalStream3bv := wglGetProcAddress('glNormalStream3bv');
-    if not Assigned(glNormalStream3bv) then Exit;
-    glNormalStream3sv := wglGetProcAddress('glNormalStream3sv');
-    if not Assigned(glNormalStream3sv) then Exit;
-    glNormalStream3iv := wglGetProcAddress('glNormalStream3iv');
-    if not Assigned(glNormalStream3iv) then Exit;
-    glNormalStream3fv := wglGetProcAddress('glNormalStream3fv');
-    if not Assigned(glNormalStream3fv) then Exit;
-    glNormalStream3dv := wglGetProcAddress('glNormalStream3dv');
-    if not Assigned(glNormalStream3dv) then Exit;
-    glClientActiveVertexStream := wglGetProcAddress('glClientActiveVertexStream');
-    if not Assigned(glClientActiveVertexStream) then Exit;
-    glVertexBlendEnvi := wglGetProcAddress('glVertexBlendEnvi');
-    if not Assigned(glVertexBlendEnvi) then Exit;
-    glVertexBlendEnvf := wglGetProcAddress('glVertexBlendEnvf');
-    if not Assigned(glVertexBlendEnvf) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_I3D_image_buffer: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_I3D_image_buffer', extstring) then
-  begin
-    wglCreateImageBufferI3D := wglGetProcAddress('wglCreateImageBufferI3D');
-    if not Assigned(wglCreateImageBufferI3D) then Exit;
-    wglDestroyImageBufferI3D := wglGetProcAddress('wglDestroyImageBufferI3D');
-    if not Assigned(wglDestroyImageBufferI3D) then Exit;
-    wglAssociateImageBufferEventsI3D := wglGetProcAddress('wglAssociateImageBufferEventsI3D');
-    if not Assigned(wglAssociateImageBufferEventsI3D) then Exit;
-    wglReleaseImageBufferEventsI3D := wglGetProcAddress('wglReleaseImageBufferEventsI3D');
-    if not Assigned(wglReleaseImageBufferEventsI3D) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_I3D_swap_frame_lock: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_I3D_swap_frame_lock', extstring) then
-  begin
-    wglEnableFrameLockI3D := wglGetProcAddress('wglEnableFrameLockI3D');
-    if not Assigned(wglEnableFrameLockI3D) then Exit;
-    wglDisableFrameLockI3D := wglGetProcAddress('wglDisableFrameLockI3D');
-    if not Assigned(wglDisableFrameLockI3D) then Exit;
-    wglIsEnabledFrameLockI3D := wglGetProcAddress('wglIsEnabledFrameLockI3D');
-    if not Assigned(wglIsEnabledFrameLockI3D) then Exit;
-    wglQueryFrameLockMasterI3D := wglGetProcAddress('wglQueryFrameLockMasterI3D');
-    if not Assigned(wglQueryFrameLockMasterI3D) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_I3D_swap_frame_usage: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_I3D_swap_frame_usage', extstring) then
-  begin
-    wglGetFrameUsageI3D := wglGetProcAddress('wglGetFrameUsageI3D');
-    if not Assigned(wglGetFrameUsageI3D) then Exit;
-    wglBeginFrameTrackingI3D := wglGetProcAddress('wglBeginFrameTrackingI3D');
-    if not Assigned(wglBeginFrameTrackingI3D) then Exit;
-    wglEndFrameTrackingI3D := wglGetProcAddress('wglEndFrameTrackingI3D');
-    if not Assigned(wglEndFrameTrackingI3D) then Exit;
-    wglQueryFrameTrackingI3D := wglGetProcAddress('wglQueryFrameTrackingI3D');
-    if not Assigned(wglQueryFrameTrackingI3D) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_3DFX_texture_compression_FXT1: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_3DFX_texture_compression_FXT1', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_IBM_cull_vertex: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_IBM_cull_vertex', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_IBM_multimode_draw_arrays: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_IBM_multimode_draw_arrays', extstring) then
-  begin
-    glMultiModeDrawArraysIBM := wglGetProcAddress('glMultiModeDrawArraysIBM');
-    if not Assigned(glMultiModeDrawArraysIBM) then Exit;
-    glMultiModeDrawElementsIBM := wglGetProcAddress('glMultiModeDrawElementsIBM');
-    if not Assigned(glMultiModeDrawElementsIBM) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_IBM_raster_pos_clip: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_IBM_raster_pos_clip', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_IBM_texture_mirrored_repeat: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_IBM_texture_mirrored_repeat', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_IBM_vertex_array_lists: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_IBM_vertex_array_lists', extstring) then
-  begin
-    glColorPointerListIBM := wglGetProcAddress('glColorPointerListIBM');
-    if not Assigned(glColorPointerListIBM) then Exit;
-    glSecondaryColorPointerListIBM := wglGetProcAddress('glSecondaryColorPointerListIBM');
-    if not Assigned(glSecondaryColorPointerListIBM) then Exit;
-    glEdgeFlagPointerListIBM := wglGetProcAddress('glEdgeFlagPointerListIBM');
-    if not Assigned(glEdgeFlagPointerListIBM) then Exit;
-    glFogCoordPointerListIBM := wglGetProcAddress('glFogCoordPointerListIBM');
-    if not Assigned(glFogCoordPointerListIBM) then Exit;
-    glNormalPointerListIBM := wglGetProcAddress('glNormalPointerListIBM');
-    if not Assigned(glNormalPointerListIBM) then Exit;
-    glTexCoordPointerListIBM := wglGetProcAddress('glTexCoordPointerListIBM');
-    if not Assigned(glTexCoordPointerListIBM) then Exit;
-    glVertexPointerListIBM := wglGetProcAddress('glVertexPointerListIBM');
-    if not Assigned(glVertexPointerListIBM) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_MESA_resize_buffers: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_MESA_resize_buffers', extstring) then
-  begin
-    glResizeBuffersMESA := wglGetProcAddress('glResizeBuffersMESA');
-    if not Assigned(glResizeBuffersMESA) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_MESA_window_pos: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_MESA_window_pos', extstring) then
-  begin
-    glWindowPos2dMESA := wglGetProcAddress('glWindowPos2dMESA');
-    if not Assigned(glWindowPos2dMESA) then Exit;
-    glWindowPos2fMESA := wglGetProcAddress('glWindowPos2fMESA');
-    if not Assigned(glWindowPos2fMESA) then Exit;
-    glWindowPos2iMESA := wglGetProcAddress('glWindowPos2iMESA');
-    if not Assigned(glWindowPos2iMESA) then Exit;
-    glWindowPos2sMESA := wglGetProcAddress('glWindowPos2sMESA');
-    if not Assigned(glWindowPos2sMESA) then Exit;
-    glWindowPos2ivMESA := wglGetProcAddress('glWindowPos2ivMESA');
-    if not Assigned(glWindowPos2ivMESA) then Exit;
-    glWindowPos2svMESA := wglGetProcAddress('glWindowPos2svMESA');
-    if not Assigned(glWindowPos2svMESA) then Exit;
-    glWindowPos2fvMESA := wglGetProcAddress('glWindowPos2fvMESA');
-    if not Assigned(glWindowPos2fvMESA) then Exit;
-    glWindowPos2dvMESA := wglGetProcAddress('glWindowPos2dvMESA');
-    if not Assigned(glWindowPos2dvMESA) then Exit;
-    glWindowPos3iMESA := wglGetProcAddress('glWindowPos3iMESA');
-    if not Assigned(glWindowPos3iMESA) then Exit;
-    glWindowPos3sMESA := wglGetProcAddress('glWindowPos3sMESA');
-    if not Assigned(glWindowPos3sMESA) then Exit;
-    glWindowPos3fMESA := wglGetProcAddress('glWindowPos3fMESA');
-    if not Assigned(glWindowPos3fMESA) then Exit;
-    glWindowPos3dMESA := wglGetProcAddress('glWindowPos3dMESA');
-    if not Assigned(glWindowPos3dMESA) then Exit;
-    glWindowPos3ivMESA := wglGetProcAddress('glWindowPos3ivMESA');
-    if not Assigned(glWindowPos3ivMESA) then Exit;
-    glWindowPos3svMESA := wglGetProcAddress('glWindowPos3svMESA');
-    if not Assigned(glWindowPos3svMESA) then Exit;
-    glWindowPos3fvMESA := wglGetProcAddress('glWindowPos3fvMESA');
-    if not Assigned(glWindowPos3fvMESA) then Exit;
-    glWindowPos3dvMESA := wglGetProcAddress('glWindowPos3dvMESA');
-    if not Assigned(glWindowPos3dvMESA) then Exit;
-    glWindowPos4iMESA := wglGetProcAddress('glWindowPos4iMESA');
-    if not Assigned(glWindowPos4iMESA) then Exit;
-    glWindowPos4sMESA := wglGetProcAddress('glWindowPos4sMESA');
-    if not Assigned(glWindowPos4sMESA) then Exit;
-    glWindowPos4fMESA := wglGetProcAddress('glWindowPos4fMESA');
-    if not Assigned(glWindowPos4fMESA) then Exit;
-    glWindowPos4dMESA := wglGetProcAddress('glWindowPos4dMESA');
-    if not Assigned(glWindowPos4dMESA) then Exit;
-    glWindowPos4ivMESA := wglGetProcAddress('glWindowPos4ivMESA');
-    if not Assigned(glWindowPos4ivMESA) then Exit;
-    glWindowPos4svMESA := wglGetProcAddress('glWindowPos4svMESA');
-    if not Assigned(glWindowPos4svMESA) then Exit;
-    glWindowPos4fvMESA := wglGetProcAddress('glWindowPos4fvMESA');
-    if not Assigned(glWindowPos4fvMESA) then Exit;
-    glWindowPos4dvMESA := wglGetProcAddress('glWindowPos4dvMESA');
-    if not Assigned(glWindowPos4dvMESA) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_OML_interlace: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_OML_interlace', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_OML_resample: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_OML_resample', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_OML_subsample: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_OML_subsample', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_generate_mipmap: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_generate_mipmap', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_multisample: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_multisample', extstring) then
-  begin
-    glSampleMaskSGIS := wglGetProcAddress('glSampleMaskSGIS');
-    if not Assigned(glSampleMaskSGIS) then Exit;
-    glSamplePatternSGIS := wglGetProcAddress('glSamplePatternSGIS');
-    if not Assigned(glSamplePatternSGIS) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_pixel_texture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_pixel_texture', extstring) then
-  begin
-    glPixelTexGenParameteriSGIS := wglGetProcAddress('glPixelTexGenParameteriSGIS');
-    if not Assigned(glPixelTexGenParameteriSGIS) then Exit;
-    glPixelTexGenParameterfSGIS := wglGetProcAddress('glPixelTexGenParameterfSGIS');
-    if not Assigned(glPixelTexGenParameterfSGIS) then Exit;
-    glGetPixelTexGenParameterivSGIS := wglGetProcAddress('glGetPixelTexGenParameterivSGIS');
-    if not Assigned(glGetPixelTexGenParameterivSGIS) then Exit;
-    glGetPixelTexGenParameterfvSGIS := wglGetProcAddress('glGetPixelTexGenParameterfvSGIS');
-    if not Assigned(glGetPixelTexGenParameterfvSGIS) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_texture_border_clamp: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_texture_border_clamp', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_texture_color_mask: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_texture_color_mask', extstring) then
-  begin
-    glTextureColorMaskSGIS := wglGetProcAddress('glTextureColorMaskSGIS');
-    if not Assigned(glTextureColorMaskSGIS) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_texture_edge_clamp: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_texture_edge_clamp', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_texture_lod: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_texture_lod', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIS_depth_texture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIS_depth_texture', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIX_fog_offset: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIX_fog_offset', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIX_interlace: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIX_interlace', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGIX_shadow_ambient: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGIX_shadow_ambient', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGI_color_matrix: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGI_color_matrix', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGI_color_table: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGI_color_table', extstring) then
-  begin
-    glColorTableSGI := wglGetProcAddress('glColorTableSGI');
-    if not Assigned(glColorTableSGI) then Exit;
-    glCopyColorTableSGI := wglGetProcAddress('glCopyColorTableSGI');
-    if not Assigned(glCopyColorTableSGI) then Exit;
-    glColorTableParameterivSGI := wglGetProcAddress('glColorTableParameterivSGI');
-    if not Assigned(glColorTableParameterivSGI) then Exit;
-    glColorTableParameterfvSGI := wglGetProcAddress('glColorTableParameterfvSGI');
-    if not Assigned(glColorTableParameterfvSGI) then Exit;
-    glGetColorTableSGI := wglGetProcAddress('glGetColorTableSGI');
-    if not Assigned(glGetColorTableSGI) then Exit;
-    glGetColorTableParameterivSGI := wglGetProcAddress('glGetColorTableParameterivSGI');
-    if not Assigned(glGetColorTableParameterivSGI) then Exit;
-    glGetColorTableParameterfvSGI := wglGetProcAddress('glGetColorTableParameterfvSGI');
-    if not Assigned(glGetColorTableParameterfvSGI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SGI_texture_color_table: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SGI_texture_color_table', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_SUN_vertex: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_SUN_vertex', extstring) then
-  begin
-    glColor4ubVertex2fSUN := wglGetProcAddress('glColor4ubVertex2fSUN');
-    if not Assigned(glColor4ubVertex2fSUN) then Exit;
-    glColor4ubVertex2fvSUN := wglGetProcAddress('glColor4ubVertex2fvSUN');
-    if not Assigned(glColor4ubVertex2fvSUN) then Exit;
-    glColor4ubVertex3fSUN := wglGetProcAddress('glColor4ubVertex3fSUN');
-    if not Assigned(glColor4ubVertex3fSUN) then Exit;
-    glColor4ubVertex3fvSUN := wglGetProcAddress('glColor4ubVertex3fvSUN');
-    if not Assigned(glColor4ubVertex3fvSUN) then Exit;
-    glColor3fVertex3fSUN := wglGetProcAddress('glColor3fVertex3fSUN');
-    if not Assigned(glColor3fVertex3fSUN) then Exit;
-    glColor3fVertex3fvSUN := wglGetProcAddress('glColor3fVertex3fvSUN');
-    if not Assigned(glColor3fVertex3fvSUN) then Exit;
-    glNormal3fVertex3fSUN := wglGetProcAddress('glNormal3fVertex3fSUN');
-    if not Assigned(glNormal3fVertex3fSUN) then Exit;
-    glNormal3fVertex3fvSUN := wglGetProcAddress('glNormal3fVertex3fvSUN');
-    if not Assigned(glNormal3fVertex3fvSUN) then Exit;
-    glColor4fNormal3fVertex3fSUN := wglGetProcAddress('glColor4fNormal3fVertex3fSUN');
-    if not Assigned(glColor4fNormal3fVertex3fSUN) then Exit;
-    glColor4fNormal3fVertex3fvSUN := wglGetProcAddress('glColor4fNormal3fVertex3fvSUN');
-    if not Assigned(glColor4fNormal3fVertex3fvSUN) then Exit;
-    glTexCoord2fVertex3fSUN := wglGetProcAddress('glTexCoord2fVertex3fSUN');
-    if not Assigned(glTexCoord2fVertex3fSUN) then Exit;
-    glTexCoord2fVertex3fvSUN := wglGetProcAddress('glTexCoord2fVertex3fvSUN');
-    if not Assigned(glTexCoord2fVertex3fvSUN) then Exit;
-    glTexCoord4fVertex4fSUN := wglGetProcAddress('glTexCoord4fVertex4fSUN');
-    if not Assigned(glTexCoord4fVertex4fSUN) then Exit;
-    glTexCoord4fVertex4fvSUN := wglGetProcAddress('glTexCoord4fVertex4fvSUN');
-    if not Assigned(glTexCoord4fVertex4fvSUN) then Exit;
-    glTexCoord2fColor4ubVertex3fSUN := wglGetProcAddress('glTexCoord2fColor4ubVertex3fSUN');
-    if not Assigned(glTexCoord2fColor4ubVertex3fSUN) then Exit;
-    glTexCoord2fColor4ubVertex3fvSUN := wglGetProcAddress('glTexCoord2fColor4ubVertex3fvSUN');
-    if not Assigned(glTexCoord2fColor4ubVertex3fvSUN) then Exit;
-    glTexCoord2fColor3fVertex3fSUN := wglGetProcAddress('glTexCoord2fColor3fVertex3fSUN');
-    if not Assigned(glTexCoord2fColor3fVertex3fSUN) then Exit;
-    glTexCoord2fColor3fVertex3fvSUN := wglGetProcAddress('glTexCoord2fColor3fVertex3fvSUN');
-    if not Assigned(glTexCoord2fColor3fVertex3fvSUN) then Exit;
-    glTexCoord2fNormal3fVertex3fSUN := wglGetProcAddress('glTexCoord2fNormal3fVertex3fSUN');
-    if not Assigned(glTexCoord2fNormal3fVertex3fSUN) then Exit;
-    glTexCoord2fNormal3fVertex3fvSUN := wglGetProcAddress('glTexCoord2fNormal3fVertex3fvSUN');
-    if not Assigned(glTexCoord2fNormal3fVertex3fvSUN) then Exit;
-    glTexCoord2fColor4fNormal3fVertex3fSUN := wglGetProcAddress('glTexCoord2fColor4fNormal3fVertex3fSUN');
-    if not Assigned(glTexCoord2fColor4fNormal3fVertex3fSUN) then Exit;
-    glTexCoord2fColor4fNormal3fVertex3fvSUN := wglGetProcAddress('glTexCoord2fColor4fNormal3fVertex3fvSUN');
-    if not Assigned(glTexCoord2fColor4fNormal3fVertex3fvSUN) then Exit;
-    glTexCoord4fColor4fNormal3fVertex4fSUN := wglGetProcAddress('glTexCoord4fColor4fNormal3fVertex4fSUN');
-    if not Assigned(glTexCoord4fColor4fNormal3fVertex4fSUN) then Exit;
-    glTexCoord4fColor4fNormal3fVertex4fvSUN := wglGetProcAddress('glTexCoord4fColor4fNormal3fVertex4fvSUN');
-    if not Assigned(glTexCoord4fColor4fNormal3fVertex4fvSUN) then Exit;
-    glReplacementCodeuiVertex3fSUN := wglGetProcAddress('glReplacementCodeuiVertex3fSUN');
-    if not Assigned(glReplacementCodeuiVertex3fSUN) then Exit;
-    glReplacementCodeuiVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiVertex3fvSUN) then Exit;
-    glReplacementCodeuiColor4ubVertex3fSUN := wglGetProcAddress('glReplacementCodeuiColor4ubVertex3fSUN');
-    if not Assigned(glReplacementCodeuiColor4ubVertex3fSUN) then Exit;
-    glReplacementCodeuiColor4ubVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiColor4ubVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiColor4ubVertex3fvSUN) then Exit;
-    glReplacementCodeuiColor3fVertex3fSUN := wglGetProcAddress('glReplacementCodeuiColor3fVertex3fSUN');
-    if not Assigned(glReplacementCodeuiColor3fVertex3fSUN) then Exit;
-    glReplacementCodeuiColor3fVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiColor3fVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiColor3fVertex3fvSUN) then Exit;
-    glReplacementCodeuiNormal3fVertex3fSUN := wglGetProcAddress('glReplacementCodeuiNormal3fVertex3fSUN');
-    if not Assigned(glReplacementCodeuiNormal3fVertex3fSUN) then Exit;
-    glReplacementCodeuiNormal3fVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiNormal3fVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiNormal3fVertex3fvSUN) then Exit;
-    glReplacementCodeuiColor4fNormal3fVertex3fSUN := wglGetProcAddress('glReplacementCodeuiColor4fNormal3fVertex3fSUN');
-    if not Assigned(glReplacementCodeuiColor4fNormal3fVertex3fSUN) then Exit;
-    glReplacementCodeuiColor4fNormal3fVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiColor4fNormal3fVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiColor4fNormal3fVertex3fvSUN) then Exit;
-    glReplacementCodeuiTexCoord2fVertex3fSUN := wglGetProcAddress('glReplacementCodeuiTexCoord2fVertex3fSUN');
-    if not Assigned(glReplacementCodeuiTexCoord2fVertex3fSUN) then Exit;
-    glReplacementCodeuiTexCoord2fVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiTexCoord2fVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiTexCoord2fVertex3fvSUN) then Exit;
-    glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN := wglGetProcAddress('glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN');
-    if not Assigned(glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN) then Exit;
-    glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN) then Exit;
-    glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN := wglGetProcAddress('glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN');
-    if not Assigned(glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN) then Exit;
-    glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN := wglGetProcAddress('glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN');
-    if not Assigned(glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_fragment_program: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_fragment_program', extstring) then
-  begin
-    glProgramStringARB := wglGetProcAddress('glProgramStringARB');
-    if not Assigned(glProgramStringARB) then Exit;
-    glBindProgramARB := wglGetProcAddress('glBindProgramARB');
-    if not Assigned(glBindProgramARB) then Exit;
-    glDeleteProgramsARB := wglGetProcAddress('glDeleteProgramsARB');
-    if not Assigned(glDeleteProgramsARB) then Exit;
-    glGenProgramsARB := wglGetProcAddress('glGenProgramsARB');
-    if not Assigned(glGenProgramsARB) then Exit;
-    glProgramEnvParameter4dARB := wglGetProcAddress('glProgramEnvParameter4dARB');
-    if not Assigned(glProgramEnvParameter4dARB) then Exit;
-    glProgramEnvParameter4dvARB := wglGetProcAddress('glProgramEnvParameter4dvARB');
-    if not Assigned(glProgramEnvParameter4dvARB) then Exit;
-    glProgramEnvParameter4fARB := wglGetProcAddress('glProgramEnvParameter4fARB');
-    if not Assigned(glProgramEnvParameter4fARB) then Exit;
-    glProgramEnvParameter4fvARB := wglGetProcAddress('glProgramEnvParameter4fvARB');
-    if not Assigned(glProgramEnvParameter4fvARB) then Exit;
-    glProgramLocalParameter4dARB := wglGetProcAddress('glProgramLocalParameter4dARB');
-    if not Assigned(glProgramLocalParameter4dARB) then Exit;
-    glProgramLocalParameter4dvARB := wglGetProcAddress('glProgramLocalParameter4dvARB');
-    if not Assigned(glProgramLocalParameter4dvARB) then Exit;
-    glProgramLocalParameter4fARB := wglGetProcAddress('glProgramLocalParameter4fARB');
-    if not Assigned(glProgramLocalParameter4fARB) then Exit;
-    glProgramLocalParameter4fvARB := wglGetProcAddress('glProgramLocalParameter4fvARB');
-    if not Assigned(glProgramLocalParameter4fvARB) then Exit;
-    glGetProgramEnvParameterdvARB := wglGetProcAddress('glGetProgramEnvParameterdvARB');
-    if not Assigned(glGetProgramEnvParameterdvARB) then Exit;
-    glGetProgramEnvParameterfvARB := wglGetProcAddress('glGetProgramEnvParameterfvARB');
-    if not Assigned(glGetProgramEnvParameterfvARB) then Exit;
-    glGetProgramLocalParameterdvARB := wglGetProcAddress('glGetProgramLocalParameterdvARB');
-    if not Assigned(glGetProgramLocalParameterdvARB) then Exit;
-    glGetProgramLocalParameterfvARB := wglGetProcAddress('glGetProgramLocalParameterfvARB');
-    if not Assigned(glGetProgramLocalParameterfvARB) then Exit;
-    glGetProgramivARB := wglGetProcAddress('glGetProgramivARB');
-    if not Assigned(glGetProgramivARB) then Exit;
-    glGetProgramStringARB := wglGetProcAddress('glGetProgramStringARB');
-    if not Assigned(glGetProgramStringARB) then Exit;
-    glIsProgramARB := wglGetProcAddress('glIsProgramARB');
-    if not Assigned(glIsProgramARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_text_fragment_shader: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_text_fragment_shader', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_APPLE_client_storage: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_APPLE_client_storage', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_APPLE_element_array: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_APPLE_element_array', extstring) then
-  begin
-    glElementPointerAPPLE := wglGetProcAddress('glElementPointerAPPLE');
-    if not Assigned(glElementPointerAPPLE) then Exit;
-    glDrawElementArrayAPPLE := wglGetProcAddress('glDrawElementArrayAPPLE');
-    if not Assigned(glDrawElementArrayAPPLE) then Exit;
-    glDrawRangeElementArrayAPPLE := wglGetProcAddress('glDrawRangeElementArrayAPPLE');
-    if not Assigned(glDrawRangeElementArrayAPPLE) then Exit;
-    glMultiDrawElementArrayAPPLE := wglGetProcAddress('glMultiDrawElementArrayAPPLE');
-    if not Assigned(glMultiDrawElementArrayAPPLE) then Exit;
-    glMultiDrawRangeElementArrayAPPLE := wglGetProcAddress('glMultiDrawRangeElementArrayAPPLE');
-    if not Assigned(glMultiDrawRangeElementArrayAPPLE) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_APPLE_fence: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_APPLE_fence', extstring) then
-  begin
-    glGenFencesAPPLE := wglGetProcAddress('glGenFencesAPPLE');
-    if not Assigned(glGenFencesAPPLE) then Exit;
-    glDeleteFencesAPPLE := wglGetProcAddress('glDeleteFencesAPPLE');
-    if not Assigned(glDeleteFencesAPPLE) then Exit;
-    glSetFenceAPPLE := wglGetProcAddress('glSetFenceAPPLE');
-    if not Assigned(glSetFenceAPPLE) then Exit;
-    glIsFenceAPPLE := wglGetProcAddress('glIsFenceAPPLE');
-    if not Assigned(glIsFenceAPPLE) then Exit;
-    glTestFenceAPPLE := wglGetProcAddress('glTestFenceAPPLE');
-    if not Assigned(glTestFenceAPPLE) then Exit;
-    glFinishFenceAPPLE := wglGetProcAddress('glFinishFenceAPPLE');
-    if not Assigned(glFinishFenceAPPLE) then Exit;
-    glTestObjectAPPLE := wglGetProcAddress('glTestObjectAPPLE');
-    if not Assigned(glTestObjectAPPLE) then Exit;
-    glFinishObjectAPPLE := wglGetProcAddress('glFinishObjectAPPLE');
-    if not Assigned(glFinishObjectAPPLE) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_APPLE_vertex_array_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_APPLE_vertex_array_object', extstring) then
-  begin
-    glBindVertexArrayAPPLE := wglGetProcAddress('glBindVertexArrayAPPLE');
-    if not Assigned(glBindVertexArrayAPPLE) then Exit;
-    glDeleteVertexArraysAPPLE := wglGetProcAddress('glDeleteVertexArraysAPPLE');
-    if not Assigned(glDeleteVertexArraysAPPLE) then Exit;
-    glGenVertexArraysAPPLE := wglGetProcAddress('glGenVertexArraysAPPLE');
-    if not Assigned(glGenVertexArraysAPPLE) then Exit;
-    glIsVertexArrayAPPLE := wglGetProcAddress('glIsVertexArrayAPPLE');
-    if not Assigned(glIsVertexArrayAPPLE) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_APPLE_vertex_array_range: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_APPLE_vertex_array_range', extstring) then
-  begin
-    glVertexArrayRangeAPPLE := wglGetProcAddress('glVertexArrayRangeAPPLE');
-    if not Assigned(glVertexArrayRangeAPPLE) then Exit;
-    glFlushVertexArrayRangeAPPLE := wglGetProcAddress('glFlushVertexArrayRangeAPPLE');
-    if not Assigned(glFlushVertexArrayRangeAPPLE) then Exit;
-    glVertexArrayParameteriAPPLE := wglGetProcAddress('glVertexArrayParameteriAPPLE');
-    if not Assigned(glVertexArrayParameteriAPPLE) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_ARB_pixel_format: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_ARB_pixel_format', extstring) then
-  begin
-    wglGetPixelFormatAttribivARB := wglGetProcAddress('wglGetPixelFormatAttribivARB');
-    if not Assigned(wglGetPixelFormatAttribivARB) then Exit;
-    wglGetPixelFormatAttribfvARB := wglGetProcAddress('wglGetPixelFormatAttribfvARB');
-    if not Assigned(wglGetPixelFormatAttribfvARB) then Exit;
-    wglChoosePixelFormatARB := wglGetProcAddress('wglChoosePixelFormatARB');
-    if not Assigned(wglChoosePixelFormatARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_ARB_make_current_read: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_ARB_make_current_read', extstring) then
-  begin
-    wglMakeContextCurrentARB := wglGetProcAddress('wglMakeContextCurrentARB');
-    if not Assigned(wglMakeContextCurrentARB) then Exit;
-    wglGetCurrentReadDCARB := wglGetProcAddress('wglGetCurrentReadDCARB');
-    if not Assigned(wglGetCurrentReadDCARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_ARB_pbuffer: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_ARB_pbuffer', extstring) then
-  begin
-    wglCreatePbufferARB := wglGetProcAddress('wglCreatePbufferARB');
-    if not Assigned(wglCreatePbufferARB) then Exit;
-    wglGetPbufferDCARB := wglGetProcAddress('wglGetPbufferDCARB');
-    if not Assigned(wglGetPbufferDCARB) then Exit;
-    wglReleasePbufferDCARB := wglGetProcAddress('wglReleasePbufferDCARB');
-    if not Assigned(wglReleasePbufferDCARB) then Exit;
-    wglDestroyPbufferARB := wglGetProcAddress('wglDestroyPbufferARB');
-    if not Assigned(wglDestroyPbufferARB) then Exit;
-    wglQueryPbufferARB := wglGetProcAddress('wglQueryPbufferARB');
-    if not Assigned(wglQueryPbufferARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_EXT_swap_control: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_EXT_swap_control', extstring) then
-  begin
-    wglSwapIntervalEXT := wglGetProcAddress('wglSwapIntervalEXT');
-    if not Assigned(wglSwapIntervalEXT) then Exit;
-    wglGetSwapIntervalEXT := wglGetProcAddress('wglGetSwapIntervalEXT');
-    if not Assigned(wglGetSwapIntervalEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_ARB_render_texture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_ARB_render_texture', extstring) then
-  begin
-    wglBindTexImageARB := wglGetProcAddress('wglBindTexImageARB');
-    if not Assigned(wglBindTexImageARB) then Exit;
-    wglReleaseTexImageARB := wglGetProcAddress('wglReleaseTexImageARB');
-    if not Assigned(wglReleaseTexImageARB) then Exit;
-    wglSetPbufferAttribARB := wglGetProcAddress('wglSetPbufferAttribARB');
-    if not Assigned(wglSetPbufferAttribARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_EXT_extensions_string: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_EXT_extensions_string', extstring) then
-  begin
-    wglGetExtensionsStringEXT := wglGetProcAddress('wglGetExtensionsStringEXT');
-    if not Assigned(wglGetExtensionsStringEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_EXT_make_current_read: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_EXT_make_current_read', extstring) then
-  begin
-    wglMakeContextCurrentEXT := wglGetProcAddress('wglMakeContextCurrentEXT');
-    if not Assigned(wglMakeContextCurrentEXT) then Exit;
-    wglGetCurrentReadDCEXT := wglGetProcAddress('wglGetCurrentReadDCEXT');
-    if not Assigned(wglGetCurrentReadDCEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_EXT_pbuffer: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_EXT_pbuffer', extstring) then
-  begin
-    wglCreatePbufferEXT := wglGetProcAddress('wglCreatePbufferEXT');
-    if not Assigned(wglCreatePbufferEXT) then Exit;
-    wglGetPbufferDCEXT := wglGetProcAddress('wglGetPbufferDCEXT');
-    if not Assigned(wglGetPbufferDCEXT) then Exit;
-    wglReleasePbufferDCEXT := wglGetProcAddress('wglReleasePbufferDCEXT');
-    if not Assigned(wglReleasePbufferDCEXT) then Exit;
-    wglDestroyPbufferEXT := wglGetProcAddress('wglDestroyPbufferEXT');
-    if not Assigned(wglDestroyPbufferEXT) then Exit;
-    wglQueryPbufferEXT := wglGetProcAddress('wglQueryPbufferEXT');
-    if not Assigned(wglQueryPbufferEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_EXT_pixel_format: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_EXT_pixel_format', extstring) then
-  begin
-    wglGetPixelFormatAttribivEXT := wglGetProcAddress('wglGetPixelFormatAttribivEXT');
-    if not Assigned(wglGetPixelFormatAttribivEXT) then Exit;
-    wglGetPixelFormatAttribfvEXT := wglGetProcAddress('wglGetPixelFormatAttribfvEXT');
-    if not Assigned(wglGetPixelFormatAttribfvEXT) then Exit;
-    wglChoosePixelFormatEXT := wglGetProcAddress('wglChoosePixelFormatEXT');
-    if not Assigned(wglChoosePixelFormatEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_I3D_digital_video_control: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_I3D_digital_video_control', extstring) then
-  begin
-    wglGetDigitalVideoParametersI3D := wglGetProcAddress('wglGetDigitalVideoParametersI3D');
-    if not Assigned(wglGetDigitalVideoParametersI3D) then Exit;
-    wglSetDigitalVideoParametersI3D := wglGetProcAddress('wglSetDigitalVideoParametersI3D');
-    if not Assigned(wglSetDigitalVideoParametersI3D) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_I3D_gamma: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_I3D_gamma', extstring) then
-  begin
-    wglGetGammaTableParametersI3D := wglGetProcAddress('wglGetGammaTableParametersI3D');
-    if not Assigned(wglGetGammaTableParametersI3D) then Exit;
-    wglSetGammaTableParametersI3D := wglGetProcAddress('wglSetGammaTableParametersI3D');
-    if not Assigned(wglSetGammaTableParametersI3D) then Exit;
-    wglGetGammaTableI3D := wglGetProcAddress('wglGetGammaTableI3D');
-    if not Assigned(wglGetGammaTableI3D) then Exit;
-    wglSetGammaTableI3D := wglGetProcAddress('wglSetGammaTableI3D');
-    if not Assigned(wglSetGammaTableI3D) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_I3D_genlock: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_I3D_genlock', extstring) then
-  begin
-    wglEnableGenlockI3D := wglGetProcAddress('wglEnableGenlockI3D');
-    if not Assigned(wglEnableGenlockI3D) then Exit;
-    wglDisableGenlockI3D := wglGetProcAddress('wglDisableGenlockI3D');
-    if not Assigned(wglDisableGenlockI3D) then Exit;
-    wglIsEnabledGenlockI3D := wglGetProcAddress('wglIsEnabledGenlockI3D');
-    if not Assigned(wglIsEnabledGenlockI3D) then Exit;
-    wglGenlockSourceI3D := wglGetProcAddress('wglGenlockSourceI3D');
-    if not Assigned(wglGenlockSourceI3D) then Exit;
-    wglGetGenlockSourceI3D := wglGetProcAddress('wglGetGenlockSourceI3D');
-    if not Assigned(wglGetGenlockSourceI3D) then Exit;
-    wglGenlockSourceEdgeI3D := wglGetProcAddress('wglGenlockSourceEdgeI3D');
-    if not Assigned(wglGenlockSourceEdgeI3D) then Exit;
-    wglGetGenlockSourceEdgeI3D := wglGetProcAddress('wglGetGenlockSourceEdgeI3D');
-    if not Assigned(wglGetGenlockSourceEdgeI3D) then Exit;
-    wglGenlockSampleRateI3D := wglGetProcAddress('wglGenlockSampleRateI3D');
-    if not Assigned(wglGenlockSampleRateI3D) then Exit;
-    wglGetGenlockSampleRateI3D := wglGetProcAddress('wglGetGenlockSampleRateI3D');
-    if not Assigned(wglGetGenlockSampleRateI3D) then Exit;
-    wglGenlockSourceDelayI3D := wglGetProcAddress('wglGenlockSourceDelayI3D');
-    if not Assigned(wglGenlockSourceDelayI3D) then Exit;
-    wglGetGenlockSourceDelayI3D := wglGetProcAddress('wglGetGenlockSourceDelayI3D');
-    if not Assigned(wglGetGenlockSourceDelayI3D) then Exit;
-    wglQueryGenlockMaxSourceDelayI3D := wglGetProcAddress('wglQueryGenlockMaxSourceDelayI3D');
-    if not Assigned(wglQueryGenlockMaxSourceDelayI3D) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_matrix_palette: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_matrix_palette', extstring) then
-  begin
-    glCurrentPaletteMatrixARB := wglGetProcAddress('glCurrentPaletteMatrixARB');
-    if not Assigned(glCurrentPaletteMatrixARB) then Exit;
-    glMatrixIndexubvARB := wglGetProcAddress('glMatrixIndexubvARB');
-    if not Assigned(glMatrixIndexubvARB) then Exit;
-    glMatrixIndexusvARB := wglGetProcAddress('glMatrixIndexusvARB');
-    if not Assigned(glMatrixIndexusvARB) then Exit;
-    glMatrixIndexuivARB := wglGetProcAddress('glMatrixIndexuivARB');
-    if not Assigned(glMatrixIndexuivARB) then Exit;
-    glMatrixIndexPointerARB := wglGetProcAddress('glMatrixIndexPointerARB');
-    if not Assigned(glMatrixIndexPointerARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_element_array: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_element_array', extstring) then
-  begin
-    glElementPointerNV := wglGetProcAddress('glElementPointerNV');
-    if not Assigned(glElementPointerNV) then Exit;
-    glDrawElementArrayNV := wglGetProcAddress('glDrawElementArrayNV');
-    if not Assigned(glDrawElementArrayNV) then Exit;
-    glDrawRangeElementArrayNV := wglGetProcAddress('glDrawRangeElementArrayNV');
-    if not Assigned(glDrawRangeElementArrayNV) then Exit;
-    glMultiDrawElementArrayNV := wglGetProcAddress('glMultiDrawElementArrayNV');
-    if not Assigned(glMultiDrawElementArrayNV) then Exit;
-    glMultiDrawRangeElementArrayNV := wglGetProcAddress('glMultiDrawRangeElementArrayNV');
-    if not Assigned(glMultiDrawRangeElementArrayNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_float_buffer: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_float_buffer', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_fragment_program: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_fragment_program', extstring) then
-  begin
-    glProgramNamedParameter4fNV := wglGetProcAddress('glProgramNamedParameter4fNV');
-    if not Assigned(glProgramNamedParameter4fNV) then Exit;
-    glProgramNamedParameter4dNV := wglGetProcAddress('glProgramNamedParameter4dNV');
-    if not Assigned(glProgramNamedParameter4dNV) then Exit;
-    glGetProgramNamedParameterfvNV := wglGetProcAddress('glGetProgramNamedParameterfvNV');
-    if not Assigned(glGetProgramNamedParameterfvNV) then Exit;
-    glGetProgramNamedParameterdvNV := wglGetProcAddress('glGetProgramNamedParameterdvNV');
-    if not Assigned(glGetProgramNamedParameterdvNV) then Exit;
-    glProgramLocalParameter4dARB := wglGetProcAddress('glProgramLocalParameter4dARB');
-    if not Assigned(glProgramLocalParameter4dARB) then Exit;
-    glProgramLocalParameter4dvARB := wglGetProcAddress('glProgramLocalParameter4dvARB');
-    if not Assigned(glProgramLocalParameter4dvARB) then Exit;
-    glProgramLocalParameter4fARB := wglGetProcAddress('glProgramLocalParameter4fARB');
-    if not Assigned(glProgramLocalParameter4fARB) then Exit;
-    glProgramLocalParameter4fvARB := wglGetProcAddress('glProgramLocalParameter4fvARB');
-    if not Assigned(glProgramLocalParameter4fvARB) then Exit;
-    glGetProgramLocalParameterdvARB := wglGetProcAddress('glGetProgramLocalParameterdvARB');
-    if not Assigned(glGetProgramLocalParameterdvARB) then Exit;
-    glGetProgramLocalParameterfvARB := wglGetProcAddress('glGetProgramLocalParameterfvARB');
-    if not Assigned(glGetProgramLocalParameterfvARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_primitive_restart: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_primitive_restart', extstring) then
-  begin
-    glPrimitiveRestartNV := wglGetProcAddress('glPrimitiveRestartNV');
-    if not Assigned(glPrimitiveRestartNV) then Exit;
-    glPrimitiveRestartIndexNV := wglGetProcAddress('glPrimitiveRestartIndexNV');
-    if not Assigned(glPrimitiveRestartIndexNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_vertex_program2: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_vertex_program2', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_NV_render_texture_rectangle: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_NV_render_texture_rectangle', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_pixel_data_range: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_pixel_data_range', extstring) then
-  begin
-    glPixelDataRangeNV := wglGetProcAddress('glPixelDataRangeNV');
-    if not Assigned(glPixelDataRangeNV) then Exit;
-    glFlushPixelDataRangeNV := wglGetProcAddress('glFlushPixelDataRangeNV');
-    if not Assigned(glFlushPixelDataRangeNV) then Exit;
-    wglAllocateMemoryNV := wglGetProcAddress('wglAllocateMemoryNV');
-    if not Assigned(wglAllocateMemoryNV) then Exit;
-    wglFreeMemoryNV := wglGetProcAddress('wglFreeMemoryNV');
-    if not Assigned(wglFreeMemoryNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_rectangle: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_rectangle', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_S3_s3tc: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_S3_s3tc', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_draw_buffers: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_draw_buffers', extstring) then
-  begin
-    glDrawBuffersATI := wglGetProcAddress('glDrawBuffersATI');
-    if not Assigned(glDrawBuffersATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_WGL_ATI_pixel_format_float: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  wglGetExtensionsStringARB := wglGetProcAddress('wglGetExtensionsStringARB');
-  if not Assigned(wglGetExtensionsStringARB) then Exit;
-  extstring := String(PChar(wglGetExtensionsStringARB(wglGetCurrentDC)));
-
-  if glext_ExtensionSupported('WGL_ATI_pixel_format_float', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_texture_env_combine3: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_texture_env_combine3', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_texture_float: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_texture_float', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_texture_expand_normal: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_texture_expand_normal', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_half_float: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_half_float', extstring) then
-  begin
-    glVertex2hNV := wglGetProcAddress('glVertex2hNV');
-    if not Assigned(glVertex2hNV) then Exit;
-    glVertex2hvNV := wglGetProcAddress('glVertex2hvNV');
-    if not Assigned(glVertex2hvNV) then Exit;
-    glVertex3hNV := wglGetProcAddress('glVertex3hNV');
-    if not Assigned(glVertex3hNV) then Exit;
-    glVertex3hvNV := wglGetProcAddress('glVertex3hvNV');
-    if not Assigned(glVertex3hvNV) then Exit;
-    glVertex4hNV := wglGetProcAddress('glVertex4hNV');
-    if not Assigned(glVertex4hNV) then Exit;
-    glVertex4hvNV := wglGetProcAddress('glVertex4hvNV');
-    if not Assigned(glVertex4hvNV) then Exit;
-    glNormal3hNV := wglGetProcAddress('glNormal3hNV');
-    if not Assigned(glNormal3hNV) then Exit;
-    glNormal3hvNV := wglGetProcAddress('glNormal3hvNV');
-    if not Assigned(glNormal3hvNV) then Exit;
-    glColor3hNV := wglGetProcAddress('glColor3hNV');
-    if not Assigned(glColor3hNV) then Exit;
-    glColor3hvNV := wglGetProcAddress('glColor3hvNV');
-    if not Assigned(glColor3hvNV) then Exit;
-    glColor4hNV := wglGetProcAddress('glColor4hNV');
-    if not Assigned(glColor4hNV) then Exit;
-    glColor4hvNV := wglGetProcAddress('glColor4hvNV');
-    if not Assigned(glColor4hvNV) then Exit;
-    glTexCoord1hNV := wglGetProcAddress('glTexCoord1hNV');
-    if not Assigned(glTexCoord1hNV) then Exit;
-    glTexCoord1hvNV := wglGetProcAddress('glTexCoord1hvNV');
-    if not Assigned(glTexCoord1hvNV) then Exit;
-    glTexCoord2hNV := wglGetProcAddress('glTexCoord2hNV');
-    if not Assigned(glTexCoord2hNV) then Exit;
-    glTexCoord2hvNV := wglGetProcAddress('glTexCoord2hvNV');
-    if not Assigned(glTexCoord2hvNV) then Exit;
-    glTexCoord3hNV := wglGetProcAddress('glTexCoord3hNV');
-    if not Assigned(glTexCoord3hNV) then Exit;
-    glTexCoord3hvNV := wglGetProcAddress('glTexCoord3hvNV');
-    if not Assigned(glTexCoord3hvNV) then Exit;
-    glTexCoord4hNV := wglGetProcAddress('glTexCoord4hNV');
-    if not Assigned(glTexCoord4hNV) then Exit;
-    glTexCoord4hvNV := wglGetProcAddress('glTexCoord4hvNV');
-    if not Assigned(glTexCoord4hvNV) then Exit;
-    glMultiTexCoord1hNV := wglGetProcAddress('glMultiTexCoord1hNV');
-    if not Assigned(glMultiTexCoord1hNV) then Exit;
-    glMultiTexCoord1hvNV := wglGetProcAddress('glMultiTexCoord1hvNV');
-    if not Assigned(glMultiTexCoord1hvNV) then Exit;
-    glMultiTexCoord2hNV := wglGetProcAddress('glMultiTexCoord2hNV');
-    if not Assigned(glMultiTexCoord2hNV) then Exit;
-    glMultiTexCoord2hvNV := wglGetProcAddress('glMultiTexCoord2hvNV');
-    if not Assigned(glMultiTexCoord2hvNV) then Exit;
-    glMultiTexCoord3hNV := wglGetProcAddress('glMultiTexCoord3hNV');
-    if not Assigned(glMultiTexCoord3hNV) then Exit;
-    glMultiTexCoord3hvNV := wglGetProcAddress('glMultiTexCoord3hvNV');
-    if not Assigned(glMultiTexCoord3hvNV) then Exit;
-    glMultiTexCoord4hNV := wglGetProcAddress('glMultiTexCoord4hNV');
-    if not Assigned(glMultiTexCoord4hNV) then Exit;
-    glMultiTexCoord4hvNV := wglGetProcAddress('glMultiTexCoord4hvNV');
-    if not Assigned(glMultiTexCoord4hvNV) then Exit;
-    glFogCoordhNV := wglGetProcAddress('glFogCoordhNV');
-    if not Assigned(glFogCoordhNV) then Exit;
-    glFogCoordhvNV := wglGetProcAddress('glFogCoordhvNV');
-    if not Assigned(glFogCoordhvNV) then Exit;
-    glSecondaryColor3hNV := wglGetProcAddress('glSecondaryColor3hNV');
-    if not Assigned(glSecondaryColor3hNV) then Exit;
-    glSecondaryColor3hvNV := wglGetProcAddress('glSecondaryColor3hvNV');
-    if not Assigned(glSecondaryColor3hvNV) then Exit;
-    glVertexWeighthNV := wglGetProcAddress('glVertexWeighthNV');
-    if not Assigned(glVertexWeighthNV) then Exit;
-    glVertexWeighthvNV := wglGetProcAddress('glVertexWeighthvNV');
-    if not Assigned(glVertexWeighthvNV) then Exit;
-    glVertexAttrib1hNV := wglGetProcAddress('glVertexAttrib1hNV');
-    if not Assigned(glVertexAttrib1hNV) then Exit;
-    glVertexAttrib1hvNV := wglGetProcAddress('glVertexAttrib1hvNV');
-    if not Assigned(glVertexAttrib1hvNV) then Exit;
-    glVertexAttrib2hNV := wglGetProcAddress('glVertexAttrib2hNV');
-    if not Assigned(glVertexAttrib2hNV) then Exit;
-    glVertexAttrib2hvNV := wglGetProcAddress('glVertexAttrib2hvNV');
-    if not Assigned(glVertexAttrib2hvNV) then Exit;
-    glVertexAttrib3hNV := wglGetProcAddress('glVertexAttrib3hNV');
-    if not Assigned(glVertexAttrib3hNV) then Exit;
-    glVertexAttrib3hvNV := wglGetProcAddress('glVertexAttrib3hvNV');
-    if not Assigned(glVertexAttrib3hvNV) then Exit;
-    glVertexAttrib4hNV := wglGetProcAddress('glVertexAttrib4hNV');
-    if not Assigned(glVertexAttrib4hNV) then Exit;
-    glVertexAttrib4hvNV := wglGetProcAddress('glVertexAttrib4hvNV');
-    if not Assigned(glVertexAttrib4hvNV) then Exit;
-    glVertexAttribs1hvNV := wglGetProcAddress('glVertexAttribs1hvNV');
-    if not Assigned(glVertexAttribs1hvNV) then Exit;
-    glVertexAttribs2hvNV := wglGetProcAddress('glVertexAttribs2hvNV');
-    if not Assigned(glVertexAttribs2hvNV) then Exit;
-    glVertexAttribs3hvNV := wglGetProcAddress('glVertexAttribs3hvNV');
-    if not Assigned(glVertexAttribs3hvNV) then Exit;
-    glVertexAttribs4hvNV := wglGetProcAddress('glVertexAttribs4hvNV');
-    if not Assigned(glVertexAttribs4hvNV) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_map_object_buffer: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_map_object_buffer', extstring) then
-  begin
-    glMapObjectBufferATI := wglGetProcAddress('glMapObjectBufferATI');
-    if not Assigned(glMapObjectBufferATI) then Exit;
-    glUnmapObjectBufferATI := wglGetProcAddress('glUnmapObjectBufferATI');
-    if not Assigned(glUnmapObjectBufferATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_separate_stencil: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_separate_stencil', extstring) then
-  begin
-    glStencilOpSeparateATI := wglGetProcAddress('glStencilOpSeparateATI');
-    if not Assigned(glStencilOpSeparateATI) then Exit;
-    glStencilFuncSeparateATI := wglGetProcAddress('glStencilFuncSeparateATI');
-    if not Assigned(glStencilFuncSeparateATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ATI_vertex_attrib_array_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ATI_vertex_attrib_array_object', extstring) then
-  begin
-    glVertexAttribArrayObjectATI := wglGetProcAddress('glVertexAttribArrayObjectATI');
-    if not Assigned(glVertexAttribArrayObjectATI) then Exit;
-    glGetVertexAttribArrayObjectfvATI := wglGetProcAddress('glGetVertexAttribArrayObjectfvATI');
-    if not Assigned(glGetVertexAttribArrayObjectfvATI) then Exit;
-    glGetVertexAttribArrayObjectivATI := wglGetProcAddress('glGetVertexAttribArrayObjectivATI');
-    if not Assigned(glGetVertexAttribArrayObjectivATI) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_vertex_buffer_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_vertex_buffer_object', extstring) then
-  begin
-    glBindBufferARB := wglGetProcAddress('glBindBufferARB');
-    if not Assigned(glBindBufferARB) then Exit;
-    glDeleteBuffersARB := wglGetProcAddress('glDeleteBuffersARB');
-    if not Assigned(glDeleteBuffersARB) then Exit;
-    glGenBuffersARB := wglGetProcAddress('glGenBuffersARB');
-    if not Assigned(glGenBuffersARB) then Exit;
-    glIsBufferARB := wglGetProcAddress('glIsBufferARB');
-    if not Assigned(glIsBufferARB) then Exit;
-    glBufferDataARB := wglGetProcAddress('glBufferDataARB');
-    if not Assigned(glBufferDataARB) then Exit;
-    glBufferSubDataARB := wglGetProcAddress('glBufferSubDataARB');
-    if not Assigned(glBufferSubDataARB) then Exit;
-    glGetBufferSubDataARB := wglGetProcAddress('glGetBufferSubDataARB');
-    if not Assigned(glGetBufferSubDataARB) then Exit;
-    glMapBufferARB := wglGetProcAddress('glMapBufferARB');
-    if not Assigned(glMapBufferARB) then Exit;
-    glUnmapBufferARB := wglGetProcAddress('glUnmapBufferARB');
-    if not Assigned(glUnmapBufferARB) then Exit;
-    glGetBufferParameterivARB := wglGetProcAddress('glGetBufferParameterivARB');
-    if not Assigned(glGetBufferParameterivARB) then Exit;
-    glGetBufferPointervARB := wglGetProcAddress('glGetBufferPointervARB');
-    if not Assigned(glGetBufferPointervARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_occlusion_query: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_occlusion_query', extstring) then
-  begin
-    glGenQueriesARB := wglGetProcAddress('glGenQueriesARB');
-    if not Assigned(glGenQueriesARB) then Exit;
-    glDeleteQueriesARB := wglGetProcAddress('glDeleteQueriesARB');
-    if not Assigned(glDeleteQueriesARB) then Exit;
-    glIsQueryARB := wglGetProcAddress('glIsQueryARB');
-    if not Assigned(glIsQueryARB) then Exit;
-    glBeginQueryARB := wglGetProcAddress('glBeginQueryARB');
-    if not Assigned(glBeginQueryARB) then Exit;
-    glEndQueryARB := wglGetProcAddress('glEndQueryARB');
-    if not Assigned(glEndQueryARB) then Exit;
-    glGetQueryivARB := wglGetProcAddress('glGetQueryivARB');
-    if not Assigned(glGetQueryivARB) then Exit;
-    glGetQueryObjectivARB := wglGetProcAddress('glGetQueryObjectivARB');
-    if not Assigned(glGetQueryObjectivARB) then Exit;
-    glGetQueryObjectuivARB := wglGetProcAddress('glGetQueryObjectuivARB');
-    if not Assigned(glGetQueryObjectuivARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_shader_objects: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_shader_objects', extstring) then
-  begin
-    glDeleteObjectARB := wglGetProcAddress('glDeleteObjectARB');
-    if not Assigned(glDeleteObjectARB) then Exit;
-    glGetHandleARB := wglGetProcAddress('glGetHandleARB');
-    if not Assigned(glGetHandleARB) then Exit;
-    glDetachObjectARB := wglGetProcAddress('glDetachObjectARB');
-    if not Assigned(glDetachObjectARB) then Exit;
-    glCreateShaderObjectARB := wglGetProcAddress('glCreateShaderObjectARB');
-    if not Assigned(glCreateShaderObjectARB) then Exit;
-    glShaderSourceARB := wglGetProcAddress('glShaderSourceARB');
-    if not Assigned(glShaderSourceARB) then Exit;
-    glCompileShaderARB := wglGetProcAddress('glCompileShaderARB');
-    if not Assigned(glCompileShaderARB) then Exit;
-    glCreateProgramObjectARB := wglGetProcAddress('glCreateProgramObjectARB');
-    if not Assigned(glCreateProgramObjectARB) then Exit;
-    glAttachObjectARB := wglGetProcAddress('glAttachObjectARB');
-    if not Assigned(glAttachObjectARB) then Exit;
-    glLinkProgramARB := wglGetProcAddress('glLinkProgramARB');
-    if not Assigned(glLinkProgramARB) then Exit;
-    glUseProgramObjectARB := wglGetProcAddress('glUseProgramObjectARB');
-    if not Assigned(glUseProgramObjectARB) then Exit;
-    glValidateProgramARB := wglGetProcAddress('glValidateProgramARB');
-    if not Assigned(glValidateProgramARB) then Exit;
-    glUniform1fARB := wglGetProcAddress('glUniform1fARB');
-    if not Assigned(glUniform1fARB) then Exit;
-    glUniform2fARB := wglGetProcAddress('glUniform2fARB');
-    if not Assigned(glUniform2fARB) then Exit;
-    glUniform3fARB := wglGetProcAddress('glUniform3fARB');
-    if not Assigned(glUniform3fARB) then Exit;
-    glUniform4fARB := wglGetProcAddress('glUniform4fARB');
-    if not Assigned(glUniform4fARB) then Exit;
-    glUniform1iARB := wglGetProcAddress('glUniform1iARB');
-    if not Assigned(glUniform1iARB) then Exit;
-    glUniform2iARB := wglGetProcAddress('glUniform2iARB');
-    if not Assigned(glUniform2iARB) then Exit;
-    glUniform3iARB := wglGetProcAddress('glUniform3iARB');
-    if not Assigned(glUniform3iARB) then Exit;
-    glUniform4iARB := wglGetProcAddress('glUniform4iARB');
-    if not Assigned(glUniform4iARB) then Exit;
-    glUniform1fvARB := wglGetProcAddress('glUniform1fvARB');
-    if not Assigned(glUniform1fvARB) then Exit;
-    glUniform2fvARB := wglGetProcAddress('glUniform2fvARB');
-    if not Assigned(glUniform2fvARB) then Exit;
-    glUniform3fvARB := wglGetProcAddress('glUniform3fvARB');
-    if not Assigned(glUniform3fvARB) then Exit;
-    glUniform4fvARB := wglGetProcAddress('glUniform4fvARB');
-    if not Assigned(glUniform4fvARB) then Exit;
-    glUniform1ivARB := wglGetProcAddress('glUniform1ivARB');
-    if not Assigned(glUniform1ivARB) then Exit;
-    glUniform2ivARB := wglGetProcAddress('glUniform2ivARB');
-    if not Assigned(glUniform2ivARB) then Exit;
-    glUniform3ivARB := wglGetProcAddress('glUniform3ivARB');
-    if not Assigned(glUniform3ivARB) then Exit;
-    glUniform4ivARB := wglGetProcAddress('glUniform4ivARB');
-    if not Assigned(glUniform4ivARB) then Exit;
-    glUniformMatrix2fvARB := wglGetProcAddress('glUniformMatrix2fvARB');
-    if not Assigned(glUniformMatrix2fvARB) then Exit;
-    glUniformMatrix3fvARB := wglGetProcAddress('glUniformMatrix3fvARB');
-    if not Assigned(glUniformMatrix3fvARB) then Exit;
-    glUniformMatrix4fvARB := wglGetProcAddress('glUniformMatrix4fvARB');
-    if not Assigned(glUniformMatrix4fvARB) then Exit;
-    glGetObjectParameterfvARB := wglGetProcAddress('glGetObjectParameterfvARB');
-    if not Assigned(glGetObjectParameterfvARB) then Exit;
-    glGetObjectParameterivARB := wglGetProcAddress('glGetObjectParameterivARB');
-    if not Assigned(glGetObjectParameterivARB) then Exit;
-    glGetInfoLogARB := wglGetProcAddress('glGetInfoLogARB');
-    if not Assigned(glGetInfoLogARB) then Exit;
-    glGetAttachedObjectsARB := wglGetProcAddress('glGetAttachedObjectsARB');
-    if not Assigned(glGetAttachedObjectsARB) then Exit;
-    glGetUniformLocationARB := wglGetProcAddress('glGetUniformLocationARB');
-    if not Assigned(glGetUniformLocationARB) then Exit;
-    glGetActiveUniformARB := wglGetProcAddress('glGetActiveUniformARB');
-    if not Assigned(glGetActiveUniformARB) then Exit;
-    glGetUniformfvARB := wglGetProcAddress('glGetUniformfvARB');
-    if not Assigned(glGetUniformfvARB) then Exit;
-    glGetUniformivARB := wglGetProcAddress('glGetUniformivARB');
-    if not Assigned(glGetUniformivARB) then Exit;
-    glGetShaderSourceARB := wglGetProcAddress('glGetShaderSourceARB');
-    if not Assigned(glGetShaderSourceARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_vertex_shader: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_vertex_shader', extstring) then
-  begin
-    glVertexAttrib1fARB := wglGetProcAddress('glVertexAttrib1fARB');
-    if not Assigned(glVertexAttrib1fARB) then Exit;
-    glVertexAttrib1sARB := wglGetProcAddress('glVertexAttrib1sARB');
-    if not Assigned(glVertexAttrib1sARB) then Exit;
-    glVertexAttrib1dARB := wglGetProcAddress('glVertexAttrib1dARB');
-    if not Assigned(glVertexAttrib1dARB) then Exit;
-    glVertexAttrib2fARB := wglGetProcAddress('glVertexAttrib2fARB');
-    if not Assigned(glVertexAttrib2fARB) then Exit;
-    glVertexAttrib2sARB := wglGetProcAddress('glVertexAttrib2sARB');
-    if not Assigned(glVertexAttrib2sARB) then Exit;
-    glVertexAttrib2dARB := wglGetProcAddress('glVertexAttrib2dARB');
-    if not Assigned(glVertexAttrib2dARB) then Exit;
-    glVertexAttrib3fARB := wglGetProcAddress('glVertexAttrib3fARB');
-    if not Assigned(glVertexAttrib3fARB) then Exit;
-    glVertexAttrib3sARB := wglGetProcAddress('glVertexAttrib3sARB');
-    if not Assigned(glVertexAttrib3sARB) then Exit;
-    glVertexAttrib3dARB := wglGetProcAddress('glVertexAttrib3dARB');
-    if not Assigned(glVertexAttrib3dARB) then Exit;
-    glVertexAttrib4fARB := wglGetProcAddress('glVertexAttrib4fARB');
-    if not Assigned(glVertexAttrib4fARB) then Exit;
-    glVertexAttrib4sARB := wglGetProcAddress('glVertexAttrib4sARB');
-    if not Assigned(glVertexAttrib4sARB) then Exit;
-    glVertexAttrib4dARB := wglGetProcAddress('glVertexAttrib4dARB');
-    if not Assigned(glVertexAttrib4dARB) then Exit;
-    glVertexAttrib4NubARB := wglGetProcAddress('glVertexAttrib4NubARB');
-    if not Assigned(glVertexAttrib4NubARB) then Exit;
-    glVertexAttrib1fvARB := wglGetProcAddress('glVertexAttrib1fvARB');
-    if not Assigned(glVertexAttrib1fvARB) then Exit;
-    glVertexAttrib1svARB := wglGetProcAddress('glVertexAttrib1svARB');
-    if not Assigned(glVertexAttrib1svARB) then Exit;
-    glVertexAttrib1dvARB := wglGetProcAddress('glVertexAttrib1dvARB');
-    if not Assigned(glVertexAttrib1dvARB) then Exit;
-    glVertexAttrib2fvARB := wglGetProcAddress('glVertexAttrib2fvARB');
-    if not Assigned(glVertexAttrib2fvARB) then Exit;
-    glVertexAttrib2svARB := wglGetProcAddress('glVertexAttrib2svARB');
-    if not Assigned(glVertexAttrib2svARB) then Exit;
-    glVertexAttrib2dvARB := wglGetProcAddress('glVertexAttrib2dvARB');
-    if not Assigned(glVertexAttrib2dvARB) then Exit;
-    glVertexAttrib3fvARB := wglGetProcAddress('glVertexAttrib3fvARB');
-    if not Assigned(glVertexAttrib3fvARB) then Exit;
-    glVertexAttrib3svARB := wglGetProcAddress('glVertexAttrib3svARB');
-    if not Assigned(glVertexAttrib3svARB) then Exit;
-    glVertexAttrib3dvARB := wglGetProcAddress('glVertexAttrib3dvARB');
-    if not Assigned(glVertexAttrib3dvARB) then Exit;
-    glVertexAttrib4fvARB := wglGetProcAddress('glVertexAttrib4fvARB');
-    if not Assigned(glVertexAttrib4fvARB) then Exit;
-    glVertexAttrib4svARB := wglGetProcAddress('glVertexAttrib4svARB');
-    if not Assigned(glVertexAttrib4svARB) then Exit;
-    glVertexAttrib4dvARB := wglGetProcAddress('glVertexAttrib4dvARB');
-    if not Assigned(glVertexAttrib4dvARB) then Exit;
-    glVertexAttrib4ivARB := wglGetProcAddress('glVertexAttrib4ivARB');
-    if not Assigned(glVertexAttrib4ivARB) then Exit;
-    glVertexAttrib4bvARB := wglGetProcAddress('glVertexAttrib4bvARB');
-    if not Assigned(glVertexAttrib4bvARB) then Exit;
-    glVertexAttrib4ubvARB := wglGetProcAddress('glVertexAttrib4ubvARB');
-    if not Assigned(glVertexAttrib4ubvARB) then Exit;
-    glVertexAttrib4usvARB := wglGetProcAddress('glVertexAttrib4usvARB');
-    if not Assigned(glVertexAttrib4usvARB) then Exit;
-    glVertexAttrib4uivARB := wglGetProcAddress('glVertexAttrib4uivARB');
-    if not Assigned(glVertexAttrib4uivARB) then Exit;
-    glVertexAttrib4NbvARB := wglGetProcAddress('glVertexAttrib4NbvARB');
-    if not Assigned(glVertexAttrib4NbvARB) then Exit;
-    glVertexAttrib4NsvARB := wglGetProcAddress('glVertexAttrib4NsvARB');
-    if not Assigned(glVertexAttrib4NsvARB) then Exit;
-    glVertexAttrib4NivARB := wglGetProcAddress('glVertexAttrib4NivARB');
-    if not Assigned(glVertexAttrib4NivARB) then Exit;
-    glVertexAttrib4NubvARB := wglGetProcAddress('glVertexAttrib4NubvARB');
-    if not Assigned(glVertexAttrib4NubvARB) then Exit;
-    glVertexAttrib4NusvARB := wglGetProcAddress('glVertexAttrib4NusvARB');
-    if not Assigned(glVertexAttrib4NusvARB) then Exit;
-    glVertexAttrib4NuivARB := wglGetProcAddress('glVertexAttrib4NuivARB');
-    if not Assigned(glVertexAttrib4NuivARB) then Exit;
-    glVertexAttribPointerARB := wglGetProcAddress('glVertexAttribPointerARB');
-    if not Assigned(glVertexAttribPointerARB) then Exit;
-    glEnableVertexAttribArrayARB := wglGetProcAddress('glEnableVertexAttribArrayARB');
-    if not Assigned(glEnableVertexAttribArrayARB) then Exit;
-    glDisableVertexAttribArrayARB := wglGetProcAddress('glDisableVertexAttribArrayARB');
-    if not Assigned(glDisableVertexAttribArrayARB) then Exit;
-    glBindAttribLocationARB := wglGetProcAddress('glBindAttribLocationARB');
-    if not Assigned(glBindAttribLocationARB) then Exit;
-    glGetActiveAttribARB := wglGetProcAddress('glGetActiveAttribARB');
-    if not Assigned(glGetActiveAttribARB) then Exit;
-    glGetAttribLocationARB := wglGetProcAddress('glGetAttribLocationARB');
-    if not Assigned(glGetAttribLocationARB) then Exit;
-    glGetVertexAttribdvARB := wglGetProcAddress('glGetVertexAttribdvARB');
-    if not Assigned(glGetVertexAttribdvARB) then Exit;
-    glGetVertexAttribfvARB := wglGetProcAddress('glGetVertexAttribfvARB');
-    if not Assigned(glGetVertexAttribfvARB) then Exit;
-    glGetVertexAttribivARB := wglGetProcAddress('glGetVertexAttribivARB');
-    if not Assigned(glGetVertexAttribivARB) then Exit;
-    glGetVertexAttribPointervARB := wglGetProcAddress('glGetVertexAttribPointervARB');
-    if not Assigned(glGetVertexAttribPointervARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_fragment_shader: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_fragment_shader', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_shading_language_100: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_shading_language_100', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_non_power_of_two: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_non_power_of_two', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_point_sprite: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_point_sprite', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_depth_bounds_test: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_depth_bounds_test', extstring) then
-  begin
-    glDepthBoundsEXT := wglGetProcAddress('glDepthBoundsEXT');
-    if not Assigned(glDepthBoundsEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_secondary_color: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_secondary_color', extstring) then
-  begin
-    glSecondaryColor3bEXT := wglGetProcAddress('glSecondaryColor3bEXT');
-    if not Assigned(glSecondaryColor3bEXT) then Exit;
-    glSecondaryColor3sEXT := wglGetProcAddress('glSecondaryColor3sEXT');
-    if not Assigned(glSecondaryColor3sEXT) then Exit;
-    glSecondaryColor3iEXT := wglGetProcAddress('glSecondaryColor3iEXT');
-    if not Assigned(glSecondaryColor3iEXT) then Exit;
-    glSecondaryColor3fEXT := wglGetProcAddress('glSecondaryColor3fEXT');
-    if not Assigned(glSecondaryColor3fEXT) then Exit;
-    glSecondaryColor3dEXT := wglGetProcAddress('glSecondaryColor3dEXT');
-    if not Assigned(glSecondaryColor3dEXT) then Exit;
-    glSecondaryColor3ubEXT := wglGetProcAddress('glSecondaryColor3ubEXT');
-    if not Assigned(glSecondaryColor3ubEXT) then Exit;
-    glSecondaryColor3usEXT := wglGetProcAddress('glSecondaryColor3usEXT');
-    if not Assigned(glSecondaryColor3usEXT) then Exit;
-    glSecondaryColor3uiEXT := wglGetProcAddress('glSecondaryColor3uiEXT');
-    if not Assigned(glSecondaryColor3uiEXT) then Exit;
-    glSecondaryColor3bvEXT := wglGetProcAddress('glSecondaryColor3bvEXT');
-    if not Assigned(glSecondaryColor3bvEXT) then Exit;
-    glSecondaryColor3svEXT := wglGetProcAddress('glSecondaryColor3svEXT');
-    if not Assigned(glSecondaryColor3svEXT) then Exit;
-    glSecondaryColor3ivEXT := wglGetProcAddress('glSecondaryColor3ivEXT');
-    if not Assigned(glSecondaryColor3ivEXT) then Exit;
-    glSecondaryColor3fvEXT := wglGetProcAddress('glSecondaryColor3fvEXT');
-    if not Assigned(glSecondaryColor3fvEXT) then Exit;
-    glSecondaryColor3dvEXT := wglGetProcAddress('glSecondaryColor3dvEXT');
-    if not Assigned(glSecondaryColor3dvEXT) then Exit;
-    glSecondaryColor3ubvEXT := wglGetProcAddress('glSecondaryColor3ubvEXT');
-    if not Assigned(glSecondaryColor3ubvEXT) then Exit;
-    glSecondaryColor3usvEXT := wglGetProcAddress('glSecondaryColor3usvEXT');
-    if not Assigned(glSecondaryColor3usvEXT) then Exit;
-    glSecondaryColor3uivEXT := wglGetProcAddress('glSecondaryColor3uivEXT');
-    if not Assigned(glSecondaryColor3uivEXT) then Exit;
-    glSecondaryColorPointerEXT := wglGetProcAddress('glSecondaryColorPointerEXT');
-    if not Assigned(glSecondaryColorPointerEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_mirror_clamp: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_mirror_clamp', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_blend_equation_separate: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_blend_equation_separate', extstring) then
-  begin
-    glBlendEquationSeparateEXT := wglGetProcAddress('glBlendEquationSeparateEXT');
-    if not Assigned(glBlendEquationSeparateEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_MESA_pack_invert: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_MESA_pack_invert', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_MESA_ycbcr_texture: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_MESA_ycbcr_texture', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_fragment_program_shadow: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_fragment_program_shadow', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_fog_coord: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_fog_coord', extstring) then
-  begin
-    glFogCoordfEXT := wglGetProcAddress('glFogCoordfEXT');
-    if not Assigned(glFogCoordfEXT) then Exit;
-    glFogCoorddEXT := wglGetProcAddress('glFogCoorddEXT');
-    if not Assigned(glFogCoorddEXT) then Exit;
-    glFogCoordfvEXT := wglGetProcAddress('glFogCoordfvEXT');
-    if not Assigned(glFogCoordfvEXT) then Exit;
-    glFogCoorddvEXT := wglGetProcAddress('glFogCoorddvEXT');
-    if not Assigned(glFogCoorddvEXT) then Exit;
-    glFogCoordPointerEXT := wglGetProcAddress('glFogCoordPointerEXT');
-    if not Assigned(glFogCoordPointerEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_fragment_program_option: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_fragment_program_option', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_pixel_buffer_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_pixel_buffer_object', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_fragment_program2: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_fragment_program2', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_vertex_program2_option: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_vertex_program2_option', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_NV_vertex_program3: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_NV_vertex_program3', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_draw_buffers: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_draw_buffers', extstring) then
-  begin
-    glDrawBuffersARB := wglGetProcAddress('glDrawBuffersARB');
-    if not Assigned(glDrawBuffersARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_rectangle: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_rectangle', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_color_buffer_float: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_color_buffer_float', extstring) then
-  begin
-    glClampColorARB := wglGetProcAddress('glClampColorARB');
-    if not Assigned(glClampColorARB) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_half_float_pixel: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_half_float_pixel', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_texture_float: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_texture_float', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_texture_compression_dxt1: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_texture_compression_dxt1', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_ARB_pixel_buffer_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_ARB_pixel_buffer_object', extstring) then
-  begin
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_EXT_framebuffer_object: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-  if glext_ExtensionSupported('GL_EXT_framebuffer_object', extstring) then
-  begin
-    glIsRenderbufferEXT := wglGetProcAddress('glIsRenderbufferEXT');
-    if not Assigned(glIsRenderbufferEXT) then Exit;
-    glBindRenderbufferEXT := wglGetProcAddress('glBindRenderbufferEXT');
-    if not Assigned(glBindRenderbufferEXT) then Exit;
-    glDeleteRenderbuffersEXT := wglGetProcAddress('glDeleteRenderbuffersEXT');
-    if not Assigned(glDeleteRenderbuffersEXT) then Exit;
-    glGenRenderbuffersEXT := wglGetProcAddress('glGenRenderbuffersEXT');
-    if not Assigned(glGenRenderbuffersEXT) then Exit;
-    glRenderbufferStorageEXT := wglGetProcAddress('glRenderbufferStorageEXT');
-    if not Assigned(glRenderbufferStorageEXT) then Exit;
-    glGetRenderbufferParameterivEXT := wglGetProcAddress('glGetRenderbufferParameterivEXT');
-    if not Assigned(glGetRenderbufferParameterivEXT) then Exit;
-    glIsFramebufferEXT := wglGetProcAddress('glIsFramebufferEXT');
-    if not Assigned(glIsFramebufferEXT) then Exit;
-    glBindFramebufferEXT := wglGetProcAddress('glBindFramebufferEXT');
-    if not Assigned(glBindFramebufferEXT) then Exit;
-    glDeleteFramebuffersEXT := wglGetProcAddress('glDeleteFramebuffersEXT');
-    if not Assigned(glDeleteFramebuffersEXT) then Exit;
-    glGenFramebuffersEXT := wglGetProcAddress('glGenFramebuffersEXT');
-    if not Assigned(glGenFramebuffersEXT) then Exit;
-    glCheckFramebufferStatusEXT := wglGetProcAddress('glCheckFramebufferStatusEXT');
-    if not Assigned(glCheckFramebufferStatusEXT) then Exit;
-    glFramebufferTexture1DEXT := wglGetProcAddress('glFramebufferTexture1DEXT');
-    if not Assigned(glFramebufferTexture1DEXT) then Exit;
-    glFramebufferTexture2DEXT := wglGetProcAddress('glFramebufferTexture2DEXT');
-    if not Assigned(glFramebufferTexture2DEXT) then Exit;
-    glFramebufferTexture3DEXT := wglGetProcAddress('glFramebufferTexture3DEXT');
-    if not Assigned(glFramebufferTexture3DEXT) then Exit;
-    glFramebufferRenderbufferEXT := wglGetProcAddress('glFramebufferRenderbufferEXT');
-    if not Assigned(glFramebufferRenderbufferEXT) then Exit;
-    glGetFramebufferAttachmentParameterivEXT := wglGetProcAddress('glGetFramebufferAttachmentParameterivEXT');
-    if not Assigned(glGetFramebufferAttachmentParameterivEXT) then Exit;
-    glGenerateMipmapEXT := wglGetProcAddress('glGenerateMipmapEXT');
-    if not Assigned(glGenerateMipmapEXT) then Exit;
-    Result := TRUE;
-  end;
-
-end;
-
-function Load_GL_version_1_4: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-    glBlendFuncSeparate := wglGetProcAddress('glBlendFuncSeparate');
-    if not Assigned(glBlendFuncSeparate) then Exit;
-    glFogCoordf := wglGetProcAddress('glFogCoordf');
-    if not Assigned(glFogCoordf) then Exit;
-    glFogCoordfv := wglGetProcAddress('glFogCoordfv');
-    if not Assigned(glFogCoordfv) then Exit;
-    glFogCoordd := wglGetProcAddress('glFogCoordd');
-    if not Assigned(glFogCoordd) then Exit;
-    glFogCoorddv := wglGetProcAddress('glFogCoorddv');
-    if not Assigned(glFogCoorddv) then Exit;
-    glFogCoordPointer := wglGetProcAddress('glFogCoordPointer');
-    if not Assigned(glFogCoordPointer) then Exit;
-    glMultiDrawArrays := wglGetProcAddress('glMultiDrawArrays');
-    if not Assigned(glMultiDrawArrays) then Exit;
-    glMultiDrawElements := wglGetProcAddress('glMultiDrawElements');
-    if not Assigned(glMultiDrawElements) then Exit;
-    glPointParameterf := wglGetProcAddress('glPointParameterf');
-    if not Assigned(glPointParameterf) then Exit;
-    glPointParameterfv := wglGetProcAddress('glPointParameterfv');
-    if not Assigned(glPointParameterfv) then Exit;
-    glPointParameteri := wglGetProcAddress('glPointParameteri');
-    if not Assigned(glPointParameteri) then Exit;
-    glPointParameteriv := wglGetProcAddress('glPointParameteriv');
-    if not Assigned(glPointParameteriv) then Exit;
-    glSecondaryColor3b := wglGetProcAddress('glSecondaryColor3b');
-    if not Assigned(glSecondaryColor3b) then Exit;
-    glSecondaryColor3bv := wglGetProcAddress('glSecondaryColor3bv');
-    if not Assigned(glSecondaryColor3bv) then Exit;
-    glSecondaryColor3d := wglGetProcAddress('glSecondaryColor3d');
-    if not Assigned(glSecondaryColor3d) then Exit;
-    glSecondaryColor3dv := wglGetProcAddress('glSecondaryColor3dv');
-    if not Assigned(glSecondaryColor3dv) then Exit;
-    glSecondaryColor3f := wglGetProcAddress('glSecondaryColor3f');
-    if not Assigned(glSecondaryColor3f) then Exit;
-    glSecondaryColor3fv := wglGetProcAddress('glSecondaryColor3fv');
-    if not Assigned(glSecondaryColor3fv) then Exit;
-    glSecondaryColor3i := wglGetProcAddress('glSecondaryColor3i');
-    if not Assigned(glSecondaryColor3i) then Exit;
-    glSecondaryColor3iv := wglGetProcAddress('glSecondaryColor3iv');
-    if not Assigned(glSecondaryColor3iv) then Exit;
-    glSecondaryColor3s := wglGetProcAddress('glSecondaryColor3s');
-    if not Assigned(glSecondaryColor3s) then Exit;
-    glSecondaryColor3sv := wglGetProcAddress('glSecondaryColor3sv');
-    if not Assigned(glSecondaryColor3sv) then Exit;
-    glSecondaryColor3ub := wglGetProcAddress('glSecondaryColor3ub');
-    if not Assigned(glSecondaryColor3ub) then Exit;
-    glSecondaryColor3ubv := wglGetProcAddress('glSecondaryColor3ubv');
-    if not Assigned(glSecondaryColor3ubv) then Exit;
-    glSecondaryColor3ui := wglGetProcAddress('glSecondaryColor3ui');
-    if not Assigned(glSecondaryColor3ui) then Exit;
-    glSecondaryColor3uiv := wglGetProcAddress('glSecondaryColor3uiv');
-    if not Assigned(glSecondaryColor3uiv) then Exit;
-    glSecondaryColor3us := wglGetProcAddress('glSecondaryColor3us');
-    if not Assigned(glSecondaryColor3us) then Exit;
-    glSecondaryColor3usv := wglGetProcAddress('glSecondaryColor3usv');
-    if not Assigned(glSecondaryColor3usv) then Exit;
-    glSecondaryColorPointer := wglGetProcAddress('glSecondaryColorPointer');
-    if not Assigned(glSecondaryColorPointer) then Exit;
-    glWindowPos2d := wglGetProcAddress('glWindowPos2d');
-    if not Assigned(glWindowPos2d) then Exit;
-    glWindowPos2dv := wglGetProcAddress('glWindowPos2dv');
-    if not Assigned(glWindowPos2dv) then Exit;
-    glWindowPos2f := wglGetProcAddress('glWindowPos2f');
-    if not Assigned(glWindowPos2f) then Exit;
-    glWindowPos2fv := wglGetProcAddress('glWindowPos2fv');
-    if not Assigned(glWindowPos2fv) then Exit;
-    glWindowPos2i := wglGetProcAddress('glWindowPos2i');
-    if not Assigned(glWindowPos2i) then Exit;
-    glWindowPos2iv := wglGetProcAddress('glWindowPos2iv');
-    if not Assigned(glWindowPos2iv) then Exit;
-    glWindowPos2s := wglGetProcAddress('glWindowPos2s');
-    if not Assigned(glWindowPos2s) then Exit;
-    glWindowPos2sv := wglGetProcAddress('glWindowPos2sv');
-    if not Assigned(glWindowPos2sv) then Exit;
-    glWindowPos3d := wglGetProcAddress('glWindowPos3d');
-    if not Assigned(glWindowPos3d) then Exit;
-    glWindowPos3dv := wglGetProcAddress('glWindowPos3dv');
-    if not Assigned(glWindowPos3dv) then Exit;
-    glWindowPos3f := wglGetProcAddress('glWindowPos3f');
-    if not Assigned(glWindowPos3f) then Exit;
-    glWindowPos3fv := wglGetProcAddress('glWindowPos3fv');
-    if not Assigned(glWindowPos3fv) then Exit;
-    glWindowPos3i := wglGetProcAddress('glWindowPos3i');
-    if not Assigned(glWindowPos3i) then Exit;
-    glWindowPos3iv := wglGetProcAddress('glWindowPos3iv');
-    if not Assigned(glWindowPos3iv) then Exit;
-    glWindowPos3s := wglGetProcAddress('glWindowPos3s');
-    if not Assigned(glWindowPos3s) then Exit;
-    glWindowPos3sv := wglGetProcAddress('glWindowPos3sv');
-    if not Assigned(glWindowPos3sv) then Exit;
-    Result := TRUE;
-
-end;
-
-function Load_GL_version_1_5: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-    glGenQueries := wglGetProcAddress('glGenQueries');
-    if not Assigned(glGenQueries) then Exit;
-    glDeleteQueries := wglGetProcAddress('glDeleteQueries');
-    if not Assigned(glDeleteQueries) then Exit;
-    glIsQuery := wglGetProcAddress('glIsQuery');
-    if not Assigned(glIsQuery) then Exit;
-    glBeginQuery := wglGetProcAddress('glBeginQuery');
-    if not Assigned(glBeginQuery) then Exit;
-    glEndQuery := wglGetProcAddress('glEndQuery');
-    if not Assigned(glEndQuery) then Exit;
-    glGetQueryiv := wglGetProcAddress('glGetQueryiv');
-    if not Assigned(glGetQueryiv) then Exit;
-    glGetQueryObjectiv := wglGetProcAddress('glGetQueryObjectiv');
-    if not Assigned(glGetQueryObjectiv) then Exit;
-    glGetQueryObjectuiv := wglGetProcAddress('glGetQueryObjectuiv');
-    if not Assigned(glGetQueryObjectuiv) then Exit;
-    glBindBuffer := wglGetProcAddress('glBindBuffer');
-    if not Assigned(glBindBuffer) then Exit;
-    glDeleteBuffers := wglGetProcAddress('glDeleteBuffers');
-    if not Assigned(glDeleteBuffers) then Exit;
-    glGenBuffers := wglGetProcAddress('glGenBuffers');
-    if not Assigned(glGenBuffers) then Exit;
-    glIsBuffer := wglGetProcAddress('glIsBuffer');
-    if not Assigned(glIsBuffer) then Exit;
-    glBufferData := wglGetProcAddress('glBufferData');
-    if not Assigned(glBufferData) then Exit;
-    glBufferSubData := wglGetProcAddress('glBufferSubData');
-    if not Assigned(glBufferSubData) then Exit;
-    glGetBufferSubData := wglGetProcAddress('glGetBufferSubData');
-    if not Assigned(glGetBufferSubData) then Exit;
-    glMapBuffer := wglGetProcAddress('glMapBuffer');
-    if not Assigned(glMapBuffer) then Exit;
-    glUnmapBuffer := wglGetProcAddress('glUnmapBuffer');
-    if not Assigned(glUnmapBuffer) then Exit;
-    glGetBufferParameteriv := wglGetProcAddress('glGetBufferParameteriv');
-    if not Assigned(glGetBufferParameteriv) then Exit;
-    glGetBufferPointerv := wglGetProcAddress('glGetBufferPointerv');
-    if not Assigned(glGetBufferPointerv) then Exit;
-    Result := TRUE;
-
-end;
-
-function Load_GL_version_2_0: Boolean;
-var
-  extstring: String;
-begin
-
-  Result := FALSE;
-  extstring := String(PChar(glGetString(GL_EXTENSIONS)));
-
-    glBlendEquationSeparate := wglGetProcAddress('glBlendEquationSeparate');
-    if not Assigned(glBlendEquationSeparate) then Exit;
-    glDrawBuffers := wglGetProcAddress('glDrawBuffers');
-    if not Assigned(glDrawBuffers) then Exit;
-    glStencilOpSeparate := wglGetProcAddress('glStencilOpSeparate');
-    if not Assigned(glStencilOpSeparate) then Exit;
-    glStencilFuncSeparate := wglGetProcAddress('glStencilFuncSeparate');
-    if not Assigned(glStencilFuncSeparate) then Exit;
-    glStencilMaskSeparate := wglGetProcAddress('glStencilMaskSeparate');
-    if not Assigned(glStencilMaskSeparate) then Exit;
-    glAttachShader := wglGetProcAddress('glAttachShader');
-    if not Assigned(glAttachShader) then Exit;
-    glBindAttribLocation := wglGetProcAddress('glBindAttribLocation');
-    if not Assigned(glBindAttribLocation) then Exit;
-    glCompileShader := wglGetProcAddress('glCompileShader');
-    if not Assigned(glCompileShader) then Exit;
-    glCreateProgram := wglGetProcAddress('glCreateProgram');
-    if not Assigned(glCreateProgram) then Exit;
-    glCreateShader := wglGetProcAddress('glCreateShader');
-    if not Assigned(glCreateShader) then Exit;
-    glDeleteProgram := wglGetProcAddress('glDeleteProgram');
-    if not Assigned(glDeleteProgram) then Exit;
-    glDeleteShader := wglGetProcAddress('glDeleteShader');
-    if not Assigned(glDeleteShader) then Exit;
-    glDetachShader := wglGetProcAddress('glDetachShader');
-    if not Assigned(glDetachShader) then Exit;
-    glDisableVertexAttribArray := wglGetProcAddress('glDisableVertexAttribArray');
-    if not Assigned(glDisableVertexAttribArray) then Exit;
-    glEnableVertexAttribArray := wglGetProcAddress('glEnableVertexAttribArray');
-    if not Assigned(glEnableVertexAttribArray) then Exit;
-    glGetActiveAttrib := wglGetProcAddress('glGetActiveAttrib');
-    if not Assigned(glGetActiveAttrib) then Exit;
-    glGetActiveUniform := wglGetProcAddress('glGetActiveUniform');
-    if not Assigned(glGetActiveUniform) then Exit;
-    glGetAttachedShaders := wglGetProcAddress('glGetAttachedShaders');
-    if not Assigned(glGetAttachedShaders) then Exit;
-    glGetAttribLocation := wglGetProcAddress('glGetAttribLocation');
-    if not Assigned(glGetAttribLocation) then Exit;
-    glGetProgramiv := wglGetProcAddress('glGetProgramiv');
-    if not Assigned(glGetProgramiv) then Exit;
-    glGetProgramInfoLog := wglGetProcAddress('glGetProgramInfoLog');
-    if not Assigned(glGetProgramInfoLog) then Exit;
-    glGetShaderiv := wglGetProcAddress('glGetShaderiv');
-    if not Assigned(glGetShaderiv) then Exit;
-    glGetShaderInfoLog := wglGetProcAddress('glGetShaderInfoLog');
-    if not Assigned(glGetShaderInfoLog) then Exit;
-    glGetShaderSource := wglGetProcAddress('glGetShaderSource');
-    if not Assigned(glGetShaderSource) then Exit;
-    glGetUniformLocation := wglGetProcAddress('glGetUniformLocation');
-    if not Assigned(glGetUniformLocation) then Exit;
-    glGetUniformfv := wglGetProcAddress('glGetUniformfv');
-    if not Assigned(glGetUniformfv) then Exit;
-    glGetUniformiv := wglGetProcAddress('glGetUniformiv');
-    if not Assigned(glGetUniformiv) then Exit;
-    glGetVertexAttribdv := wglGetProcAddress('glGetVertexAttribdv');
-    if not Assigned(glGetVertexAttribdv) then Exit;
-    glGetVertexAttribfv := wglGetProcAddress('glGetVertexAttribfv');
-    if not Assigned(glGetVertexAttribfv) then Exit;
-    glGetVertexAttribiv := wglGetProcAddress('glGetVertexAttribiv');
-    if not Assigned(glGetVertexAttribiv) then Exit;
-    glGetVertexAttribPointerv := wglGetProcAddress('glGetVertexAttribPointerv');
-    if not Assigned(glGetVertexAttribPointerv) then Exit;
-    glIsProgram := wglGetProcAddress('glIsProgram');
-    if not Assigned(glIsProgram) then Exit;
-    glIsShader := wglGetProcAddress('glIsShader');
-    if not Assigned(glIsShader) then Exit;
-    glLinkProgram := wglGetProcAddress('glLinkProgram');
-    if not Assigned(glLinkProgram) then Exit;
-    glShaderSource := wglGetProcAddress('glShaderSource');
-    if not Assigned(glShaderSource) then Exit;
-    glUseProgram := wglGetProcAddress('glUseProgram');
-    if not Assigned(glUseProgram) then Exit;
-    glUniform1f := wglGetProcAddress('glUniform1f');
-    if not Assigned(glUniform1f) then Exit;
-    glUniform2f := wglGetProcAddress('glUniform2f');
-    if not Assigned(glUniform2f) then Exit;
-    glUniform3f := wglGetProcAddress('glUniform3f');
-    if not Assigned(glUniform3f) then Exit;
-    glUniform4f := wglGetProcAddress('glUniform4f');
-    if not Assigned(glUniform4f) then Exit;
-    glUniform1i := wglGetProcAddress('glUniform1i');
-    if not Assigned(glUniform1i) then Exit;
-    glUniform2i := wglGetProcAddress('glUniform2i');
-    if not Assigned(glUniform2i) then Exit;
-    glUniform3i := wglGetProcAddress('glUniform3i');
-    if not Assigned(glUniform3i) then Exit;
-    glUniform4i := wglGetProcAddress('glUniform4i');
-    if not Assigned(glUniform4i) then Exit;
-    glUniform1fv := wglGetProcAddress('glUniform1fv');
-    if not Assigned(glUniform1fv) then Exit;
-    glUniform2fv := wglGetProcAddress('glUniform2fv');
-    if not Assigned(glUniform2fv) then Exit;
-    glUniform3fv := wglGetProcAddress('glUniform3fv');
-    if not Assigned(glUniform3fv) then Exit;
-    glUniform4fv := wglGetProcAddress('glUniform4fv');
-    if not Assigned(glUniform4fv) then Exit;
-    glUniform1iv := wglGetProcAddress('glUniform1iv');
-    if not Assigned(glUniform1iv) then Exit;
-    glUniform2iv := wglGetProcAddress('glUniform2iv');
-    if not Assigned(glUniform2iv) then Exit;
-    glUniform3iv := wglGetProcAddress('glUniform3iv');
-    if not Assigned(glUniform3iv) then Exit;
-    glUniform4iv := wglGetProcAddress('glUniform4iv');
-    if not Assigned(glUniform4iv) then Exit;
-    glUniformMatrix2fv := wglGetProcAddress('glUniformMatrix2fv');
-    if not Assigned(glUniformMatrix2fv) then Exit;
-    glUniformMatrix3fv := wglGetProcAddress('glUniformMatrix3fv');
-    if not Assigned(glUniformMatrix3fv) then Exit;
-    glUniformMatrix4fv := wglGetProcAddress('glUniformMatrix4fv');
-    if not Assigned(glUniformMatrix4fv) then Exit;
-    glValidateProgram := wglGetProcAddress('glValidateProgram');
-    if not Assigned(glValidateProgram) then Exit;
-    glVertexAttrib1d := wglGetProcAddress('glVertexAttrib1d');
-    if not Assigned(glVertexAttrib1d) then Exit;
-    glVertexAttrib1dv := wglGetProcAddress('glVertexAttrib1dv');
-    if not Assigned(glVertexAttrib1dv) then Exit;
-    glVertexAttrib1f := wglGetProcAddress('glVertexAttrib1f');
-    if not Assigned(glVertexAttrib1f) then Exit;
-    glVertexAttrib1fv := wglGetProcAddress('glVertexAttrib1fv');
-    if not Assigned(glVertexAttrib1fv) then Exit;
-    glVertexAttrib1s := wglGetProcAddress('glVertexAttrib1s');
-    if not Assigned(glVertexAttrib1s) then Exit;
-    glVertexAttrib1sv := wglGetProcAddress('glVertexAttrib1sv');
-    if not Assigned(glVertexAttrib1sv) then Exit;
-    glVertexAttrib2d := wglGetProcAddress('glVertexAttrib2d');
-    if not Assigned(glVertexAttrib2d) then Exit;
-    glVertexAttrib2dv := wglGetProcAddress('glVertexAttrib2dv');
-    if not Assigned(glVertexAttrib2dv) then Exit;
-    glVertexAttrib2f := wglGetProcAddress('glVertexAttrib2f');
-    if not Assigned(glVertexAttrib2f) then Exit;
-    glVertexAttrib2fv := wglGetProcAddress('glVertexAttrib2fv');
-    if not Assigned(glVertexAttrib2fv) then Exit;
-    glVertexAttrib2s := wglGetProcAddress('glVertexAttrib2s');
-    if not Assigned(glVertexAttrib2s) then Exit;
-    glVertexAttrib2sv := wglGetProcAddress('glVertexAttrib2sv');
-    if not Assigned(glVertexAttrib2sv) then Exit;
-    glVertexAttrib3d := wglGetProcAddress('glVertexAttrib3d');
-    if not Assigned(glVertexAttrib3d) then Exit;
-    glVertexAttrib3dv := wglGetProcAddress('glVertexAttrib3dv');
-    if not Assigned(glVertexAttrib3dv) then Exit;
-    glVertexAttrib3f := wglGetProcAddress('glVertexAttrib3f');
-    if not Assigned(glVertexAttrib3f) then Exit;
-    glVertexAttrib3fv := wglGetProcAddress('glVertexAttrib3fv');
-    if not Assigned(glVertexAttrib3fv) then Exit;
-    glVertexAttrib3s := wglGetProcAddress('glVertexAttrib3s');
-    if not Assigned(glVertexAttrib3s) then Exit;
-    glVertexAttrib3sv := wglGetProcAddress('glVertexAttrib3sv');
-    if not Assigned(glVertexAttrib3sv) then Exit;
-    glVertexAttrib4Nbv := wglGetProcAddress('glVertexAttrib4Nbv');
-    if not Assigned(glVertexAttrib4Nbv) then Exit;
-    glVertexAttrib4Niv := wglGetProcAddress('glVertexAttrib4Niv');
-    if not Assigned(glVertexAttrib4Niv) then Exit;
-    glVertexAttrib4Nsv := wglGetProcAddress('glVertexAttrib4Nsv');
-    if not Assigned(glVertexAttrib4Nsv) then Exit;
-    glVertexAttrib4Nub := wglGetProcAddress('glVertexAttrib4Nub');
-    if not Assigned(glVertexAttrib4Nub) then Exit;
-    glVertexAttrib4Nubv := wglGetProcAddress('glVertexAttrib4Nubv');
-    if not Assigned(glVertexAttrib4Nubv) then Exit;
-    glVertexAttrib4Nuiv := wglGetProcAddress('glVertexAttrib4Nuiv');
-    if not Assigned(glVertexAttrib4Nuiv) then Exit;
-    glVertexAttrib4Nusv := wglGetProcAddress('glVertexAttrib4Nusv');
-    if not Assigned(glVertexAttrib4Nusv) then Exit;
-    glVertexAttrib4bv := wglGetProcAddress('glVertexAttrib4bv');
-    if not Assigned(glVertexAttrib4bv) then Exit;
-    glVertexAttrib4d := wglGetProcAddress('glVertexAttrib4d');
-    if not Assigned(glVertexAttrib4d) then Exit;
-    glVertexAttrib4dv := wglGetProcAddress('glVertexAttrib4dv');
-    if not Assigned(glVertexAttrib4dv) then Exit;
-    glVertexAttrib4f := wglGetProcAddress('glVertexAttrib4f');
-    if not Assigned(glVertexAttrib4f) then Exit;
-    glVertexAttrib4fv := wglGetProcAddress('glVertexAttrib4fv');
-    if not Assigned(glVertexAttrib4fv) then Exit;
-    glVertexAttrib4iv := wglGetProcAddress('glVertexAttrib4iv');
-    if not Assigned(glVertexAttrib4iv) then Exit;
-    glVertexAttrib4s := wglGetProcAddress('glVertexAttrib4s');
-    if not Assigned(glVertexAttrib4s) then Exit;
-    glVertexAttrib4sv := wglGetProcAddress('glVertexAttrib4sv');
-    if not Assigned(glVertexAttrib4sv) then Exit;
-    glVertexAttrib4ubv := wglGetProcAddress('glVertexAttrib4ubv');
-    if not Assigned(glVertexAttrib4ubv) then Exit;
-    glVertexAttrib4uiv := wglGetProcAddress('glVertexAttrib4uiv');
-    if not Assigned(glVertexAttrib4uiv) then Exit;
-    glVertexAttrib4usv := wglGetProcAddress('glVertexAttrib4usv');
-    if not Assigned(glVertexAttrib4usv) then Exit;
-    glVertexAttribPointer := wglGetProcAddress('glVertexAttribPointer');
-    if not Assigned(glVertexAttribPointer) then Exit;
-    Result := TRUE;
-
-end;
-
-function glext_LoadExtension(ext: String): Boolean;
-begin
-
-  Result := FALSE;
-
-  if ext = 'GL_version_1_2' then Result := Load_GL_version_1_2
-  else if ext = 'GL_ARB_imaging' then Result := Load_GL_ARB_imaging
-  else if ext = 'GL_version_1_3' then Result := Load_GL_version_1_3
-  else if ext = 'GL_ARB_multitexture' then Result := Load_GL_ARB_multitexture
-  else if ext = 'GL_ARB_transpose_matrix' then Result := Load_GL_ARB_transpose_matrix
-  else if ext = 'GL_ARB_multisample' then Result := Load_GL_ARB_multisample
-  else if ext = 'GL_ARB_texture_env_add' then Result := Load_GL_ARB_texture_env_add
-  else if ext = 'WGL_ARB_extensions_string' then Result := Load_WGL_ARB_extensions_string
-  else if ext = 'WGL_ARB_buffer_region' then Result := Load_WGL_ARB_buffer_region
-  else if ext = 'GL_ARB_texture_cube_map' then Result := Load_GL_ARB_texture_cube_map
-  else if ext = 'GL_ARB_depth_texture' then Result := Load_GL_ARB_depth_texture
-  else if ext = 'GL_ARB_point_parameters' then Result := Load_GL_ARB_point_parameters
-  else if ext = 'GL_ARB_shadow' then Result := Load_GL_ARB_shadow
-  else if ext = 'GL_ARB_shadow_ambient' then Result := Load_GL_ARB_shadow_ambient
-  else if ext = 'GL_ARB_texture_border_clamp' then Result := Load_GL_ARB_texture_border_clamp
-  else if ext = 'GL_ARB_texture_compression' then Result := Load_GL_ARB_texture_compression
-  else if ext = 'GL_ARB_texture_env_combine' then Result := Load_GL_ARB_texture_env_combine
-  else if ext = 'GL_ARB_texture_env_crossbar' then Result := Load_GL_ARB_texture_env_crossbar
-  else if ext = 'GL_ARB_texture_env_dot3' then Result := Load_GL_ARB_texture_env_dot3
-  else if ext = 'GL_ARB_texture_mirrored_repeat' then Result := Load_GL_ARB_texture_mirrored_repeat
-  else if ext = 'GL_ARB_vertex_blend' then Result := Load_GL_ARB_vertex_blend
-  else if ext = 'GL_ARB_vertex_program' then Result := Load_GL_ARB_vertex_program
-  else if ext = 'GL_ARB_window_pos' then Result := Load_GL_ARB_window_pos
-  else if ext = 'GL_EXT_422_pixels' then Result := Load_GL_EXT_422_pixels
-  else if ext = 'GL_EXT_abgr' then Result := Load_GL_EXT_abgr
-  else if ext = 'GL_EXT_bgra' then Result := Load_GL_EXT_bgra
-  else if ext = 'GL_EXT_blend_color' then Result := Load_GL_EXT_blend_color
-  else if ext = 'GL_EXT_blend_func_separate' then Result := Load_GL_EXT_blend_func_separate
-  else if ext = 'GL_EXT_blend_logic_op' then Result := Load_GL_EXT_blend_logic_op
-  else if ext = 'GL_EXT_blend_minmax' then Result := Load_GL_EXT_blend_minmax
-  else if ext = 'GL_EXT_blend_subtract' then Result := Load_GL_EXT_blend_subtract
-  else if ext = 'GL_EXT_clip_volume_hint' then Result := Load_GL_EXT_clip_volume_hint
-  else if ext = 'GL_EXT_color_subtable' then Result := Load_GL_EXT_color_subtable
-  else if ext = 'GL_EXT_compiled_vertex_array' then Result := Load_GL_EXT_compiled_vertex_array
-  else if ext = 'GL_EXT_convolution' then Result := Load_GL_EXT_convolution
-  else if ext = 'GL_EXT_histogram' then Result := Load_GL_EXT_histogram
-  else if ext = 'GL_EXT_multi_draw_arrays' then Result := Load_GL_EXT_multi_draw_arrays
-  else if ext = 'GL_EXT_packed_pixels' then Result := Load_GL_EXT_packed_pixels
-  else if ext = 'GL_EXT_paletted_texture' then Result := Load_GL_EXT_paletted_texture
-  else if ext = 'GL_EXT_point_parameters' then Result := Load_GL_EXT_point_parameters
-  else if ext = 'GL_EXT_polygon_offset' then Result := Load_GL_EXT_polygon_offset
-  else if ext = 'GL_EXT_separate_specular_color' then Result := Load_GL_EXT_separate_specular_color
-  else if ext = 'GL_EXT_shadow_funcs' then Result := Load_GL_EXT_shadow_funcs
-  else if ext = 'GL_EXT_shared_texture_palette' then Result := Load_GL_EXT_shared_texture_palette
-  else if ext = 'GL_EXT_stencil_two_side' then Result := Load_GL_EXT_stencil_two_side
-  else if ext = 'GL_EXT_stencil_wrap' then Result := Load_GL_EXT_stencil_wrap
-  else if ext = 'GL_EXT_subtexture' then Result := Load_GL_EXT_subtexture
-  else if ext = 'GL_EXT_texture3D' then Result := Load_GL_EXT_texture3D
-  else if ext = 'GL_EXT_texture_compression_s3tc' then Result := Load_GL_EXT_texture_compression_s3tc
-  else if ext = 'GL_EXT_texture_env_add' then Result := Load_GL_EXT_texture_env_add
-  else if ext = 'GL_EXT_texture_env_combine' then Result := Load_GL_EXT_texture_env_combine
-  else if ext = 'GL_EXT_texture_env_dot3' then Result := Load_GL_EXT_texture_env_dot3
-  else if ext = 'GL_EXT_texture_filter_anisotropic' then Result := Load_GL_EXT_texture_filter_anisotropic
-  else if ext = 'GL_EXT_texture_lod_bias' then Result := Load_GL_EXT_texture_lod_bias
-  else if ext = 'GL_EXT_texture_object' then Result := Load_GL_EXT_texture_object
-  else if ext = 'GL_EXT_vertex_array' then Result := Load_GL_EXT_vertex_array
-  else if ext = 'GL_EXT_vertex_shader' then Result := Load_GL_EXT_vertex_shader
-  else if ext = 'GL_EXT_vertex_weighting' then Result := Load_GL_EXT_vertex_weighting
-  else if ext = 'GL_HP_occlusion_test' then Result := Load_GL_HP_occlusion_test
-  else if ext = 'GL_NV_blend_square' then Result := Load_GL_NV_blend_square
-  else if ext = 'GL_NV_copy_depth_to_color' then Result := Load_GL_NV_copy_depth_to_color
-  else if ext = 'GL_NV_depth_clamp' then Result := Load_GL_NV_depth_clamp
-  else if ext = 'GL_NV_evaluators' then Result := Load_GL_NV_evaluators
-  else if ext = 'GL_NV_fence' then Result := Load_GL_NV_fence
-  else if ext = 'GL_NV_fog_distance' then Result := Load_GL_NV_fog_distance
-  else if ext = 'GL_NV_light_max_exponent' then Result := Load_GL_NV_light_max_exponent
-  else if ext = 'GL_NV_multisample_filter_hint' then Result := Load_GL_NV_multisample_filter_hint
-  else if ext = 'GL_NV_occlusion_query' then Result := Load_GL_NV_occlusion_query
-  else if ext = 'GL_NV_packed_depth_stencil' then Result := Load_GL_NV_packed_depth_stencil
-  else if ext = 'GL_NV_point_sprite' then Result := Load_GL_NV_point_sprite
-  else if ext = 'GL_NV_register_combiners' then Result := Load_GL_NV_register_combiners
-  else if ext = 'GL_NV_register_combiners2' then Result := Load_GL_NV_register_combiners2
-  else if ext = 'GL_NV_texgen_emboss' then Result := Load_GL_NV_texgen_emboss
-  else if ext = 'GL_NV_texgen_reflection' then Result := Load_GL_NV_texgen_reflection
-  else if ext = 'GL_NV_texture_compression_vtc' then Result := Load_GL_NV_texture_compression_vtc
-  else if ext = 'GL_NV_texture_env_combine4' then Result := Load_GL_NV_texture_env_combine4
-  else if ext = 'GL_NV_texture_rectangle' then Result := Load_GL_NV_texture_rectangle
-  else if ext = 'GL_NV_texture_shader' then Result := Load_GL_NV_texture_shader
-  else if ext = 'GL_NV_texture_shader2' then Result := Load_GL_NV_texture_shader2
-  else if ext = 'GL_NV_texture_shader3' then Result := Load_GL_NV_texture_shader3
-  else if ext = 'GL_NV_vertex_array_range' then Result := Load_GL_NV_vertex_array_range
-  else if ext = 'GL_NV_vertex_array_range2' then Result := Load_GL_NV_vertex_array_range2
-  else if ext = 'GL_NV_vertex_program' then Result := Load_GL_NV_vertex_program
-  else if ext = 'GL_NV_vertex_program1_1' then Result := Load_GL_NV_vertex_program1_1
-  else if ext = 'GL_ATI_element_array' then Result := Load_GL_ATI_element_array
-  else if ext = 'GL_ATI_envmap_bumpmap' then Result := Load_GL_ATI_envmap_bumpmap
-  else if ext = 'GL_ATI_fragment_shader' then Result := Load_GL_ATI_fragment_shader
-  else if ext = 'GL_ATI_pn_triangles' then Result := Load_GL_ATI_pn_triangles
-  else if ext = 'GL_ATI_texture_mirror_once' then Result := Load_GL_ATI_texture_mirror_once
-  else if ext = 'GL_ATI_vertex_array_object' then Result := Load_GL_ATI_vertex_array_object
-  else if ext = 'GL_ATI_vertex_streams' then Result := Load_GL_ATI_vertex_streams
-  else if ext = 'WGL_I3D_image_buffer' then Result := Load_WGL_I3D_image_buffer
-  else if ext = 'WGL_I3D_swap_frame_lock' then Result := Load_WGL_I3D_swap_frame_lock
-  else if ext = 'WGL_I3D_swap_frame_usage' then Result := Load_WGL_I3D_swap_frame_usage
-  else if ext = 'GL_3DFX_texture_compression_FXT1' then Result := Load_GL_3DFX_texture_compression_FXT1
-  else if ext = 'GL_IBM_cull_vertex' then Result := Load_GL_IBM_cull_vertex
-  else if ext = 'GL_IBM_multimode_draw_arrays' then Result := Load_GL_IBM_multimode_draw_arrays
-  else if ext = 'GL_IBM_raster_pos_clip' then Result := Load_GL_IBM_raster_pos_clip
-  else if ext = 'GL_IBM_texture_mirrored_repeat' then Result := Load_GL_IBM_texture_mirrored_repeat
-  else if ext = 'GL_IBM_vertex_array_lists' then Result := Load_GL_IBM_vertex_array_lists
-  else if ext = 'GL_MESA_resize_buffers' then Result := Load_GL_MESA_resize_buffers
-  else if ext = 'GL_MESA_window_pos' then Result := Load_GL_MESA_window_pos
-  else if ext = 'GL_OML_interlace' then Result := Load_GL_OML_interlace
-  else if ext = 'GL_OML_resample' then Result := Load_GL_OML_resample
-  else if ext = 'GL_OML_subsample' then Result := Load_GL_OML_subsample
-  else if ext = 'GL_SGIS_generate_mipmap' then Result := Load_GL_SGIS_generate_mipmap
-  else if ext = 'GL_SGIS_multisample' then Result := Load_GL_SGIS_multisample
-  else if ext = 'GL_SGIS_pixel_texture' then Result := Load_GL_SGIS_pixel_texture
-  else if ext = 'GL_SGIS_texture_border_clamp' then Result := Load_GL_SGIS_texture_border_clamp
-  else if ext = 'GL_SGIS_texture_color_mask' then Result := Load_GL_SGIS_texture_color_mask
-  else if ext = 'GL_SGIS_texture_edge_clamp' then Result := Load_GL_SGIS_texture_edge_clamp
-  else if ext = 'GL_SGIS_texture_lod' then Result := Load_GL_SGIS_texture_lod
-  else if ext = 'GL_SGIS_depth_texture' then Result := Load_GL_SGIS_depth_texture
-  else if ext = 'GL_SGIX_fog_offset' then Result := Load_GL_SGIX_fog_offset
-  else if ext = 'GL_SGIX_interlace' then Result := Load_GL_SGIX_interlace
-  else if ext = 'GL_SGIX_shadow_ambient' then Result := Load_GL_SGIX_shadow_ambient
-  else if ext = 'GL_SGI_color_matrix' then Result := Load_GL_SGI_color_matrix
-  else if ext = 'GL_SGI_color_table' then Result := Load_GL_SGI_color_table
-  else if ext = 'GL_SGI_texture_color_table' then Result := Load_GL_SGI_texture_color_table
-  else if ext = 'GL_SUN_vertex' then Result := Load_GL_SUN_vertex
-  else if ext = 'GL_ARB_fragment_program' then Result := Load_GL_ARB_fragment_program
-  else if ext = 'GL_ATI_text_fragment_shader' then Result := Load_GL_ATI_text_fragment_shader
-  else if ext = 'GL_APPLE_client_storage' then Result := Load_GL_APPLE_client_storage
-  else if ext = 'GL_APPLE_element_array' then Result := Load_GL_APPLE_element_array
-  else if ext = 'GL_APPLE_fence' then Result := Load_GL_APPLE_fence
-  else if ext = 'GL_APPLE_vertex_array_object' then Result := Load_GL_APPLE_vertex_array_object
-  else if ext = 'GL_APPLE_vertex_array_range' then Result := Load_GL_APPLE_vertex_array_range
-  else if ext = 'WGL_ARB_pixel_format' then Result := Load_WGL_ARB_pixel_format
-  else if ext = 'WGL_ARB_make_current_read' then Result := Load_WGL_ARB_make_current_read
-  else if ext = 'WGL_ARB_pbuffer' then Result := Load_WGL_ARB_pbuffer
-  else if ext = 'WGL_EXT_swap_control' then Result := Load_WGL_EXT_swap_control
-  else if ext = 'WGL_ARB_render_texture' then Result := Load_WGL_ARB_render_texture
-  else if ext = 'WGL_EXT_extensions_string' then Result := Load_WGL_EXT_extensions_string
-  else if ext = 'WGL_EXT_make_current_read' then Result := Load_WGL_EXT_make_current_read
-  else if ext = 'WGL_EXT_pbuffer' then Result := Load_WGL_EXT_pbuffer
-  else if ext = 'WGL_EXT_pixel_format' then Result := Load_WGL_EXT_pixel_format
-  else if ext = 'WGL_I3D_digital_video_control' then Result := Load_WGL_I3D_digital_video_control
-  else if ext = 'WGL_I3D_gamma' then Result := Load_WGL_I3D_gamma
-  else if ext = 'WGL_I3D_genlock' then Result := Load_WGL_I3D_genlock
-  else if ext = 'GL_ARB_matrix_palette' then Result := Load_GL_ARB_matrix_palette
-  else if ext = 'GL_NV_element_array' then Result := Load_GL_NV_element_array
-  else if ext = 'GL_NV_float_buffer' then Result := Load_GL_NV_float_buffer
-  else if ext = 'GL_NV_fragment_program' then Result := Load_GL_NV_fragment_program
-  else if ext = 'GL_NV_primitive_restart' then Result := Load_GL_NV_primitive_restart
-  else if ext = 'GL_NV_vertex_program2' then Result := Load_GL_NV_vertex_program2
-  else if ext = 'WGL_NV_render_texture_rectangle' then Result := Load_WGL_NV_render_texture_rectangle
-  else if ext = 'GL_NV_pixel_data_range' then Result := Load_GL_NV_pixel_data_range
-  else if ext = 'GL_EXT_texture_rectangle' then Result := Load_GL_EXT_texture_rectangle
-  else if ext = 'GL_S3_s3tc' then Result := Load_GL_S3_s3tc
-  else if ext = 'GL_ATI_draw_buffers' then Result := Load_GL_ATI_draw_buffers
-  else if ext = 'WGL_ATI_pixel_format_float' then Result := Load_WGL_ATI_pixel_format_float
-  else if ext = 'GL_ATI_texture_env_combine3' then Result := Load_GL_ATI_texture_env_combine3
-  else if ext = 'GL_ATI_texture_float' then Result := Load_GL_ATI_texture_float
-  else if ext = 'GL_NV_texture_expand_normal' then Result := Load_GL_NV_texture_expand_normal
-  else if ext = 'GL_NV_half_float' then Result := Load_GL_NV_half_float
-  else if ext = 'GL_ATI_map_object_buffer' then Result := Load_GL_ATI_map_object_buffer
-  else if ext = 'GL_ATI_separate_stencil' then Result := Load_GL_ATI_separate_stencil
-  else if ext = 'GL_ATI_vertex_attrib_array_object' then Result := Load_GL_ATI_vertex_attrib_array_object
-  else if ext = 'GL_ARB_vertex_buffer_object' then Result := Load_GL_ARB_vertex_buffer_object
-  else if ext = 'GL_ARB_occlusion_query' then Result := Load_GL_ARB_occlusion_query
-  else if ext = 'GL_ARB_shader_objects' then Result := Load_GL_ARB_shader_objects
-  else if ext = 'GL_ARB_vertex_shader' then Result := Load_GL_ARB_vertex_shader
-  else if ext = 'GL_ARB_fragment_shader' then Result := Load_GL_ARB_fragment_shader
-  else if ext = 'GL_ARB_shading_language_100' then Result := Load_GL_ARB_shading_language_100
-  else if ext = 'GL_ARB_texture_non_power_of_two' then Result := Load_GL_ARB_texture_non_power_of_two
-  else if ext = 'GL_ARB_point_sprite' then Result := Load_GL_ARB_point_sprite
-  else if ext = 'GL_EXT_depth_bounds_test' then Result := Load_GL_EXT_depth_bounds_test
-  else if ext = 'GL_EXT_secondary_color' then Result := Load_GL_EXT_secondary_color
-  else if ext = 'GL_EXT_texture_mirror_clamp' then Result := Load_GL_EXT_texture_mirror_clamp
-  else if ext = 'GL_EXT_blend_equation_separate' then Result := Load_GL_EXT_blend_equation_separate
-  else if ext = 'GL_MESA_pack_invert' then Result := Load_GL_MESA_pack_invert
-  else if ext = 'GL_MESA_ycbcr_texture' then Result := Load_GL_MESA_ycbcr_texture
-  else if ext = 'GL_ARB_fragment_program_shadow' then Result := Load_GL_ARB_fragment_program_shadow
-  else if ext = 'GL_EXT_fog_coord' then Result := Load_GL_EXT_fog_coord
-  else if ext = 'GL_NV_fragment_program_option' then Result := Load_GL_NV_fragment_program_option
-  else if ext = 'GL_EXT_pixel_buffer_object' then Result := Load_GL_EXT_pixel_buffer_object
-  else if ext = 'GL_NV_fragment_program2' then Result := Load_GL_NV_fragment_program2
-  else if ext = 'GL_NV_vertex_program2_option' then Result := Load_GL_NV_vertex_program2_option
-  else if ext = 'GL_NV_vertex_program3' then Result := Load_GL_NV_vertex_program3
-  else if ext = 'GL_ARB_draw_buffers' then Result := Load_GL_ARB_draw_buffers
-  else if ext = 'GL_ARB_texture_rectangle' then Result := Load_GL_ARB_texture_rectangle
-  else if ext = 'GL_ARB_color_buffer_float' then Result := Load_GL_ARB_color_buffer_float
-  else if ext = 'GL_ARB_half_float_pixel' then Result := Load_GL_ARB_half_float_pixel
-  else if ext = 'GL_ARB_texture_float' then Result := Load_GL_ARB_texture_float
-  else if ext = 'GL_EXT_texture_compression_dxt1' then Result := Load_GL_EXT_texture_compression_dxt1
-  else if ext = 'GL_ARB_pixel_buffer_object' then Result := Load_GL_ARB_pixel_buffer_object
-  else if ext = 'GL_EXT_framebuffer_object' then Result := Load_GL_EXT_framebuffer_object
-  else if ext = 'GL_version_1_4' then Result := Load_GL_version_1_4
-  else if ext = 'GL_version_1_5' then Result := Load_GL_version_1_5
-  else if ext = 'GL_version_2_0' then Result := Load_GL_version_2_0
-
-end;
-
-end.
diff --git a/src/lib/vampimg/Imaging.pas b/src/lib/vampimg/Imaging.pas
new file mode 100644 (file)
index 0000000..f21fa64
--- /dev/null
@@ -0,0 +1,4252 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit is heart of Imaging library. It contains basic functions for
+  manipulating image data as well as various image file format support.}
+unit Imaging;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, Classes, Types, ImagingTypes;
+
+type
+  { Default Imaging excepton class }
+  EImagingError = class(Exception);
+  { Raised when function receives bad image (not passed TestImage).}
+  EImagingBadImage = class(Exception)
+  public
+    constructor Create;
+  end;
+
+  { Dynamic array of TImageData records }
+  TDynImageDataArray = array of TImageData;
+
+
+{ ------------------------------------------------------------------------
+                       Low Level Interface Functions
+  ------------------------------------------------------------------------}
+
+{ General Functions }
+
+{ Initializes image (all is set to zeroes). Call this for each image
+  before using it (before calling every other function) to be sure there
+  are no random-filled bytes (which would cause errors later).}
+procedure InitImage(var Image: TImageData);
+{ Creates empty image of given dimensions and format. Image is filled with
+  transparent black color (A=0, R=0, G=0, B=0).}
+function NewImage(Width, Height: LongInt; Format: TImageFormat;
+  var Image: TImageData): Boolean;
+{ Returns True if given TImageData record is valid.}
+function TestImage(const Image: TImageData): Boolean;
+{ Frees given image data. Ater this call image is in the same state
+  as after calling InitImage. If image is not valid (dost not pass TestImage
+  test) it is only zeroed by calling InitImage.}
+procedure FreeImage(var Image: TImageData);
+{ Call FreeImage() on all images in given dynamic array and sets its
+  length to zero.}
+procedure FreeImagesInArray(var Images: TDynImageDataArray);
+{ Returns True if all TImageData records in given array are valid. Returns False
+  if at least one is invalid or if array is empty.}
+function TestImagesInArray(const Images: TDynImageDataArray): Boolean;
+{ Checks given file for every supported image file format and if
+  the file is in one of them returns its string identifier
+  (which can be used in LoadFromStream/LoadFromMem type functions).
+  If file is not in any of the supported formats empty string is returned.}
+function DetermineFileFormat(const FileName: string): string;
+{ Checks given stream for every supported image file format and if
+  the stream is in one of them returns its string identifier
+  (which can be used in LoadFromStream/LoadFromMem type functions).
+  If stream is not in any of the supported formats empty string is returned.}
+function DetermineStreamFormat(Stream: TStream): string;
+{ Checks given memory for every supported image file format and if
+  the memory is in one of them returns its string identifier
+  (which can be used in LoadFromStream/LoadFromMem type functions).
+  If memory is not in any of the supported formats empty string is returned.}
+function DetermineMemoryFormat(Data: Pointer; Size: LongInt): string;
+{ Checks that an apropriate file format is supported purely from inspecting
+  the given file name's extension (not contents of the file itself).
+  The file need not exist.}
+function IsFileFormatSupported(const FileName: string): Boolean;
+{ Enumerates all registered image file formats. Descriptive name,
+  default extension, masks (like '*.jpg,*.jfif') and some capabilities
+  of each format are returned. To enumerate all formats start with Index at 0 and
+  call EnumFileFormats with given Index in loop until it returns False (Index is
+  automatically increased by 1 in function's body on successful call).}
+function EnumFileFormats(var Index: LongInt; var Name, DefaultExt, Masks: string;
+  var CanSaveImages, IsMultiImageFormat: Boolean): Boolean;
+
+{ Loading Functions }
+
+{ Loads single image from given file.}
+function LoadImageFromFile(const FileName: string; var Image: TImageData): Boolean;
+{ Loads single image from given stream. If function fails stream position
+  is not changed.}
+function LoadImageFromStream(Stream: TStream; var Image: TImageData): Boolean;
+{ Loads single image from given memory location.}
+function LoadImageFromMemory(Data: Pointer; Size: LongInt; var Image: TImageData): Boolean;
+{ Loads multiple images from given file.}
+function LoadMultiImageFromFile(const FileName: string;
+  var Images: TDynImageDataArray): Boolean;
+{ Loads multiple images from given stream. If function fails stream position
+  is not changed.}
+function LoadMultiImageFromStream(Stream: TStream;
+  var Images: TDynImageDataArray): Boolean;
+{ Loads multiple images from given memory location.}
+function LoadMultiImageFromMemory(Data: Pointer; Size: LongInt;
+  var Images: TDynImageDataArray): Boolean;
+
+{ Saving Functions }
+
+{ Saves single image to given file.}
+function SaveImageToFile(const FileName: string; const Image: TImageData): Boolean;
+{ Saves single image to given stream. If function fails stream position
+  is not changed. Ext identifies desired image file format (jpg, png, dds, ...).}
+function SaveImageToStream(const Ext: string; Stream: TStream;
+  const Image: TImageData): Boolean;
+{ Saves single image to given memory location. Memory must be allocated and its
+  size is passed in Size parameter in which number of written bytes is returned.
+  Ext identifies desired image file format (jpg, png, dds, ...).}
+function SaveImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt;
+  const Image: TImageData): Boolean;
+{ Saves multiple images to given file. If format supports
+  only single level images and there are multiple images to be saved,
+  they are saved as sequence of files img000.jpg, img001.jpg ....).}
+function SaveMultiImageToFile(const FileName: string;
+  const Images: TDynImageDataArray): Boolean;
+{ Saves multiple images to given stream. If format supports
+  only single level images and there are multiple images to be saved,
+  they are saved one after another to the stream. If function fails stream
+  position is not changed. Ext identifies desired image file format (jpg, png, dds, ...).}
+function SaveMultiImageToStream(const Ext: string; Stream: TStream;
+  const Images: TDynImageDataArray): Boolean;
+{ Saves multiple images to given memory location. If format supports
+  only single level images and there are multiple images to be saved,
+  they are saved one after another to the memory. Memory must be allocated and
+  its size is passed in Size parameter in which number of written bytes is returned.
+  Ext identifies desired image file format (jpg, png, dds, ...).}
+function SaveMultiImageToMemory(const Ext: string; Data: Pointer;
+  var Size: LongInt; const Images: TDynImageDataArray): Boolean;
+
+{ Manipulation Functions }
+
+{ Creates identical copy of image data. Clone should be initialized
+  by InitImage or it should be vaild image which will be freed by CloneImage.}
+function CloneImage(const Image: TImageData; var Clone: TImageData): Boolean;
+{ Converts image to the given format.}
+function ConvertImage(var Image: TImageData; DestFormat: TImageFormat): Boolean;
+{ Flips given image. Reverses the image along its horizontal axis - the top
+  becomes the bottom and vice versa.}
+function FlipImage(var Image: TImageData): Boolean;
+{ Mirrors given image. Reverses the image along its vertical axis \97 the left
+  side becomes the right and vice versa.}
+function MirrorImage(var Image: TImageData): Boolean;
+{ Resizes given image to new dimensions. Nearest, bilinear, or bicubic filtering
+  can be used. Input Image must already be created - use NewImage to create new images.}
+function ResizeImage(var Image: TImageData; NewWidth, NewHeight: LongInt;
+  Filter: TResizeFilter): Boolean;
+{ Swaps SrcChannel and DstChannel color or alpha channels of image.
+  Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to
+  identify channels.}
+function SwapChannels(var Image: TImageData; SrcChannel, DstChannel: LongInt): Boolean;
+{ Reduces the number of colors of the Image. Currently MaxColors must be in
+  range <2, 4096>. Color reduction works also for alpha channel. Note that for
+  large images and big number of colors it can be very slow.
+  Output format of the image is the same as input format.}
+function ReduceColors(var Image: TImageData; MaxColors: LongInt): Boolean;
+{ Generates mipmaps for image. Levels is the number of desired mipmaps levels
+  with zero (or some invalid number) meaning all possible levels.}
+function GenerateMipMaps(const Image: TImageData; Levels: LongInt;
+  var MipMaps: TDynImageDataArray): Boolean;
+{ Maps image to existing palette producing image in ifIndex8 format.
+  Pal must be allocated to at least Entries * SizeOf(TColor32Rec) bytes.
+  As resulting image is in 8bit indexed format Entries must be lower or
+  equal to 256.}
+function MapImageToPalette(var Image: TImageData; Pal: PPalette32;
+  Entries: LongInt): Boolean;
+{ Splits image into XChunks x YChunks subimages. Default size of each chunk is
+  ChunkWidth x ChunkHeight. If PreserveSize si True chunks at the edges of
+  the image are also ChunkWidth x ChunkHeight sized and empty space is filled
+  with optional Fill pixels. After calling this function XChunks contains number of
+  chunks along x axis and YChunks along y axis. To access chunk [X, Y] use this
+  index: Chunks[Y * XChunks + X].}
+function SplitImage(var Image: TImageData; var Chunks: TDynImageDataArray;
+  ChunkWidth, ChunkHeight: LongInt; var XChunks, YChunks: LongInt;
+  PreserveSize: Boolean; Fill: Pointer = nil): Boolean;
+{ Creates palette with MaxColors based on the colors of images in Images array.
+  Use it when you want to convert several images to indexed format using
+  single palette for all of them. If ConvertImages is True images in array
+  are converted to indexed format using resulting palette. if it is False
+  images are left intact and only resulting palatte is returned in Pal.
+  Pal must be allocated to have at least MaxColors entries.}
+function MakePaletteForImages(var Images: TDynImageDataArray; Pal: PPalette32;
+  MaxColors: LongInt; ConvertImages: Boolean): Boolean;
+{ Rotates image by Angle degrees counterclockwise. All angles are allowed.}
+procedure RotateImage(var Image: TImageData; Angle: Single);
+
+{ Drawing/Pixel functions }
+
+{ Copies rectangular part of SrcImage to DstImage. No blending is performed -
+  alpha is simply copied to destination image. Operates also with
+  negative X and Y coordinates.
+  Note that copying is fastest for images in the same data format
+  (and slowest for images in special formats).}
+function CopyRect(const SrcImage: TImageData; SrcX, SrcY, Width, Height: LongInt;
+  var DstImage: TImageData; DstX, DstY: LongInt): Boolean;
+{ Fills given rectangle of image with given pixel fill data. Fill should point
+  to the pixel in the same format as the given image is in.}
+function FillRect(var Image: TImageData; X, Y, Width, Height: LongInt; FillColor: Pointer): Boolean;
+{ Replaces pixels with OldPixel in the given rectangle by NewPixel.
+  OldPixel and NewPixel should point to the pixels in the same format
+  as the given image is in.}
+function ReplaceColor(var Image: TImageData; X, Y, Width, Height: LongInt;
+  OldColor, NewColor: Pointer): Boolean;
+{ Stretches the contents of the source rectangle to the destination rectangle
+  with optional resampling. No blending is performed - alpha is
+  simply copied/resampled to destination image. Note that stretching is
+  fastest for images in the same data format (and slowest for
+  images in special formats).}
+function StretchRect(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt; Filter: TResizeFilter): Boolean;
+{ Copies pixel of Image at [X, Y] to memory pointed at by Pixel. Doesn't
+  work with special formats.}
+procedure GetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer);
+{ Copies pixel from memory pointed at by Pixel to Image at position [X, Y].
+  Doesn't work with special formats.}
+procedure SetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer);
+{ Function for getting pixel colors. Native pixel is read from Image and
+  then translated to 32 bit ARGB. Works for all image formats (except special)
+  so it is not very fast.}
+function GetPixel32(const Image: TImageData; X, Y: LongInt): TColor32Rec;
+{ Procedure for setting pixel colors. Input 32 bit ARGB color is translated to
+  native format and then written to Image. Works for all image formats (except special)
+  so it is not very fast.}
+procedure SetPixel32(const Image: TImageData; X, Y: LongInt; const Color: TColor32Rec);
+{ Function for getting pixel colors. Native pixel is read from Image and
+  then translated to FP ARGB. Works for all image formats (except special)
+  so it is not very fast.}
+function GetPixelFP(const Image: TImageData; X, Y: LongInt): TColorFPRec;
+{ Procedure for setting pixel colors. Input FP ARGB color is translated to
+  native format and then written to Image. Works for all image formats (except special)
+  so it is not very fast.}
+procedure SetPixelFP(const Image: TImageData; X, Y: LongInt; const Color: TColorFPRec);
+
+{ Palette Functions }
+
+{ Allocates new palette with Entries ARGB color entries.}
+procedure NewPalette(Entries: LongInt; var Pal: PPalette32);
+{ Frees given palette.}
+procedure FreePalette(var Pal: PPalette32);
+{ Copies Count palette entries from SrcPal starting at index SrcIdx to
+  DstPal at index DstPal.}
+procedure CopyPalette(SrcPal, DstPal: PPalette32; SrcIdx, DstIdx, Count: LongInt);
+{ Returns index of color in palette or index of nearest color if exact match
+  is not found. Pal must have at least Entries color entries.}
+function FindColor(Pal: PPalette32; Entries: LongInt; Color: TColor32): LongInt;
+{ Creates grayscale palette where each color channel has the same value.
+  Pal must have at least Entries color entries.}
+procedure FillGrayscalePalette(Pal: PPalette32; Entries: LongInt);
+{ Creates palette with given bitcount for each channel.
+  2^(RBits + GBits + BBits) should be equl to Entries. Examples:
+  (3, 3, 2) will create palette with all possible colors of R3G3B2 format
+  and (8, 0, 0) will create palette with 256 shades of red.
+  Pal must be allocated to at least Entries * SizeOf(TColor32Rec) bytes.}
+procedure FillCustomPalette(Pal: PPalette32; Entries: LongInt; RBits, GBits,
+  BBits: Byte; Alpha: Byte = $FF);
+{ Swaps SrcChannel and DstChannel color or alpha channels of palette.
+  Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to
+  identify channels. Pal must be allocated to at least
+  Entries * SizeOf(TColor32Rec) bytes.}
+procedure SwapChannelsOfPalette(Pal: PPalette32; Entries, SrcChannel,
+  DstChannel: LongInt);
+
+{ Options Functions }
+
+{ Sets value of integer option specified by OptionId parameter.
+  Option Ids are constans starting ImagingXXX.}
+function SetOption(OptionId, Value: LongInt): Boolean;
+{ Returns value of integer option specified by OptionId parameter. If OptionId is
+  invalid, InvalidOption is returned. Option Ids are constans
+  starting ImagingXXX.}
+function GetOption(OptionId: LongInt): LongInt;
+{ Pushes current values of all options on the stack. Returns True
+  if successfull (max stack depth is 8 now). }
+function PushOptions: Boolean;
+{ Pops back values of all options from the top of the stack. Returns True
+  if successfull (max stack depth is 8 now). }
+function PopOptions: Boolean;
+
+{ Image Format Functions }
+
+{ Returns short information about given image format.}
+function GetImageFormatInfo(Format: TImageFormat; out Info: TImageFormatInfo): Boolean;
+{ Returns size in bytes of Width x Height area of pixels. Works for all formats.}
+function GetPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
+
+{ IO Functions }
+
+{ User can set his own file IO functions used when loading from/saving to
+  files by this function.}
+procedure SetUserFileIO(OpenProc: TOpenProc; CloseProc: TCloseProc; EofProc: TEofProc; SeekProc:
+  TSeekProc; TellProc: TTellProc; ReadProc: TReadProc; WriteProc: TWriteProc);
+{ Sets file IO functions to Imaging default.}
+procedure ResetFileIO;
+
+{ Raw Image IO Functions }
+
+procedure ReadRawImageFromFile(const FileName: string; Width, Height: Integer;
+  Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0);
+procedure ReadRawImageFromStream(Stream: TStream; Width, Height: Integer;
+  Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0);
+procedure ReadRawImageFromMemory(Data: Pointer; DataSize: Integer; Width, Height: Integer;
+  Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0);
+procedure ReadRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer;
+  var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0);
+
+procedure WriteRawImageToFile(const FileName: string; const Image: TImageData;
+  Offset: Integer = 0; RowLength: Integer = 0);
+procedure WriteRawImageToStream(Stream: TStream; const Image: TImageData;
+  Offset: Integer = 0; RowLength: Integer = 0);
+procedure WriteRawImageToMemory(Data: Pointer; DataSize: Integer; const Image: TImageData;
+  Offset: Integer = 0; RowLength: Integer = 0);
+procedure WriteRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer;
+  const Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0);
+
+{ Convenience/helper Functions }
+
+procedure ResizeImageToFit(const SrcImage: TImageData; FitWidth, FitHeight: Integer;
+  Filter: TResizeFilter; var DestImage: TImageData);
+
+
+{ ------------------------------------------------------------------------
+                           Other Imaging Stuff
+  ------------------------------------------------------------------------}
+
+type
+  { Set of TImageFormat enum.}
+  TImageFormats = set of TImageFormat;
+
+  { Record containg set of IO functions internaly used by image loaders/savers.}
+  TIOFunctions = record
+    Open: TOpenProc;
+    Close: TCloseProc;
+    Eof: TEofProc;
+    Seek: TSeekProc;
+    Tell: TTellProc;
+    Read: TReadProc;
+    Write: TWriteProc;
+  end;
+  PIOFunctions = ^TIOFunctions;
+
+type
+  TFileFormatFeature = (
+    ffLoad,
+    ffSave,
+    ffMultiImage,
+    ffReadOnSave,
+    ffProgress,
+    ffReadScanlines);
+
+  TFileFormatFeatures = set of TFileFormatFeature;
+
+  TMetadata = class;
+
+  { Base class for various image file format loaders/savers which
+    descend from this class. If you want to add support for new image file
+    format the best way is probably to look at TImageFileFormat descendants'
+    implementations that are already part of Imaging.}
+{$TYPEINFO ON}
+  TImageFileFormat = class
+  private
+    FExtensions: TStringList;
+    FMasks: TStringList;
+    function GetCanLoad: Boolean;
+    function GetCanSave: Boolean;
+    function GetIsMultiImageFormat: Boolean;
+    { Does various checks and actions before LoadData method is called.}
+    function PrepareLoad(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstFrame: Boolean): Boolean;
+    { Processes some actions according to result of LoadData.}
+    function PostLoadCheck(var Images: TDynImageDataArray; LoadResult: Boolean): Boolean;
+    { Helper function to be called in SaveData methods of descendants (ensures proper
+      index and sets FFirstIdx and FLastIdx for multi-images).}
+    function PrepareSave(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      var Index: LongInt): Boolean;
+    { Returns file open mode used for saving images. Depends on defined Features.}
+    function GetSaveOpenMode: TOpenMode;
+  protected
+    FName: string;
+    FFeatures: TFileFormatFeatures;
+    FSupportedFormats: TImageFormats;
+    FFirstIdx, FLastIdx: LongInt;
+    FMetadata: TMetadata;
+    { Descendants must override this method and define file format name and
+      capabilities.}
+    procedure Define; virtual;
+    { Defines filename masks for this image file format. AMasks should be
+      in format '*.ext1,*.ext2,umajo.*'.}
+    procedure AddMasks(const AMasks: string);
+    function GetFormatInfo(Format: TImageFormat): TImageFormatInfo;
+    { Returns set of TImageData formats that can be saved in this file format
+      without need for conversion.}
+    function GetSupportedFormats: TImageFormats; virtual;
+    { Method which must be overrided in descendants if they' are be capable
+      of loading images. Images are already freed and length is set to zero
+      whenever this method gets called. Also Handle is assured to be valid
+      and contains data that passed TestFormat method's check.}
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstFrame: Boolean): Boolean; virtual;
+    { Method which must be overriden in descendants if they are be capable
+      of saving images. Images are checked to have length >0 and
+      that they contain valid images. For single-image file formats
+      Index contain valid index to Images array (to image which should be saved).
+      Multi-image formats should use FFirstIdx and FLastIdx fields to
+      to get all images that are to be saved.}
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; virtual;
+    { This method is called internaly by MakeCompatible when input image
+      is in format not supported by this file format. Image is clone of
+      MakeCompatible's input and Info is its extended format info.}
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); virtual;
+    { Returns True if given image is supported for saving by this file format.
+      Most file formats don't need to override this method. It checks
+      (in this base class) if Image's format is in SupportedFromats set.
+      But you may override it if you want further checks
+      (proper widht and height for example).}
+    function IsSupported(const Image: TImageData): Boolean; virtual;
+  public
+    constructor Create(AMetadata: TMetadata = nil); virtual;
+    destructor Destroy; override;
+
+    { Loads images from file source.}
+    function LoadFromFile(const FileName: string; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean = False): Boolean;
+    { Loads images from stream source.}
+    function LoadFromStream(Stream: TStream; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean = False): Boolean;
+    { Loads images from memory source.}
+    function LoadFromMemory(Data: Pointer; Size: LongInt;
+      var Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean;
+
+    { Saves images to file. If format supports only single level images and
+      there are multiple images to be saved, they are saved as sequence of
+      independent images (for example SaveToFile saves sequence of
+      files img000.jpg, img001.jpg ....).}
+    function SaveToFile(const FileName: string; const Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean = False): Boolean;
+    { Saves images to stream. If format supports only single level images and
+      there are multiple images to be saved, they are saved as sequence of
+      independent images.}
+    function SaveToStream(Stream: TStream; const Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean = False): Boolean;
+    { Saves images to memory. If format supports only single level images and
+      there are multiple images to be saved, they are saved as sequence of
+      independent images. Data must be already allocated and their size passed
+      as Size parameter, number of written bytes is then returned in the same
+      parameter.}
+    function SaveToMemory(Data: Pointer; var Size: LongInt;
+      const Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean;
+
+    { Makes Image compatible with this file format (that means it is in one
+      of data formats in Supported formats set). If input is already
+      in supported format then Compatible just use value from input
+      (Compatible := Image) so must not free it after you are done with it
+      (image bits pointer points to input image's bits).
+      If input is not in supported format then it is cloned to Compatible
+      and concerted to one of supported formats (which one dependeds on
+      this file format). If image is cloned MustBeFreed is set to True
+      to indicated that you must free Compatible after you are done with it.}
+    function MakeCompatible(const Image: TImageData; var Compatible: TImageData;
+      out MustBeFreed: Boolean): Boolean;
+    { Returns True if data located in source identified by Handle
+      represent valid image in current format.}
+    function TestFormat(Handle: TImagingHandle): Boolean; virtual;
+    { Resturns True if the given FileName matches filter for this file format.
+      For most formats it just checks filename extensions.
+      It uses filename masks in from Masks property so it can recognize
+      filenames like this 'umajoXXXumajo.j0j' if one of themasks is
+      'umajo*umajo.j?j'.}
+    function TestFileName(const FileName: string): Boolean;
+    { Descendants use this method to check if their options (registered with
+      constant Ids for SetOption/GetOption interface or accessible as properties
+      of descendants) have valid values and make necessary changes.}
+    procedure CheckOptionsValidity; virtual;
+
+    { Description of this format.}
+    property Name: string read FName;
+    { Indicates whether images in this format can be loaded.}
+    property CanLoad: Boolean read GetCanLoad;
+    { Indicates whether images in this format can be saved.}
+    property CanSave: Boolean read GetCanSave;
+    { Indicates whether images in this format can contain multiple image levels.}
+    property IsMultiImageFormat: Boolean read GetIsMultiImageFormat;
+    { List of filename extensions for this format.}
+    property Extensions: TStringList read FExtensions;
+    { List of filename masks that are used to associate filenames
+      with TImageFileFormat descendants. Typical mask looks like
+      '*.bmp' or 'texture.*' (supports file formats which use filename instead
+      of extension to identify image files).}
+    property Masks: TStringList read FMasks;
+    { Set of TImageFormats supported by saving functions of this format. Images
+      can be saved only in one those formats.}
+    property SupportedFormats: TImageFormats read GetSupportedFormats;
+  end;
+{$TYPEINFO OFF}
+
+  { Class reference for TImageFileFormat class}
+  TImageFileFormatClass = class of TImageFileFormat;
+
+  { Physical resolution unit.}
+  TResolutionUnit = (
+    ruSizeInMicroMeters, // value is pixel size in micrometers
+    ruDpi,               // value is pixels/dots per inch
+    ruDpm,               // value is pixels/dots per meter
+    ruDpcm               // value is pixels/dots per centimeter
+  );
+
+  { Class for storage of single metadata item.}
+  TMetadataItem = class
+  public
+    Id: string;
+    ImageIndex: Integer;
+    Value: Variant;
+  end;
+
+  { Metadata manager class.}
+  TMetadata = class
+  private
+    FLoadMetaItems: TStringList;
+    FSaveMetaItems: TStringList;
+    procedure AddMetaToList(List: TStringList; const Id: string; const Value: Variant; ImageIndex: Integer);
+    procedure ClearMetaList(List: TStringList);
+    function GetMetaById(const Id: string): Variant;
+    function GetMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant;
+    function GetMetaCount: Integer;
+    function GetMetaByIdx(Index: Integer): TMetadataItem;
+    function GetSaveMetaById(const Id: string): Variant;
+    function GetSaveMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant;
+    procedure TranslateUnits(ResolutionUnit: TResolutionUnit; var XRes, YRes: Single);
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    procedure SetMetaItem(const Id: string; const Value: Variant; ImageIndex: Integer = 0);
+    procedure SetMetaItemForSaving(const Id: string; const Value: Variant; ImageIndex: Integer = 0);
+    function HasMetaItem(const Id: string; ImageIndex: Integer = 0): Boolean;
+    function HasMetaItemForSaving(const Id: string; ImageIndex: Integer = 0): Boolean;
+
+    procedure ClearMetaItems;
+    procedure ClearMetaItemsForSaving;
+    function GetMetaItemName(const Id: string; ImageIndex: Integer): string;
+    { Copies loaded meta items to items-for-save stack. Use this when you want to
+      save metadata that have been just loaded (e.g. resaving image in
+      different file format but keeping the metadata).}
+    procedure CopyLoadedMetaItemsForSaving;
+
+    function GetPhysicalPixelSize(ResUnit: TResolutionUnit; var XSize,
+      YSize: Single; MetaForSave: Boolean = False; ImageIndex: Integer = 0): Boolean;
+    procedure SetPhysicalPixelSize(ResUnit: TResolutionUnit; XSize, YSize: Single;
+      MetaForSave: Boolean = False; ImageIndex: Integer = 0);
+
+    property MetaItems[const Id: string]: Variant read GetMetaById;
+    property MetaItemsMulti[const Id: string; ImageIndex: Integer]: Variant read GetMetaByIdMulti;
+    { Number of loaded metadata items.}
+    property MetaItemCount: Integer read GetMetaCount;
+    property MetaItemsByIdx[Index: Integer]: TMetadataItem read GetMetaByIdx;
+    property MetaItemsForSaving[const Id: string]: Variant read GetSaveMetaById;
+    property MetaItemsForSavingMulti[const Id: string; ImageIndex: Integer]: Variant read GetSaveMetaByIdMulti;
+  end;
+
+const
+  { Metadata item id constants }
+
+  { Physical size of one pixel in micrometers. Type of value is Float.}
+  SMetaPhysicalPixelSizeX = 'PhysicalPixelSizeX';
+  SMetaPhysicalPixelSizeY = 'PhysicalPixelSizeY';
+  { Delay for frame of animation (how long it should stay visible) in milliseconds.
+    Type of value is Integer.}
+  SMetaFrameDelay = 'FrameDelay';
+  { Number of times animation should be looped (0 = infinite looping). Type is Int. }
+  SMetaAnimationLoops = 'AnimationLoops';
+  { Gamma correction value. Type is Float.}
+  SMetaGamma = 'Gamma';
+  { Exposure value for HDR etc. Type is Float.}
+  SMetaExposure = 'Exposure';
+  { EXIF image metadata raw blob.}
+  SMetaExifBlob = 'ExifBlob';
+  { XMP image metadata raw blob.}
+  SMetaXmpBlob  = 'XmpBlob';
+  { IPTC image metadata raw blob.}
+  SMetaIptcBlob = 'IptcBlob';
+
+var
+  GlobalMetadata: TMetadata;
+
+{ Returns symbolic name of given format.}
+function GetFormatName(Format: TImageFormat): string;
+{ Returns string with information about given Image.}
+function ImageToStr(const Image: TImageData): string;
+{ Returns Imaging version string in format 'Major.Minor.Patch'.}
+function GetVersionStr: string;
+{ If Condition is True then TruePart is retured, otherwise FalsePart is returned.}
+function IffFormat(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat;
+
+{ Registers new option so it can be used by SetOption and GetOption functions.
+  Returns True if registration was succesful - that is Id is valid and is
+  not already taken by another option.}
+function RegisterOption(OptionId: LongInt; Variable: PLongInt): Boolean;
+
+{ Registers new image loader/saver so it can be used by LoadFrom/SaveTo
+  functions.}
+procedure RegisterImageFileFormat(AClass: TImageFileFormatClass);
+{ Returns image format loader/saver according to given extension
+  or nil if not found.}
+function FindImageFileFormatByExt(const Ext: string): TImageFileFormat;
+{ Returns image format loader/saver according to given filename
+  or nil if not found.}
+function FindImageFileFormatByName(const FileName: string): TImageFileFormat;
+{ Returns image format loader/saver based on its class
+  or nil if not found or not registered.}
+function FindImageFileFormatByClass(AClass: TImageFileFormatClass): TImageFileFormat;
+{ Returns number of registered image file format loaders/saver.}
+function GetFileFormatCount: LongInt;
+{ Returns image file format loader/saver at given index. Index must be
+  in range [0..GetFileFormatCount - 1] otherwise nil is returned.}
+function GetFileFormatAtIndex(Index: LongInt): TImageFileFormat;
+{ Returns filter string for usage with open and save picture dialogs
+  which contains all registered image file formats.
+  Set OpenFileFilter to True if you want filter for open dialog
+  and to False if you want save dialog filter (formats that cannot save to files
+  are not added then).
+  For open dialog filter for all known graphic files
+  (like All(*.jpg;*.png;....) is added too at the first index.}
+function GetImageFileFormatsFilter(OpenFileFilter: Boolean): string;
+{ Returns file extension (without dot) of image format selected
+  by given filter index. Used filter string is defined by GetImageFileFormatsFilter
+  function. This function can be used with save dialogs (with filters created
+  by GetImageFileFormatsFilter) to get the extension of file format selected
+  in dialog quickly. Index is in range 1..N (as FilterIndex property
+  of TOpenDialog/TSaveDialog)}
+function GetFilterIndexExtension(Index: LongInt; OpenFileFilter: Boolean): string;
+{ Returns filter index of image file format of file specified by FileName. Used filter
+  string is defined by GetImageFileFormatsFilter function.
+  Returned index is in range 1..N (as FilterIndex property of TOpenDialog/TSaveDialog)}
+function GetFileNameFilterIndex(const FileName: string; OpenFileFilter: Boolean): LongInt;
+
+{ Returns current IO functions.}
+function GetIO: TIOFunctions;
+{ Raises EImagingError with given message.}
+procedure RaiseImaging(const Msg: string; const Args: array of const); overload;
+procedure RaiseImaging(const Msg: string); overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+
+const
+  SImagingLibTitle = 'Vampyre Imaging Library';
+
+implementation
+
+uses
+{$IFNDEF DONT_LINK_BITMAP}
+  ImagingBitmap,
+{$ENDIF}
+{$IFNDEF DONT_LINK_JPEG}
+  ImagingJpeg,
+{$ENDIF}
+{$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)}
+  ImagingNetworkGraphics,
+{$IFEND}
+{$IFNDEF DONT_LINK_GIF}
+  ImagingGif,
+{$ENDIF}
+{$IFNDEF DONT_LINK_DDS}
+  ImagingDds,
+{$ENDIF}
+{$IFNDEF DONT_LINK_TARGA}
+  ImagingTarga,
+{$ENDIF}
+{$IFNDEF DONT_LINK_PNM}
+  ImagingPortableMaps,
+{$ENDIF}
+{$IFNDEF DONT_LINK_RADHDR}
+  ImagingRadiance,
+{$ENDIF}
+{$IFNDEF DONT_LINK_EXTRAS}
+  ImagingExtras,
+{$ENDIF}
+  //ImagingDebug,
+  ImagingFormats, ImagingUtility, ImagingIO, Variants;
+
+resourcestring
+  SExceptMsg = 'Exception Message';
+  SAllFilter = 'All Images';
+  SUnknownFormat = 'Unknown and unsupported format';
+
+  SErrorFreeImage = 'Error while freeing image. %s';
+  SErrorCloneImage = 'Error while cloning image. %s';
+  SErrorFlipImage = 'Error while flipping image. %s';
+  SErrorMirrorImage = 'Error while mirroring image. %s';
+  SErrorResizeImage = 'Error while resizing image.  %s';
+  SErrorSwapImage = 'Error while swapping channels of image. %s';
+  SFileFormatCanNotLoad = 'Image Format "%s" does not support loading images.';
+  SFileFormatCanNotSave = 'Image Format "%s" does not support saving images.';
+  SErrorNewImage = 'Error while creating image data with params: Width=%d ' +
+    'Height=%d Format=%s.';
+  SErrorConvertImage = 'Error while converting image to format "%s". %s';
+  SImageInfo = 'Image @%p info: Width = %dpx, Height = %dpx, ' +
+    'Format = %s, Size = %.0n %s, Bits @%p, Palette @%p.';
+  SImageInfoInvalid = 'Access violation encountered when getting info on ' +
+    'image at address %p.';
+  SFileNotValid = 'File "%s" is not valid image in "%s" format.';
+  SStreamNotValid = 'Stream %p does not contain valid image in "%s" format.';
+  SMemoryNotValid = 'Memory %p (%d Bytes) does not contain valid image ' +
+    'in "%s" format.';
+  SErrorLoadingFile = 'Error while loading images from file "%s" (file format: %s).';
+  SErrorLoadingStream = 'Error while loading images from stream %p (file format: %s).';
+  SErrorLoadingMemory = 'Error while loading images from memory %p (%d Bytes) (file format: %s).';
+  SErrorSavingFile = 'Error while saving images to file "%s" (file format: %s).';
+  SErrorSavingStream = 'Error while saving images to stream %p (file format: %s).';
+  SErrorSavingMemory = 'Error while saving images to memory %p (%d Bytes) (file format: %s).';
+  SErrorFindColor = 'Error while finding color in palette @%p with %d entries.';
+  SErrorGrayscalePalette = 'Error while filling grayscale palette @%p with %d entries.';
+  SErrorCustomPalette = 'Error while filling custom palette @%p with %d entries.';
+  SErrorSwapPalette = 'Error while swapping channels of palette @%p with %d entries.';
+  SErrorReduceColors = 'Error while reducing number of colors of image to %d. %s';
+  SErrorGenerateMipMaps = 'Error while generating %d mipmap levels for image %s';
+  SImagesNotValid = 'One or more images are not valid.';
+  SErrorCopyRect = 'Error while copying rect from image %s to image %s.';
+  SErrorMapImage = 'Error while mapping image %s to palette.';
+  SErrorFillRect = 'Error while filling rectangle X:%d Y:%d W:%d H:%d in image %s';
+  SErrorSplitImage = 'Error while splitting image %s to %dx%d sized chunks.';
+  SErrorMakePaletteForImages = 'Error while making %d color palette for %d images.';
+  SErrorNewPalette = 'Error while creating new palette with %d entries';
+  SErrorFreePalette = 'Error while freeing palette @%p';
+  SErrorCopyPalette = 'Error while copying %d entries from palette @%p to @%p';
+  SErrorReplaceColor = 'Error while replacing colors in rectangle X:%d Y:%d W:%d H:%d of image %s';
+  SErrorRotateImage = 'Error while rotating image %s by %.2n degrees';
+  SErrorStretchRect = 'Error while stretching rect from image %s to image %s.';
+  SErrorEmptyStream = 'Input stream has no data. Check Position property.';
+  SErrorInvalidInputImage = 'Invalid input image.';
+
+  SErrorBadImage = 'Bad image detected.';
+
+const
+  // Initial size of array with options information
+  InitialOptions = 256;
+  // Max depth of the option stack
+  OptionStackDepth = 8;
+  // Do not change the default format now, its too late
+  DefaultImageFormat: TImageFormat = ifA8R8G8B8;
+  // Format used to create metadata IDs for frames loaded form multiimages.
+  SMetaIdForSubImage = '%s/%d';
+
+type
+  TOptionArray = array of PLongInt;
+  TOptionValueArray = array of LongInt;
+
+  TOptionStack = class(TObject)
+  private
+    FStack: array[0..OptionStackDepth - 1] of TOptionValueArray;
+    FPosition: LongInt;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function Push: Boolean;
+    function Pop: Boolean;
+  end;
+
+var
+  // Currently set IO functions
+  IO: TIOFunctions;
+  // List with all registered TImageFileFormat classes
+  ImageFileFormats: TList = nil;
+  // Aarray with registered options (pointers to their values)
+  Options: TOptionArray = nil;
+  // Array containing addional infomation about every image format
+  ImageFormatInfos: TImageFormatInfoArray;
+  // Stack used by PushOptions/PopOtions functions
+  OptionStack: TOptionStack = nil;
+var
+  // Variable for ImagingColorReduction option
+  ColorReductionMask: LongInt = $FF;
+  // Variable for ImagingLoadOverrideFormat option
+  LoadOverrideFormat: TImageFormat = ifUnknown;
+  // Variable for ImagingSaveOverrideFormat option
+  SaveOverrideFormat: TImageFormat = ifUnknown;
+  // Variable for ImagingSaveOverrideFormat option
+  MipMapFilter: TSamplingFilter = sfLinear;
+  // Variable for ImagingBinaryTreshold option
+  BinaryTreshold: Integer = 128;
+
+{ Exceptions }
+
+constructor EImagingBadImage.Create;
+begin
+  inherited Create(SErrorBadImage);
+end;
+
+{ Internal unit functions }
+
+{ Modifies option value to be in the allowed range. Works only
+  for options registered in this unit.}
+function CheckOptionValue(OptionId, Value: LongInt): LongInt; forward;
+{ Sets IO functions to file IO.}
+procedure SetFileIO; forward;
+{ Sets IO functions to stream IO.}
+procedure SetStreamIO; forward;
+{ Sets IO functions to memory IO.}
+procedure SetMemoryIO; forward;
+{ Inits image format infos array.}
+procedure InitImageFormats; forward;
+{ Freew image format infos array.}
+procedure FreeImageFileFormats; forward;
+{ Creates options array and stack.}
+procedure InitOptions; forward;
+{ Frees options array and stack.}
+procedure FreeOptions; forward;
+
+function UpdateExceptMessage(E: Exception; const MsgToPrepend: string; const Args: array of const): Exception;
+begin
+  Result := E;
+  E.Message := Format(MsgToPrepend, Args) +  ' ' + SExceptMsg + ': ' + E.Message
+end;
+
+{ ------------------------------------------------------------------------
+                       Low Level Interface Functions
+  ------------------------------------------------------------------------}
+
+{ General Functions }
+
+procedure InitImage(var Image: TImageData);
+begin
+  FillChar(Image, SizeOf(Image), 0);
+end;
+
+function NewImage(Width, Height: LongInt; Format: TImageFormat; var Image:
+  TImageData): Boolean;
+var
+  FInfo: PImageFormatInfo;
+begin
+  Assert((Width > 0) and (Height >0));
+  Assert(IsImageFormatValid(Format));
+  Result := False;
+  FreeImage(Image);
+  try
+    Image.Width := Width;
+    Image.Height := Height;
+    // Select default data format if selected
+    if (Format = ifDefault)  then
+      Image.Format := DefaultImageFormat
+    else
+      Image.Format := Format;
+    // Get extended format info
+    FInfo := ImageFormatInfos[Image.Format];
+    if FInfo = nil then
+    begin
+      InitImage(Image);
+      Exit;
+    end;
+    // Check image dimensions and calculate its size in bytes
+    FInfo.CheckDimensions(FInfo.Format, Image.Width, Image.Height);
+    Image.Size := FInfo.GetPixelsSize(FInfo.Format, Image.Width, Image.Height);
+    if Image.Size = 0 then
+    begin
+      InitImage(Image);
+      Exit;
+    end;
+    // Image bits are allocated and set to zeroes
+    GetMem(Image.Bits, Image.Size);
+    FillChar(Image.Bits^, Image.Size, 0);
+    // Palette is allocated and set to zeroes
+    if FInfo.PaletteEntries > 0 then
+    begin
+      GetMem(Image.Palette, FInfo.PaletteEntries * SizeOf(TColor32Rec));
+      FillChar(Image.Palette^, FInfo.PaletteEntries * SizeOf(TColor32Rec), 0);
+    end;
+    Result := TestImage(Image);
+  except
+    on E: Exception do
+    begin
+      FreeMem(Image.Bits);
+      FreeMem(Image.Palette);
+      InitImage(Image);
+      raise UpdateExceptMessage(E, SErrorNewImage, [Width, Height, GetFormatName(Format)]);
+    end;
+  end;
+end;
+
+function TestImage(const Image: TImageData): Boolean;
+begin
+  try
+    Result := (LongInt(Image.Format) >= LongInt(Low(TImageFormat))) and
+      (LongInt(Image.Format) <= LongInt(High(TImageFormat))) and
+      (ImageFormatInfos[Image.Format] <> nil) and
+      (Assigned(ImageFormatInfos[Image.Format].GetPixelsSize) and
+      (ImageFormatInfos[Image.Format].GetPixelsSize(Image.Format,
+      Image.Width, Image.Height) = Image.Size));
+  except
+    // Possible int overflows or other errors
+    Result := False;
+  end;
+end;
+
+procedure FreeImage(var Image: TImageData);
+begin
+  try
+    if TestImage(Image) then
+    begin
+      FreeMemNil(Image.Bits);
+      FreeMemNil(Image.Palette);
+    end;
+    InitImage(Image);
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorFreeImage, [ImageToStr(Image)]);
+  end;
+end;
+
+procedure FreeImagesInArray(var Images: TDynImageDataArray);
+var
+  I: LongInt;
+begin
+  if Length(Images) > 0 then
+  begin
+    for I := 0 to Length(Images) - 1 do
+      FreeImage(Images[I]);
+    SetLength(Images, 0);
+  end;
+end;
+
+function TestImagesInArray(const Images: TDynImageDataArray): Boolean;
+var
+  I: LongInt;
+begin
+  if Length(Images) > 0 then
+  begin
+    Result := True;
+    for I := 0 to Length(Images) - 1 do
+    begin
+      Result := Result and TestImage(Images[I]);
+      if not Result then
+        Break;
+    end;
+  end
+  else
+    Result := False;
+end;
+
+function DetermineFileFormat(const FileName: string): string;
+var
+  I: LongInt;
+  Fmt: TImageFileFormat;
+  Handle: TImagingHandle;
+begin
+  Assert(FileName <> '');
+  Result := '';
+  SetFileIO;
+  Handle := IO.Open(PChar(FileName), omReadOnly);
+  try
+    // First file format according to FileName and test if the data in
+    // file is really in that format
+    for I := 0 to ImageFileFormats.Count - 1 do
+    begin
+      Fmt := TImageFileFormat(ImageFileFormats[I]);
+      if Fmt.TestFileName(FileName) and Fmt.TestFormat(Handle) then
+      begin
+        Result := Fmt.Extensions[0];
+        Exit;
+      end;
+    end;
+    // No file format was found with filename search so try data-based search
+    for I := 0 to ImageFileFormats.Count - 1 do
+    begin
+      Fmt := TImageFileFormat(ImageFileFormats[I]);
+      if Fmt.TestFormat(Handle) then
+      begin
+        Result := Fmt.Extensions[0];
+        Exit;
+      end;
+    end;
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+function DetermineStreamFormat(Stream: TStream): string;
+var
+  I: LongInt;
+  Fmt: TImageFileFormat;
+  Handle: TImagingHandle;
+begin
+  Assert(Stream <> nil);
+  Result := '';
+  SetStreamIO;
+  Handle := IO.Open(Pointer(Stream), omReadOnly);
+  try
+    for I := 0 to ImageFileFormats.Count - 1 do
+    begin
+      Fmt := TImageFileFormat(ImageFileFormats[I]);
+      if Fmt.TestFormat(Handle) then
+      begin
+        Result := Fmt.Extensions[0];
+        Exit;
+      end;
+    end;
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+function DetermineMemoryFormat(Data: Pointer; Size: LongInt): string;
+var
+  I: LongInt;
+  Fmt: TImageFileFormat;
+  Handle: TImagingHandle;
+  IORec: TMemoryIORec;
+begin
+  Assert((Data <> nil) and (Size > 0));
+  Result := '';
+  SetMemoryIO;
+  IORec.Data := Data;
+  IORec.Position := 0;
+  IORec.Size := Size;
+  Handle := IO.Open(@IORec, omReadOnly);
+  try
+    for I := 0 to ImageFileFormats.Count - 1 do
+    begin
+      Fmt := TImageFileFormat(ImageFileFormats[I]);
+      if Fmt.TestFormat(Handle) then
+      begin
+        Result := Fmt.Extensions[0];
+        Exit;
+      end;
+    end;
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+function IsFileFormatSupported(const FileName: string): Boolean;
+begin
+  Result := FindImageFileFormatByName(FileName) <> nil;
+end;
+
+function EnumFileFormats(var Index: LongInt; var Name, DefaultExt, Masks: string;
+  var CanSaveImages, IsMultiImageFormat: Boolean): Boolean;
+var
+  FileFmt: TImageFileFormat;
+begin
+  FileFmt := GetFileFormatAtIndex(Index);
+  Result := FileFmt <> nil;
+  if Result then
+  begin
+    Name := FileFmt.Name;
+    DefaultExt := FileFmt.Extensions[0];
+    Masks := FileFmt.Masks.DelimitedText;
+    CanSaveImages := FileFmt.CanSave;
+    IsMultiImageFormat := FileFmt.IsMultiImageFormat;
+    Inc(Index);
+  end
+  else
+  begin
+    Name := '';
+    DefaultExt := '';
+    Masks := '';
+    CanSaveImages := False;
+    IsMultiImageFormat := False;
+  end;
+end;
+
+{ Loading Functions }
+
+function LoadImageFromFile(const FileName: string; var Image: TImageData):
+  Boolean;
+var
+  Format: TImageFileFormat;
+  IArray: TDynImageDataArray;
+  I: LongInt;
+begin
+  Assert(FileName <> '');
+  Result := False;
+  Format := FindImageFileFormatByExt(DetermineFileFormat(FileName));
+  if Format <> nil then
+  begin
+    FreeImage(Image);
+    Result := Format.LoadFromFile(FileName, IArray, True);
+    if Result and (Length(IArray) > 0) then
+    begin
+      Image := IArray[0];
+      for I := 1 to Length(IArray) - 1 do
+        FreeImage(IArray[I]);
+    end
+    else
+      Result := False;
+  end;
+end;
+
+function LoadImageFromStream(Stream: TStream; var Image: TImageData): Boolean;
+var
+  Format: TImageFileFormat;
+  IArray: TDynImageDataArray;
+  I: LongInt;
+begin
+  Assert(Stream <> nil);
+  if Stream.Size - Stream.Position = 0 then
+    RaiseImaging(SErrorEmptyStream, []);
+  Result := False;
+  Format := FindImageFileFormatByExt(DetermineStreamFormat(Stream));
+  if Format <> nil then
+  begin
+    FreeImage(Image);
+    Result := Format.LoadFromStream(Stream, IArray, True);
+    if Result and (Length(IArray) > 0) then
+    begin
+      Image := IArray[0];
+      for I := 1 to Length(IArray) - 1 do
+        FreeImage(IArray[I]);
+    end
+    else
+      Result := False;
+  end;
+end;
+
+function LoadImageFromMemory(Data: Pointer; Size: LongInt; var Image: TImageData): Boolean;
+var
+  Format: TImageFileFormat;
+  IArray: TDynImageDataArray;
+  I: LongInt;
+begin
+  Assert((Data <> nil) and (Size > 0));
+  Result := False;
+  Format := FindImageFileFormatByExt(DetermineMemoryFormat(Data, Size));
+  if Format <> nil then
+  begin
+    FreeImage(Image);
+    Result := Format.LoadFromMemory(Data, Size, IArray, True);
+    if Result and (Length(IArray) > 0) then
+    begin
+      Image := IArray[0];
+      for I := 1 to Length(IArray) - 1 do
+        FreeImage(IArray[I]);
+    end
+    else
+      Result := False;
+  end;
+end;
+
+function LoadMultiImageFromFile(const FileName: string; var Images:
+  TDynImageDataArray): Boolean;
+var
+  Format: TImageFileFormat;
+begin
+  Assert(FileName <> '');
+  Result := False;
+  Format := FindImageFileFormatByExt(DetermineFileFormat(FileName));
+  if Format <> nil then
+  begin
+    FreeImagesInArray(Images);
+    Result := Format.LoadFromFile(FileName, Images);
+  end;
+end;
+
+function LoadMultiImageFromStream(Stream: TStream; var Images: TDynImageDataArray): Boolean;
+var
+  Format: TImageFileFormat;
+begin
+  Assert(Stream <> nil);
+  if Stream.Size - Stream.Position = 0 then
+    RaiseImaging(SErrorEmptyStream, []);
+  Result := False;
+  Format := FindImageFileFormatByExt(DetermineStreamFormat(Stream));
+  if Format <> nil then
+  begin
+    FreeImagesInArray(Images);
+    Result := Format.LoadFromStream(Stream, Images);
+  end;
+end;
+
+function LoadMultiImageFromMemory(Data: Pointer; Size: LongInt;
+  var Images: TDynImageDataArray): Boolean;
+var
+  Format: TImageFileFormat;
+begin
+  Assert((Data <> nil) and (Size > 0));
+  Result := False;
+  Format := FindImageFileFormatByExt(DetermineMemoryFormat(Data, Size));
+  if Format <> nil then
+  begin
+    FreeImagesInArray(Images);
+    Result := Format.LoadFromMemory(Data, Size, Images);
+  end;
+end;
+
+{ Saving Functions }
+
+function SaveImageToFile(const FileName: string; const Image: TImageData): Boolean;
+var
+  Format: TImageFileFormat;
+  IArray: TDynImageDataArray;
+begin
+  Assert(FileName <> '');
+  Result := False;
+  Format := FindImageFileFormatByName(FileName);
+  if Format <> nil then
+  begin
+    SetLength(IArray, 1);
+    IArray[0] := Image;
+    Result := Format.SaveToFile(FileName, IArray, True);
+  end;
+end;
+
+function SaveImageToStream(const Ext: string; Stream: TStream;
+  const Image: TImageData): Boolean;
+var
+  Format: TImageFileFormat;
+  IArray: TDynImageDataArray;
+begin
+  Assert((Ext <> '') and (Stream <> nil));
+  Result := False;
+  Format := FindImageFileFormatByExt(Ext);
+  if Format <> nil then
+  begin
+    SetLength(IArray, 1);
+    IArray[0] := Image;
+    Result := Format.SaveToStream(Stream, IArray, True);
+  end;
+end;
+
+function SaveImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt;
+  const Image: TImageData): Boolean;
+var
+  Format: TImageFileFormat;
+  IArray: TDynImageDataArray;
+begin
+  Assert((Ext <> '') and (Data <> nil) and (Size > 0));
+  Result := False;
+  Format := FindImageFileFormatByExt(Ext);
+  if Format <> nil then
+  begin
+    SetLength(IArray, 1);
+    IArray[0] := Image;
+    Result := Format.SaveToMemory(Data, Size, IArray, True);
+  end;
+end;
+
+function SaveMultiImageToFile(const FileName: string;
+  const Images: TDynImageDataArray): Boolean;
+var
+  Format: TImageFileFormat;
+begin
+  Assert(FileName <> '');
+  Result := False;
+  Format := FindImageFileFormatByName(FileName);
+  if Format <> nil then
+    Result := Format.SaveToFile(FileName, Images);
+end;
+
+function SaveMultiImageToStream(const Ext: string; Stream: TStream;
+  const Images: TDynImageDataArray): Boolean;
+var
+  Format: TImageFileFormat;
+begin
+  Assert((Ext <> '') and (Stream <> nil));
+  Result := False;
+  Format := FindImageFileFormatByExt(Ext);
+  if Format <> nil then
+    Result := Format.SaveToStream(Stream, Images);
+end;
+
+function SaveMultiImageToMemory(const Ext: string; Data: Pointer;
+  var Size: LongInt; const Images: TDynImageDataArray): Boolean;
+var
+  Format: TImageFileFormat;
+begin
+  Assert((Ext <> '') and (Data <> nil) and (Size > 0));
+  Result := False;
+  Format := FindImageFileFormatByExt(Ext);
+  if Format <> nil then
+    Result := Format.SaveToMemory(Data, Size, Images);
+end;
+
+{ Manipulation Functions }
+
+function CloneImage(const Image: TImageData; var Clone: TImageData): Boolean;
+var
+  Info: PImageFormatInfo;
+begin
+  Result := False;
+  if TestImage(Image) then
+  try
+    if TestImage(Clone) and (Image.Bits <> Clone.Bits) then
+      FreeImage(Clone)
+    else
+      InitImage(Clone);
+
+    Info := ImageFormatInfos[Image.Format];
+    Clone.Width := Image.Width;
+    Clone.Height := Image.Height;
+    Clone.Format := Image.Format;
+    Clone.Size := Image.Size;
+
+    if Info.PaletteEntries > 0 then
+    begin
+      GetMem(Clone.Palette, Info.PaletteEntries * SizeOf(TColor32Rec));
+      Move(Image.Palette^, Clone.Palette^, Info.PaletteEntries *
+        SizeOf(TColor32Rec));
+    end;
+
+    GetMem(Clone.Bits, Clone.Size);
+    Move(Image.Bits^, Clone.Bits^, Clone.Size);
+    Result := True;
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorCloneImage, [ImageToStr(Image)]);
+  end;
+end;
+
+function ConvertImage(var Image: TImageData; DestFormat: TImageFormat): Boolean;
+var
+  NewData: Pointer;
+  NewPal: PPalette32;
+  NewSize, NumPixels: LongInt;
+  SrcInfo, DstInfo: PImageFormatInfo;
+begin
+  Assert(IsImageFormatValid(DestFormat));
+  Result := False;
+  if TestImage(Image) then
+  with Image do
+  try
+    // If default format is set we use DefaultImageFormat
+    if DestFormat = ifDefault then
+      DestFormat := DefaultImageFormat;
+    SrcInfo := ImageFormatInfos[Format];
+    DstInfo := ImageFormatInfos[DestFormat];
+    if SrcInfo = DstInfo then
+    begin
+      // There is nothing to convert - src is alredy in dest format
+      Result := True;
+      Exit;
+    end;
+    // Exit Src or Dest format is invalid
+    if (SrcInfo = nil) or (DstInfo = nil) then Exit;
+    // If dest format is just src with swapped channels we call
+    // SwapChannels instead
+    if (SrcInfo.RBSwapFormat = DestFormat) and
+      (DstInfo.RBSwapFormat = SrcInfo.Format) then
+    begin
+      Result := SwapChannels(Image, ChannelRed, ChannelBlue);
+      Image.Format := SrcInfo.RBSwapFormat;
+      Exit;
+    end;
+
+    if (not SrcInfo.IsSpecial) and (not DstInfo.IsSpecial) then
+    begin
+      NumPixels := Width * Height;
+      NewSize := NumPixels * DstInfo.BytesPerPixel;
+      GetMem(NewData, NewSize);
+      FillChar(NewData^, NewSize, 0);
+      GetMem(NewPal, DstInfo.PaletteEntries * SizeOf(TColor32Rec));
+      FillChar(NewPal^, DstInfo.PaletteEntries * SizeOf(TColor32Rec), 0);
+
+      if SrcInfo.IsIndexed then
+      begin
+        // Source: indexed format
+        if DstInfo.IsIndexed then
+          IndexToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette, NewPal)
+        else if DstInfo.HasGrayChannel then
+          IndexToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette)
+        else if DstInfo.IsFloatingPoint then
+          IndexToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette)
+        else
+          IndexToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette);
+      end
+      else if SrcInfo.HasGrayChannel then
+      begin
+        // Source: grayscale format
+        if DstInfo.IsIndexed then
+          GrayToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal)
+        else if DstInfo.HasGrayChannel then
+          GrayToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo)
+        else if DstInfo.IsFloatingPoint then
+          GrayToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo)
+        else
+          GrayToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo);
+      end
+      else if SrcInfo.IsFloatingPoint then
+      begin
+        // Source: floating point format
+        if DstInfo.IsIndexed then
+          FloatToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal)
+        else if DstInfo.HasGrayChannel then
+          FloatToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo)
+        else if DstInfo.IsFloatingPoint then
+          FloatToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo)
+        else
+          FloatToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo);
+      end
+      else
+      begin
+        // Source: standard multi channel image
+        if DstInfo.IsIndexed then
+          ChannelToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal)
+        else if DstInfo.HasGrayChannel then
+          ChannelToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo)
+        else if DstInfo.IsFloatingPoint then
+          ChannelToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo)
+        else
+          ChannelToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo);
+      end;
+
+      FreeMemNil(Bits);
+      FreeMemNil(Palette);
+      Format := DestFormat;
+      Bits := NewData;
+      Size := NewSize;
+      Palette := NewPal;
+    end
+    else
+      ConvertSpecial(Image, SrcInfo, DstInfo);
+
+    Assert(SrcInfo.Format <> Image.Format);
+
+    Result := True;
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorConvertImage, [GetFormatName(DestFormat), ImageToStr(Image)]);
+  end;
+end;
+
+function FlipImage(var Image: TImageData): Boolean;
+var
+  P1, P2, Buff: Pointer;
+  WidthBytes, I: LongInt;
+  OldFmt: TImageFormat;
+begin
+  Result := False;
+  OldFmt := Image.Format;
+  if TestImage(Image) then
+  with Image do
+  try
+    if ImageFormatInfos[OldFmt].IsSpecial then
+      ConvertImage(Image, ifDefault);
+
+    WidthBytes := Width * ImageFormatInfos[Format].BytesPerPixel;
+    GetMem(Buff, WidthBytes);
+    try
+      // Swap all scanlines of image
+      for I := 0 to Height div 2 - 1 do
+      begin
+        P1 := @PByteArray(Bits)[I * WidthBytes];
+        P2 := @PByteArray(Bits)[(Height - I - 1) * WidthBytes];
+        Move(P1^, Buff^, WidthBytes);
+        Move(P2^, P1^, WidthBytes);
+        Move(Buff^, P2^, WidthBytes);
+      end;
+    finally
+      FreeMemNil(Buff);
+    end;
+
+    if OldFmt <> Format then
+      ConvertImage(Image, OldFmt);
+
+    Result := True;
+  except
+    RaiseImaging(SErrorFlipImage, [ImageToStr(Image)]);
+  end;
+end;
+
+function MirrorImage(var Image: TImageData): Boolean;
+var
+  Scanline: PByte;
+  Buff: TColorFPRec;
+  Bpp, Y, X, WidthDiv2, WidthBytes, XLeft, XRight: LongInt;
+  OldFmt: TImageFormat;
+begin
+  Result := False;
+  OldFmt := Image.Format;
+  if TestImage(Image) then
+  with Image do
+  try
+    if ImageFormatInfos[OldFmt].IsSpecial then
+      ConvertImage(Image, ifDefault);
+
+    Bpp := ImageFormatInfos[Format].BytesPerPixel;
+    WidthDiv2 := Width div 2;
+    WidthBytes := Width * Bpp;
+    // Mirror all pixels on each scanline of image
+    for Y := 0 to Height - 1 do
+    begin
+      Scanline := @PByteArray(Bits)[Y * WidthBytes];
+      XLeft := 0;
+      XRight := (Width - 1) * Bpp;
+      for X := 0 to WidthDiv2 - 1 do
+      begin
+        CopyPixel(@PByteArray(Scanline)[XLeft], @Buff, Bpp);
+        CopyPixel(@PByteArray(Scanline)[XRight],
+          @PByteArray(Scanline)[XLeft], Bpp);
+        CopyPixel(@Buff, @PByteArray(Scanline)[XRight], Bpp);
+        Inc(XLeft, Bpp);
+        Dec(XRight, Bpp);
+      end;
+    end;
+
+    if OldFmt <> Format then
+      ConvertImage(Image, OldFmt);
+
+    Result := True;
+  except
+    RaiseImaging(SErrorMirrorImage, [ImageToStr(Image)]);
+  end;
+end;
+
+function ResizeImage(var Image: TImageData; NewWidth, NewHeight: LongInt;
+  Filter: TResizeFilter): Boolean;
+var
+  WorkImage: TImageData;
+begin
+  Assert((NewWidth > 0) and (NewHeight > 0), 'New width or height is zero.');
+  Result := False;
+  if TestImage(Image) and ((Image.Width <> NewWidth) or (Image.Height <> NewHeight)) then
+  try
+    InitImage(WorkImage);
+    // Create new image with desired dimensions
+    NewImage(NewWidth, NewHeight, Image.Format, WorkImage);
+    // Stretch pixels from old image to new one
+    StretchRect(Image, 0, 0, Image.Width, Image.Height,
+      WorkImage, 0, 0, WorkImage.Width, WorkImage.Height, Filter);
+    // Free old image and assign new image to it
+    FreeMemNil(Image.Bits);
+    if Image.Palette <> nil then
+    begin
+      FreeMem(WorkImage.Palette);
+      WorkImage.Palette := Image.Palette;
+    end;
+    Image := WorkImage;
+    Result := True;
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorResizeImage, [ImageToStr(Image)]);
+  end;
+end;
+
+function SwapChannels(var Image: TImageData; SrcChannel, DstChannel: LongInt): Boolean;
+var
+  I, NumPixels: LongInt;
+  Info: PImageFormatInfo;
+  Swap, Alpha: Word;
+  Data: PByte;
+  Pix64: TColor64Rec;
+  PixF: TColorFPRec;
+  SwapF: Single;
+begin
+  Assert((SrcChannel in [0..3]) and (DstChannel in [0..3]));
+  Result := False;
+  if TestImage(Image) and (SrcChannel <> DstChannel) then
+  with Image do
+  try
+    NumPixels := Width * Height;
+    Info := ImageFormatInfos[Format];
+    Data := Bits;
+
+    if (Info.Format = ifR8G8B8) or ((Info.Format = ifA8R8G8B8) and
+       (SrcChannel <> ChannelAlpha) and (DstChannel <> ChannelAlpha)) then
+    begin
+      // Swap channels of most common formats R8G8B8 and A8R8G8B8 (no alpha)
+      for I := 0 to NumPixels - 1 do
+      with PColor24Rec(Data)^ do
+      begin
+        Swap := Channels[SrcChannel];
+        Channels[SrcChannel] := Channels[DstChannel];
+        Channels[DstChannel] := Swap;
+        Inc(Data, Info.BytesPerPixel);
+      end;
+    end
+    else if Info.IsIndexed then
+    begin
+      // Swap palette channels of indexed images
+      SwapChannelsOfPalette(Palette, Info.PaletteEntries, SrcChannel, DstChannel)
+    end
+    else if Info.IsFloatingPoint then
+    begin
+      // Swap channels of floating point images
+      for I := 0 to NumPixels - 1 do
+      begin
+        FloatGetSrcPixel(Data, Info, PixF);
+        with PixF do
+        begin
+          SwapF := Channels[SrcChannel];
+          Channels[SrcChannel] := Channels[DstChannel];
+          Channels[DstChannel] := SwapF;
+        end;
+        FloatSetDstPixel(Data, Info, PixF);
+        Inc(Data, Info.BytesPerPixel);
+      end;
+    end
+    else if Info.IsSpecial then
+    begin
+      // Swap channels of special format images
+      ConvertImage(Image, ifDefault);
+      SwapChannels(Image, SrcChannel, DstChannel);
+      ConvertImage(Image, Info.Format);
+    end
+    else if Info.HasGrayChannel and Info.HasAlphaChannel and
+      ((SrcChannel = ChannelAlpha) or (DstChannel = ChannelAlpha)) then
+    begin
+      for I := 0 to NumPixels - 1 do
+      begin
+        // If we have grayscale image with alpha and alpha is channel
+        // to be swapped, we swap it. No other alternative for gray images,
+        // just alpha and something
+        GrayGetSrcPixel(Data, Info, Pix64, Alpha);
+        Swap := Alpha;
+        Alpha := Pix64.A;
+        Pix64.A := Swap;
+        GraySetDstPixel(Data, Info, Pix64, Alpha);
+        Inc(Data, Info.BytesPerPixel);
+      end;
+    end
+    else
+    begin
+      // Then do general swap on other channel image formats
+      for I := 0 to NumPixels - 1 do
+      begin
+        ChannelGetSrcPixel(Data, Info, Pix64);
+        with Pix64 do
+        begin
+          Swap := Channels[SrcChannel];
+          Channels[SrcChannel] := Channels[DstChannel];
+          Channels[DstChannel] := Swap;
+        end;
+        ChannelSetDstPixel(Data, Info, Pix64);
+        Inc(Data, Info.BytesPerPixel);
+      end;
+    end;
+
+    Result := True;
+  except
+    RaiseImaging(SErrorSwapImage, [ImageToStr(Image)]);
+  end;
+end;
+
+function ReduceColors(var Image: TImageData; MaxColors: LongInt): Boolean;
+var
+  TmpInfo: TImageFormatInfo;
+  Data, Index: PWord;
+  I, NumPixels: LongInt;
+  Pal: PPalette32;
+  Col:PColor32Rec;
+  OldFmt: TImageFormat;
+begin
+  Result := False;
+  if TestImage(Image) then
+  with Image do
+  try
+    // First create temp image info and allocate output bits and palette
+    MaxColors := ClampInt(MaxColors, 2, High(Word));
+    OldFmt := Format;
+    FillChar(TmpInfo, SizeOf(TmpInfo), 0);
+    TmpInfo.PaletteEntries := MaxColors;
+    TmpInfo.BytesPerPixel := 2;
+    NumPixels := Width * Height;
+    GetMem(Data, NumPixels * TmpInfo.BytesPerPixel);
+    GetMem(Pal, MaxColors * SizeOf(TColor32Rec));
+    ConvertImage(Image, ifA8R8G8B8);
+    // We use median cut algorithm to create reduced palette and to
+    // fill Data with indices to this palette
+    ReduceColorsMedianCut(NumPixels, Bits, PByte(Data),
+      ImageFormatInfos[Format], @TmpInfo, MaxColors, ColorReductionMask, Pal);
+    Col := Bits;
+    Index := Data;
+    // Then we write reduced colors to the input image
+    for I := 0 to NumPixels - 1 do
+    begin
+      Col.Color := Pal[Index^].Color;
+      Inc(Col);
+      Inc(Index);
+    end;
+    FreeMemNil(Data);
+    FreeMemNil(Pal);
+    // And convert it to its original format
+    ConvertImage(Image, OldFmt);
+    Result := True;
+  except
+    RaiseImaging(SErrorReduceColors, [MaxColors, ImageToStr(Image)]);
+  end;
+end;
+
+function GenerateMipMaps(const Image: TImageData; Levels: LongInt;
+  var MipMaps: TDynImageDataArray): Boolean;
+var
+  Width, Height, I, Count: LongInt;
+  Info: TImageFormatInfo;
+  CompatibleCopy: TImageData;
+begin
+  Result := False;
+  if TestImage(Image) then
+  try
+    Width := Image.Width;
+    Height := Image.Height;
+    // We compute number of possible mipmap levels and if
+    // the given levels are invalid or zero we use this value
+    Count := GetNumMipMapLevels(Width, Height);
+    if (Levels <= 0) or (Levels > Count) then
+      Levels := Count;
+
+    // If we have special format image we create copy to allow pixel access.
+    // This is also done in FillMipMapLevel which is called for each level
+    // but then the main big image would be converted to compatible
+    // for every level.
+    GetImageFormatInfo(Image.Format, Info);
+    if Info.IsSpecial then
+    begin
+      InitImage(CompatibleCopy);
+      CloneImage(Image, CompatibleCopy);
+      ConvertImage(CompatibleCopy, ifDefault);
+    end
+    else
+      CompatibleCopy := Image;
+
+    FreeImagesInArray(MipMaps);
+    SetLength(MipMaps, Levels);
+    CloneImage(Image, MipMaps[0]);
+
+    for I := 1 to Levels - 1 do
+    begin
+      Width := Width shr 1;
+      Height := Height shr 1;
+      if Width < 1 then Width := 1;
+      if Height < 1 then Height := 1;
+      FillMipMapLevel(CompatibleCopy, Width, Height, MipMaps[I]);
+    end;
+
+    if CompatibleCopy.Format <> MipMaps[0].Format then
+    begin
+      // Must convert smaller levels to proper format
+      for I := 1 to High(MipMaps) do
+        ConvertImage(MipMaps[I], MipMaps[0].Format);
+      FreeImage(CompatibleCopy);
+    end;
+
+    Result := True;
+  except
+    RaiseImaging(SErrorGenerateMipMaps, [Levels, ImageToStr(Image)]);
+  end;
+end;
+
+function MapImageToPalette(var Image: TImageData; Pal: PPalette32;
+  Entries: LongInt): Boolean;
+
+  function FindNearestColor(Pal: PPalette32; Entries: LongInt; Col: TColor32Rec): LongInt;
+  var
+    I, MinDif, Dif: LongInt;
+  begin
+    Result := 0;
+    MinDif := 1020;
+    for I := 0 to Entries - 1 do
+    with Pal[I] do
+    begin
+      Dif := Abs(R - Col.R);
+      if Dif > MinDif then Continue;
+      Dif := Dif + Abs(G - Col.G);
+      if Dif > MinDif then Continue;
+      Dif := Dif + Abs(B - Col.B);
+      if Dif > MinDif then Continue;
+      Dif := Dif + Abs(A - Col.A);
+      if Dif < MinDif then
+      begin
+        MinDif := Dif;
+        Result := I;
+      end;
+    end;
+  end;
+
+var
+  I, MaxEntries: LongInt;
+  PIndex: PByte;
+  PColor: PColor32Rec;
+  CloneARGB: TImageData;
+  Info: PImageFormatInfo;
+begin
+  Assert((Entries >= 2) and (Entries <= 256));
+  Result := False;
+
+  if TestImage(Image) then
+  try
+    // We create clone of source image in A8R8G8B8 and
+    // then recreate source image in ifIndex8 format
+    // with palette taken from Pal parameter
+    InitImage(CloneARGB);
+    CloneImage(Image, CloneARGB);
+    ConvertImage(CloneARGB, ifA8R8G8B8);
+    FreeImage(Image);
+    NewImage(CloneARGB.Width, CloneARGB.Height, ifIndex8, Image);
+
+    Info := ImageFormatInfos[Image.Format];
+    MaxEntries := Min(Info.PaletteEntries, Entries);
+    Move(Pal^, Image.Palette^, MaxEntries * SizeOf(TColor32Rec));
+    PIndex := Image.Bits;
+    PColor := CloneARGB.Bits;
+
+    // For every pixel of ARGB clone we find closest color in
+    // given palette and assign its index to resulting image's pixel
+    // procedure used here is very slow but simple and memory usage friendly
+    // (contrary to other methods)
+    for I := 0 to Image.Width * Image.Height - 1 do
+    begin
+      PIndex^ := Byte(FindNearestColor(Image.Palette, MaxEntries, PColor^));
+      Inc(PIndex);
+      Inc(PColor);
+    end;
+
+    FreeImage(CloneARGB);
+    Result := True;
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorMapImage, [ImageToStr(Image)]);
+  end;
+end;
+
+function SplitImage(var Image: TImageData; var Chunks: TDynImageDataArray;
+  ChunkWidth, ChunkHeight: LongInt; var XChunks, YChunks: LongInt;
+  PreserveSize: Boolean; Fill: Pointer): Boolean;
+var
+  X, Y, XTrunc, YTrunc: LongInt;
+  NotOnEdge: Boolean;
+  Info: PImageFormatInfo;
+  OldFmt: TImageFormat;
+begin
+  Assert((ChunkWidth > 0) and (ChunkHeight > 0));
+  Result := False;
+  OldFmt := Image.Format;
+  FreeImagesInArray(Chunks);
+
+  if TestImage(Image) then
+  try
+    Info := ImageFormatInfos[Image.Format];
+    if Info.IsSpecial then
+      ConvertImage(Image, ifDefault);
+
+    // We compute make sure that chunks are not larger than source image or negative
+    ChunkWidth := ClampInt(ChunkWidth, 0, Image.Width);
+    ChunkHeight := ClampInt(ChunkHeight, 0, Image.Height);
+    // Number of chunks along X and Y axes is computed
+    XChunks := Trunc(Ceil(Image.Width / ChunkWidth));
+    YChunks := Trunc(Ceil(Image.Height / ChunkHeight));
+    SetLength(Chunks, XChunks * YChunks);
+
+    // For every chunk we create new image and copy a portion of
+    // the source image to it. If chunk is on the edge of the source image
+    // we fill enpty space with Fill pixel data if PreserveSize is set or
+    // make the chunk smaller if it is not set
+    for Y := 0 to YChunks - 1 do
+      for X := 0 to XChunks - 1 do
+      begin
+        // Determine if current chunk is on the edge of original image
+        NotOnEdge := ((X < XChunks - 1) and (Y < YChunks - 1)) or
+          ((Image.Width mod ChunkWidth = 0) and (Image.Height mod ChunkHeight = 0));
+
+        if PreserveSize or NotOnEdge then
+        begin
+          // We should preserve chunk sizes or we are somewhere inside original image
+          NewImage(ChunkWidth, ChunkHeight, Image.Format, Chunks[Y * XChunks + X]);
+          if (not NotOnEdge) and (Fill <> nil) then
+            FillRect(Chunks[Y * XChunks + X], 0, 0, ChunkWidth, ChunkHeight, Fill);
+          CopyRect(Image, X * ChunkWidth, Y * ChunkHeight, ChunkWidth, ChunkHeight,
+            Chunks[Y * XChunks + X], 0, 0);
+        end
+        else
+        begin
+          // Create smaller edge chunk
+          XTrunc := Image.Width - X * ChunkWidth;
+          YTrunc := Image.Height - Y * ChunkHeight;
+          NewImage(XTrunc, YTrunc, Image.Format, Chunks[Y * XChunks + X]);
+          CopyRect(Image, X * ChunkWidth, Y * ChunkHeight, XTrunc, YTrunc,
+            Chunks[Y * XChunks + X], 0, 0);
+        end;
+
+        // If source image is in indexed format we copy its palette to chunk
+        if Info.IsIndexed then
+        begin
+          Move(Image.Palette^, Chunks[Y * XChunks + X].Palette^,
+            Info.PaletteEntries * SizeOf(TColor32Rec));
+        end;
+      end;
+
+    if OldFmt <> Image.Format then
+    begin
+      ConvertImage(Image, OldFmt);
+      for X := 0 to Length(Chunks) - 1 do
+        ConvertImage(Chunks[X], OldFmt);
+    end;
+
+    Result := True;
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorSplitImage,
+      [ImageToStr(Image), ChunkWidth, ChunkHeight]);
+  end;
+end;
+
+function MakePaletteForImages(var Images: TDynImageDataArray; Pal: PPalette32;
+  MaxColors: LongInt; ConvertImages: Boolean): Boolean;
+var
+  I: Integer;
+  SrcInfo, DstInfo: PImageFormatInfo;
+  Target, TempImage: TImageData;
+  DstFormat: TImageFormat;
+begin
+  Assert((Pal <> nil) and (MaxColors > 0));
+  Result := False;
+  InitImage(TempImage);
+
+  if TestImagesInArray(Images) then
+  try
+    // Null the color histogram
+    ReduceColorsMedianCut(0, nil, nil, nil, nil, 0, 0, nil, [raCreateHistogram]);
+    for I := 0 to Length(Images) - 1 do
+    begin
+      SrcInfo := ImageFormatInfos[Images[I].Format];
+      if SrcInfo.IsIndexed or SrcInfo.IsSpecial then
+      begin
+        // create temp image in supported format for updating histogram
+        CloneImage(Images[I], TempImage);
+        ConvertImage(TempImage, ifA8R8G8B8);
+        SrcInfo := ImageFormatInfos[TempImage.Format];
+      end
+      else
+        TempImage := Images[I];
+
+      // Update histogram with colors of each input image
+      ReduceColorsMedianCut(TempImage.Width * TempImage.Height, TempImage.Bits,
+        nil, SrcInfo, nil, MaxColors, ColorReductionMask, nil, [raUpdateHistogram]);
+
+      if Images[I].Bits <> TempImage.Bits then
+        FreeImage(TempImage);
+    end;
+    // Construct reduced color map from the histogram
+    ReduceColorsMedianCut(0, nil, nil, nil, nil, MaxColors, ColorReductionMask,
+      Pal, [raMakeColorMap]);
+
+    if ConvertImages then
+    begin
+      DstFormat := ifIndex8;
+      DstInfo := ImageFormatInfos[DstFormat];
+      MaxColors := Min(DstInfo.PaletteEntries, MaxColors);
+
+      for I := 0 to Length(Images) - 1 do
+      begin
+        SrcInfo := ImageFormatInfos[Images[I].Format];
+        if SrcInfo.IsIndexed or SrcInfo.IsSpecial then
+        begin
+          // If source image is in format not supported by ReduceColorsMedianCut
+          // we convert it
+          ConvertImage(Images[I], ifA8R8G8B8);
+          SrcInfo := ImageFormatInfos[Images[I].Format];
+        end;
+
+        InitImage(Target);
+        NewImage(Images[I].Width, Images[I].Height, DstFormat, Target);
+        // We map each input image to reduced palette and replace
+        // image in array with mapped image
+        ReduceColorsMedianCut(Images[I].Width * Images[I].Height, Images[I].Bits,
+          Target.Bits, SrcInfo, DstInfo, MaxColors, 0, nil, [raMapImage]);
+        Move(Pal^, Target.Palette^, MaxColors * SizeOf(TColor32Rec));
+
+        FreeImage(Images[I]);
+        Images[I] := Target;
+      end;
+    end;
+    Result := True;
+  except
+    RaiseImaging(SErrorMakePaletteForImages, [MaxColors, Length(Images)]);
+  end;
+end;
+
+procedure RotateImage(var Image: TImageData; Angle: Single);
+var
+  OldFmt: TImageFormat;
+
+  procedure XShear(var Src, Dst: TImageData; Row, Offset, Weight, Bpp: Integer);
+  var
+    I, J, XPos: Integer;
+    PixSrc, PixLeft, PixOldLeft: TColor32Rec;
+    LineDst: PByteArray;
+    SrcPtr: PColor32;
+  begin
+    SrcPtr := @PByteArray(Src.Bits)[Row * Src.Width * Bpp];
+    LineDst := @PByteArray(Dst.Bits)[Row * Dst.Width * Bpp];
+    PixOldLeft.Color := 0;
+
+    for I := 0 to Src.Width - 1 do
+    begin
+      CopyPixel(SrcPtr, @PixSrc, Bpp);
+      for J := 0 to Bpp - 1 do
+        PixLeft.Channels[J] := MulDiv(PixSrc.Channels[J], Weight, 256);
+
+      XPos := I + Offset;
+      if (XPos >= 0) and (XPos < Dst.Width) then
+      begin
+        for J := 0 to Bpp - 1 do
+          PixSrc.Channels[J] := ClampToByte(PixSrc.Channels[J] - (PixLeft.Channels[J] - PixOldLeft.Channels[J]));
+        CopyPixel(@PixSrc, @LineDst[XPos * Bpp], Bpp);
+      end;
+      PixOldLeft := PixLeft;
+      Inc(PByte(SrcPtr), Bpp);
+    end;
+
+    XPos := Src.Width + Offset;
+    if XPos < Dst.Width then
+      CopyPixel(@PixOldLeft, @LineDst[XPos * Bpp], Bpp);
+  end;
+
+  procedure YShear(var Src, Dst: TImageData; Col, Offset, Weight, Bpp: Integer);
+  var
+    I, J, YPos: Integer;
+    PixSrc, PixLeft, PixOldLeft: TColor32Rec;
+    SrcPtr: PByte;
+  begin
+    SrcPtr := @PByteArray(Src.Bits)[Col * Bpp];
+    PixOldLeft.Color := 0;
+
+    for I := 0 to Src.Height - 1 do
+    begin
+      CopyPixel(SrcPtr, @PixSrc, Bpp);
+      for J := 0 to Bpp - 1 do
+        PixLeft.Channels[J] := MulDiv(PixSrc.Channels[J], Weight, 256);
+
+      YPos := I + Offset;
+      if (YPos >= 0) and (YPos < Dst.Height) then
+      begin
+        for J := 0 to Bpp - 1 do
+          PixSrc.Channels[J] := ClampToByte(PixSrc.Channels[J] - (PixLeft.Channels[J] - PixOldLeft.Channels[J]));
+        CopyPixel(@PixSrc, @PByteArray(Dst.Bits)[(YPos * Dst.Width + Col) * Bpp], Bpp);
+      end;
+      PixOldLeft := PixLeft;
+      Inc(SrcPtr, Src.Width * Bpp);
+    end;
+
+    YPos := Src.Height + Offset;
+    if YPos < Dst.Height then
+      CopyPixel(@PixOldLeft, @PByteArray(Dst.Bits)[(YPos * Dst.Width + Col) * Bpp], Bpp);
+  end;
+
+  procedure Rotate45(var Image: TImageData; Angle: Single);
+  var
+    TempImage1, TempImage2: TImageData;
+    AngleRad, AngleTan, AngleSin, AngleCos, Shear: Single;
+    I, DstWidth, DstHeight, SrcWidth, SrcHeight, Bpp: Integer;
+    SrcFmt, TempFormat: TImageFormat;
+    Info: TImageFormatInfo;
+  begin
+    AngleRad := Angle * Pi / 180;
+    AngleSin := Sin(AngleRad);
+    AngleCos := Cos(AngleRad);
+    AngleTan := Sin(AngleRad / 2) / Cos(AngleRad / 2);
+    SrcWidth := Image.Width;
+    SrcHeight := Image.Height;
+    SrcFmt := Image.Format;
+
+    if not (SrcFmt in [ifR8G8B8..ifX8R8G8B8, ifGray8..ifGray32, ifA16Gray16]) then
+      ConvertImage(Image, ifA8R8G8B8);
+
+    TempFormat := Image.Format;
+    GetImageFormatInfo(TempFormat, Info);
+    Bpp := Info.BytesPerPixel;
+
+    // 1st shear (horizontal)
+    DstWidth := Trunc(SrcWidth + SrcHeight * Abs(AngleTan) + 0.5);
+    DstHeight := SrcHeight;
+    InitImage(TempImage1);
+    NewImage(DstWidth, DstHeight, TempFormat, TempImage1);
+
+    for I := 0 to DstHeight - 1 do
+    begin
+      if AngleTan >= 0 then
+        Shear := (I + 0.5) * AngleTan
+      else
+        Shear := (I - DstHeight + 0.5) * AngleTan;
+      XShear(Image, TempImage1, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp);
+    end;
+
+    // 2nd shear (vertical)
+    FreeImage(Image);
+    DstHeight := Trunc(SrcWidth * Abs(AngleSin) + SrcHeight * AngleCos + 0.5) + 1;
+    InitImage(TempImage2);
+    NewImage(DstWidth, DstHeight, TempFormat, TempImage2);
+
+    if AngleSin >= 0 then
+      Shear := (SrcWidth - 1) * AngleSin
+    else
+      Shear := (SrcWidth - DstWidth) * -AngleSin;
+
+    for I := 0 to DstWidth - 1 do
+    begin
+      YShear(TempImage1, TempImage2, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp);
+      Shear := Shear - AngleSin;
+    end;
+
+    // 3rd shear (horizontal)
+    FreeImage(TempImage1);
+    DstWidth := Trunc(SrcHeight * Abs(AngleSin) + SrcWidth * AngleCos + 0.5) + 1;
+    NewImage(DstWidth, DstHeight, TempFormat, Image);
+
+    if AngleSin >= 0 then
+      Shear := (SrcWidth - 1) * AngleSin * -AngleTan
+    else
+      Shear := ((SrcWidth - 1) * -AngleSin + (1 - DstHeight)) * AngleTan;
+
+    for I := 0 to DstHeight - 1 do
+    begin
+      XShear(TempImage2, Image, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp);
+      Shear := Shear + AngleTan;
+    end;
+
+    FreeImage(TempImage2);
+    if Image.Format <> SrcFmt then
+      ConvertImage(Image, SrcFmt);
+  end;
+
+  procedure RotateMul90(var Image: TImageData; Angle: Integer);
+  var
+    RotImage: TImageData;
+    X, Y, BytesPerPixel: Integer;
+    RotPix, Pix: PByte;
+  begin
+    InitImage(RotImage);
+    BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel;
+
+    if ((Angle = 90) or (Angle = 270)) and (Image.Width <> Image.Height) then
+      NewImage(Image.Height, Image.Width, Image.Format, RotImage)
+    else
+      NewImage(Image.Width, Image.Height, Image.Format, RotImage);
+
+    RotPix := RotImage.Bits;
+    case Angle of
+      90:
+        begin
+          for Y := 0 to RotImage.Height - 1 do
+          begin
+            Pix := @PByteArray(Image.Bits)[(Image.Width - Y - 1) * BytesPerPixel];
+            for X := 0 to RotImage.Width - 1 do
+            begin
+              CopyPixel(Pix, RotPix, BytesPerPixel);
+              Inc(RotPix, BytesPerPixel);
+              Inc(Pix, Image.Width * BytesPerPixel);
+            end;
+          end;
+        end;
+      180:
+        begin
+          Pix := @PByteArray(Image.Bits)[((Image.Height - 1) * Image.Width +
+            (Image.Width - 1)) * BytesPerPixel];
+          for Y := 0 to RotImage.Height - 1 do
+            for X := 0 to RotImage.Width - 1 do
+            begin
+              CopyPixel(Pix, RotPix, BytesPerPixel);
+              Inc(RotPix, BytesPerPixel);
+              Dec(Pix, BytesPerPixel);
+            end;
+        end;
+      270:
+        begin
+          for Y := 0 to RotImage.Height - 1 do
+          begin
+            Pix := @PByteArray(Image.Bits)[((Image.Height - 1) * Image.Width + Y) * BytesPerPixel];
+            for X := 0 to RotImage.Width - 1 do
+            begin
+              CopyPixel(Pix, RotPix, BytesPerPixel);
+              Inc(RotPix, BytesPerPixel);
+              Dec(Pix, Image.Width * BytesPerPixel);
+            end;
+          end;
+        end;
+    end;
+
+    FreeMemNil(Image.Bits);
+    RotImage.Palette := Image.Palette;
+    Image := RotImage;
+  end;
+
+begin
+  if TestImage(Image) then
+  try
+    while Angle >= 360 do
+      Angle := Angle - 360;
+    while Angle < 0 do
+      Angle := Angle + 360;
+
+    if (Angle = 0) or (Abs(Angle) = 360) then
+      Exit;
+
+    OldFmt := Image.Format;
+    if ImageFormatInfos[Image.Format].IsSpecial then
+      ConvertImage(Image, ifDefault);
+
+    if (Angle > 45) and (Angle <= 135) then
+    begin
+      RotateMul90(Image, 90);
+      Angle := Angle - 90;
+    end
+    else if (Angle > 135) and (Angle <= 225) then
+    begin
+      RotateMul90(Image, 180);
+      Angle := Angle - 180;
+    end
+    else if (Angle > 225) and (Angle <= 315) then
+    begin
+      RotateMul90(Image, 270);
+      Angle := Angle - 270;
+    end;
+
+    if Angle <> 0 then
+      Rotate45(Image, Angle);
+
+    if OldFmt <> Image.Format then
+      ConvertImage(Image, OldFmt);
+
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorRotateImage, [ImageToStr(Image), Angle]);
+  end;
+end;
+
+{ Drawing/Pixel functions }
+
+function CopyRect(const SrcImage: TImageData; SrcX, SrcY, Width, Height: LongInt;
+  var DstImage: TImageData; DstX, DstY: LongInt): Boolean;
+var
+  Info: PImageFormatInfo;
+  I, SrcWidthBytes, DstWidthBytes, MoveBytes: LongInt;
+  SrcPointer, DstPointer: PByte;
+  WorkImage: TImageData;
+  OldFormat: TImageFormat;
+begin
+  Result := False;
+  OldFormat := ifUnknown;
+  if TestImage(SrcImage) and TestImage(DstImage) then
+  try
+    // Make sure we are still copying image to image, not invalid pointer to protected memory
+    ClipCopyBounds(SrcX, SrcY, Width, Height, DstX, DstY, SrcImage.Width, SrcImage.Height,
+      Rect(0, 0, DstImage.Width, DstImage.Height));
+
+    if (Width > 0) and (Height > 0) then
+    begin
+      Info := ImageFormatInfos[DstImage.Format];
+      if Info.IsSpecial then
+      begin
+        // If dest image is in special format we convert it to default
+        OldFormat := Info.Format;
+        ConvertImage(DstImage, ifDefault);
+        Info := ImageFormatInfos[DstImage.Format];
+      end;
+      if SrcImage.Format <> DstImage.Format then
+      begin
+        // If images are in different format source is converted to dest's format
+        InitImage(WorkImage);
+        CloneImage(SrcImage, WorkImage);
+        ConvertImage(WorkImage, DstImage.Format);
+      end
+      else
+        WorkImage := SrcImage;
+
+      MoveBytes := Width * Info.BytesPerPixel;
+      DstWidthBytes := DstImage.Width * Info.BytesPerPixel;
+      DstPointer := @PByteArray(DstImage.Bits)[DstY * DstWidthBytes +
+        DstX * Info.BytesPerPixel];
+      SrcWidthBytes := WorkImage.Width * Info.BytesPerPixel;
+      SrcPointer := @PByteArray(WorkImage.Bits)[SrcY * SrcWidthBytes +
+        SrcX * Info.BytesPerPixel];
+
+      for I := 0 to Height - 1 do
+      begin
+        Move(SrcPointer^, DstPointer^, MoveBytes);
+        Inc(SrcPointer, SrcWidthBytes);
+        Inc(DstPointer, DstWidthBytes);
+      end;
+      // If dest image was in special format we convert it back
+      if OldFormat <> ifUnknown then
+        ConvertImage(DstImage, OldFormat);
+      // Working image must be freed if it is not the same as source image
+      if WorkImage.Bits <> SrcImage.Bits then
+        FreeImage(WorkImage);
+
+      Result := True;
+    end;
+  except
+    RaiseImaging(SErrorCopyRect, [ImageToStr(SrcImage), ImageToStr(DstImage)]);
+  end;
+end;
+
+function FillRect(var Image: TImageData; X, Y, Width, Height: LongInt;
+  FillColor: Pointer): Boolean;
+var
+  Info: PImageFormatInfo;
+  I, J, ImageWidthBytes, RectWidthBytes, Bpp: Longint;
+  LinePointer, PixPointer: PByte;
+  OldFmt: TImageFormat;
+begin
+  Result := False;
+  if TestImage(Image) then
+  try
+    ClipRectBounds(X, Y, Width, Height, Rect(0, 0, Image.Width, Image.Height));
+
+    if (Width > 0) and (Height > 0) then
+    begin
+      OldFmt := Image.Format;
+      if ImageFormatInfos[OldFmt].IsSpecial then
+        ConvertImage(Image, ifDefault);
+
+      Info := ImageFormatInfos[Image.Format];
+      Bpp := Info.BytesPerPixel;
+      ImageWidthBytes := Image.Width * Bpp;
+      RectWidthBytes := Width * Bpp;
+      LinePointer := @PByteArray(Image.Bits)[Y * ImageWidthBytes + X * Bpp];
+
+      for I := 0 to Height - 1 do
+      begin
+        case Bpp of
+          1: FillMemoryByte(LinePointer, RectWidthBytes, PByte(FillColor)^);
+          2: FillMemoryWord(LinePointer, RectWidthBytes, PWord(FillColor)^);
+          4: FillMemoryLongWord(LinePointer, RectWidthBytes, PLongWord(FillColor)^);
+        else
+          PixPointer := LinePointer;
+          for J := 0 to Width - 1 do
+          begin
+            CopyPixel(FillColor, PixPointer, Bpp);
+            Inc(PixPointer, Bpp);
+          end;
+        end;
+        Inc(LinePointer, ImageWidthBytes);
+      end;
+
+      if OldFmt <> Image.Format then
+        ConvertImage(Image, OldFmt);
+    end;
+
+    Result := True;
+  except
+    RaiseImaging(SErrorFillRect, [X, Y, Width, Height, ImageToStr(Image)]);
+  end;
+end;
+
+function ReplaceColor(var Image: TImageData; X, Y, Width, Height: LongInt;
+  OldColor, NewColor: Pointer): Boolean;
+var
+  Info: PImageFormatInfo;
+  I, J, WidthBytes, Bpp: Longint;
+  LinePointer, PixPointer: PByte;
+  OldFmt: TImageFormat;
+begin
+  Assert((OldColor <> nil) and (NewColor <> nil));
+  Result := False;
+  if TestImage(Image) then
+  try
+    ClipRectBounds(X, Y, Width, Height, Rect(0, 0, Image.Width, Image.Height));
+
+    if (Width > 0) and (Height > 0) then
+    begin
+      OldFmt := Image.Format;
+      if ImageFormatInfos[OldFmt].IsSpecial then
+        ConvertImage(Image, ifDefault);
+
+      Info := ImageFormatInfos[Image.Format];
+      Bpp := Info.BytesPerPixel;
+      WidthBytes := Image.Width * Bpp;
+      LinePointer := @PByteArray(Image.Bits)[Y * WidthBytes + X * Bpp];
+
+      for I := 0 to Height - 1 do
+      begin
+        PixPointer := LinePointer;
+        for J := 0 to Width - 1 do
+        begin
+          if ComparePixels(PixPointer, OldColor, Bpp) then
+            CopyPixel(NewColor, PixPointer, Bpp);
+          Inc(PixPointer, Bpp);
+        end;
+        Inc(LinePointer, WidthBytes);
+      end;
+
+      if OldFmt <> Image.Format then
+        ConvertImage(Image, OldFmt);
+    end;
+
+    Result := True;
+  except
+    RaiseImaging(SErrorReplaceColor, [X, Y, Width, Height, ImageToStr(Image)]);
+  end;
+end;
+
+function StretchRect(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt; Filter: TResizeFilter): Boolean;
+var
+  Info: PImageFormatInfo;
+  WorkImage: TImageData;
+  OldFormat: TImageFormat;
+  Resampling: TSamplingFilter;
+begin
+  Result := False;
+  OldFormat := ifUnknown;
+  if TestImage(SrcImage) and TestImage(DstImage) then
+  try
+    // Make sure we are still copying image to image, not invalid pointer to protected memory
+    ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, DstWidth, DstHeight,
+      SrcImage.Width, SrcImage.Height, Rect(0, 0, DstImage.Width, DstImage.Height));
+
+    if (SrcWidth = DstWidth) and (SrcHeight = DstHeight) then
+    begin
+      // If source and dest rectangles have the same size call CopyRect
+      Result := CopyRect(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY);
+    end
+    else if (SrcWidth > 0) and (SrcHeight > 0) and (DstWidth > 0) and (DstHeight > 0) then
+    begin
+      // If source and dest rectangles don't have the same size we do stretch
+      Info := ImageFormatInfos[DstImage.Format];
+
+      if Info.IsSpecial then
+      begin
+        // If dest image is in special format we convert it to default
+        OldFormat := Info.Format;
+        ConvertImage(DstImage, ifDefault);
+        Info := ImageFormatInfos[DstImage.Format];
+      end;
+
+      if SrcImage.Format <> DstImage.Format then
+      begin
+        // If images are in different format source is converted to dest's format
+        InitImage(WorkImage);
+        CloneImage(SrcImage, WorkImage);
+        ConvertImage(WorkImage, DstImage.Format);
+      end
+      else
+        WorkImage := SrcImage;
+
+      // Only pixel resize is supported for indexed images
+      if Info.IsIndexed then
+        Filter := rfNearest;
+
+      if Filter = rfNearest then
+      begin
+        StretchNearest(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight,
+          DstImage, DstX, DstY, DstWidth, DstHeight);
+      end
+      else
+      begin
+        Resampling := sfNearest;
+        case Filter of
+          rfBilinear: Resampling := sfLinear;
+          rfBicubic:  Resampling := DefaultCubicFilter;
+          rfLanczos:  Resampling := sfLanczos;
+        end;
+        StretchResample(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight,
+          DstImage, DstX, DstY, DstWidth, DstHeight, Resampling);
+      end;
+
+      // If dest image was in special format we convert it back
+      if OldFormat <> ifUnknown then
+        ConvertImage(DstImage, OldFormat);
+      // Working image must be freed if it is not the same as source image
+      if WorkImage.Bits <> SrcImage.Bits then
+        FreeImage(WorkImage);
+
+      Result := True;
+    end;
+  except
+    RaiseImaging(SErrorStretchRect, [ImageToStr(SrcImage), ImageToStr(DstImage)]);
+  end;
+end;
+
+procedure GetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer);
+var
+  BytesPerPixel: LongInt;
+begin
+  Assert(Pixel <> nil);
+  BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel;
+  CopyPixel(@PByteArray(Image.Bits)[(Y * Image.Width + X) * BytesPerPixel],
+    Pixel, BytesPerPixel);
+end;
+
+procedure SetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer);
+var
+  BytesPerPixel: LongInt;
+begin
+  Assert(Pixel <> nil);
+  BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel;
+  CopyPixel(Pixel, @PByteArray(Image.Bits)[(Y * Image.Width + X) * BytesPerPixel],
+    BytesPerPixel);
+end;
+
+function GetPixel32(const Image: TImageData; X, Y: LongInt): TColor32Rec;
+var
+  Info: PImageFormatInfo;
+  Data: PByte;
+begin
+  Info := ImageFormatInfos[Image.Format];
+  Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel];
+  Result := GetPixel32Generic(Data, Info, Image.Palette);
+end;
+
+procedure SetPixel32(const Image: TImageData; X, Y: LongInt; const Color: TColor32Rec);
+var
+  Info: PImageFormatInfo;
+  Data: PByte;
+begin
+  Info := ImageFormatInfos[Image.Format];
+  Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel];
+  SetPixel32Generic(Data, Info, Image.Palette, Color);
+end;
+
+function GetPixelFP(const Image: TImageData; X, Y: LongInt): TColorFPRec;
+var
+  Info: PImageFormatInfo;
+  Data: PByte;
+begin
+  Info := ImageFormatInfos[Image.Format];
+  Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel];
+  Result := GetPixelFPGeneric(Data, Info, Image.Palette);
+end;
+
+procedure SetPixelFP(const Image: TImageData; X, Y: LongInt; const Color: TColorFPRec);
+var
+  Info: PImageFormatInfo;
+  Data: PByte;
+begin
+  Info := ImageFormatInfos[Image.Format];
+  Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel];
+  SetPixelFPGeneric(Data, Info, Image.Palette, Color);
+end;
+
+{ Palette Functions }
+
+procedure NewPalette(Entries: LongInt; var Pal: PPalette32);
+begin
+  Assert((Entries > 2) and (Entries <= 65535));
+  try
+    GetMem(Pal, Entries * SizeOf(TColor32Rec));
+    FillChar(Pal^, Entries * SizeOf(TColor32Rec), $FF);
+  except
+    RaiseImaging(SErrorNewPalette, [Entries]);
+  end;
+end;
+
+procedure FreePalette(var Pal: PPalette32);
+begin
+  try
+    FreeMemNil(Pal);
+  except
+    RaiseImaging(SErrorFreePalette, [Pal]);
+  end;
+end;
+
+procedure CopyPalette(SrcPal, DstPal: PPalette32; SrcIdx, DstIdx, Count: LongInt);
+begin
+  Assert((SrcPal <> nil) and (DstPal <> nil));
+  Assert((SrcIdx >= 0) and (DstIdx >= 0) and (Count >= 0));
+  try
+    Move(SrcPal[SrcIdx], DstPal[DstIdx], Count * SizeOf(TColor32Rec));
+  except
+    RaiseImaging(SErrorCopyPalette, [Count, SrcPal, DstPal]);
+  end;
+end;
+
+function FindColor(Pal: PPalette32; Entries: LongInt; Color: TColor32):
+  LongInt;
+var
+  Col: TColor32Rec;
+  I, MinDif, Dif: LongInt;
+begin
+  Assert(Pal <> nil);
+  Result := -1;
+  Col.Color := Color;
+  try
+    // First try to find exact match
+    for I := 0 to Entries - 1 do
+    with Pal[I] do
+    begin
+      if (A = Col.A) and (R = Col.R) and
+        (G = Col.G) and (B = Col.B) then
+      begin
+        Result := I;
+        Exit;
+      end;
+    end;
+
+    // If exact match was not found, find nearest color
+    MinDif := 1020;
+    for I := 0 to Entries - 1 do
+    with Pal[I] do
+    begin
+      Dif := Abs(R - Col.R);
+      if Dif > MinDif then Continue;
+      Dif := Dif + Abs(G - Col.G);
+      if Dif > MinDif then Continue;
+      Dif := Dif + Abs(B - Col.B);
+      if Dif > MinDif then Continue;
+      Dif := Dif + Abs(A - Col.A);
+      if Dif < MinDif then
+      begin
+        MinDif := Dif;
+        Result := I;
+      end;
+    end;
+  except
+    RaiseImaging(SErrorFindColor, [Pal, Entries]);
+  end;
+end;
+
+procedure FillGrayscalePalette(Pal: PPalette32; Entries: LongInt);
+var
+  I: LongInt;
+begin
+  Assert(Pal <> nil);
+  try
+    for I := 0 to Entries - 1 do
+    with Pal[I] do
+    begin
+      A := $FF;
+      R := Byte(I);
+      G := Byte(I);
+      B := Byte(I);
+    end;
+  except
+    RaiseImaging(SErrorGrayscalePalette, [Pal, Entries]);
+  end;
+end;
+
+procedure FillCustomPalette(Pal: PPalette32; Entries: LongInt; RBits, GBits,
+  BBits: Byte; Alpha: Byte = $FF);
+var
+  I, TotalBits, MaxEntries: LongInt;
+begin
+  Assert(Pal <> nil);
+  TotalBits := RBits + GBits + BBits;
+  MaxEntries := Min(Pow2Int(TotalBits), Entries);
+  FillChar(Pal^, Entries * SizeOf(TColor32Rec), 0);
+  try
+    for I := 0 to MaxEntries - 1 do
+    with Pal[I] do
+    begin
+      A := Alpha;
+      if RBits > 0 then
+        R := ((I shr Max(0, GBits + BBits - 1)) and (1 shl RBits - 1)) * 255 div (1 shl RBits - 1);
+      if GBits > 0 then
+        G := ((I shr Max(0, BBits - 1)) and (1 shl GBits - 1)) * 255 div (1 shl GBits - 1);
+      if BBits > 0 then
+        B := ((I shr 0) and (1 shl BBits - 1)) * 255 div (1 shl BBits - 1);
+    end;
+  except
+    RaiseImaging(SErrorCustomPalette, [Pal, Entries]);
+  end;
+end;
+
+procedure SwapChannelsOfPalette(Pal: PPalette32; Entries, SrcChannel,
+  DstChannel: LongInt);
+var
+  I: LongInt;
+  Swap: Byte;
+begin
+  Assert(Pal <> nil);
+  Assert((SrcChannel in [0..3]) and (DstChannel in [0..3]));
+  try
+    for I := 0 to Entries - 1 do
+    with Pal[I] do
+    begin
+      Swap := Channels[SrcChannel];
+      Channels[SrcChannel] := Channels[DstChannel];
+      Channels[DstChannel] := Swap;
+    end;
+  except
+    RaiseImaging(SErrorSwapPalette, [Pal, Entries]);
+  end;
+end;
+
+{ Options Functions }
+
+function SetOption(OptionId, Value: LongInt): Boolean;
+begin
+  Result := False;
+  if (OptionId >= 0) and (OptionId < Length(Options)) and
+    (Options[OptionID] <> nil) then
+  begin
+    Options[OptionID]^ := CheckOptionValue(OptionId, Value);
+    Result := True;
+  end;
+end;
+
+function GetOption(OptionId: LongInt): LongInt;
+begin
+  Result := InvalidOption;
+  if (OptionId >= 0) and (OptionId < Length(Options)) and
+    (Options[OptionID] <> nil) then
+  begin
+    Result := Options[OptionID]^;
+  end;
+end;
+
+function PushOptions: Boolean;
+begin
+  Result := OptionStack.Push;
+end;
+
+function PopOptions: Boolean;
+begin
+  Result := OptionStack.Pop;
+end;
+
+{ Image Format Functions }
+
+function GetImageFormatInfo(Format: TImageFormat; out Info: TImageFormatInfo): Boolean;
+begin
+  FillChar(Info, SizeOf(Info), 0);
+  if ImageFormatInfos[Format] <> nil then
+  begin
+    Info := ImageFormatInfos[Format]^;
+    Result := True;
+  end
+  else
+    Result := False;
+end;
+
+function GetPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
+begin
+  if ImageFormatInfos[Format] <> nil then
+    Result := ImageFormatInfos[Format].GetPixelsSize(Format, Width, Height)
+  else
+    Result := 0;
+end;
+
+{ IO Functions }
+
+procedure SetUserFileIO(OpenProc: TOpenProc;
+  CloseProc: TCloseProc; EofProc: TEofProc; SeekProc: TSeekProc; TellProc:
+  TTellProc; ReadProc: TReadProc; WriteProc: TWriteProc);
+begin
+  FileIO.Open := OpenProc;
+  FileIO.Close := CloseProc;
+  FileIO.Eof := EofProc;
+  FileIO.Seek := SeekProc;
+  FileIO.Tell := TellProc;
+  FileIO.Read := ReadProc;
+  FileIO.Write := WriteProc;
+end;
+
+procedure ResetFileIO;
+begin
+  FileIO := OriginalFileIO;
+end;
+
+{ Raw Image IO Functions }
+
+procedure ReadRawImage(Handle: TImagingHandle;  Width, Height: Integer;
+  Format: TImageFormat; out Image: TImageData; Offset, RowLength: Integer);
+var
+  WidthBytes, I: Integer;
+  Info: PImageFormatInfo;
+begin
+  Info := ImageFormatInfos[Format];
+  // Calc scanline size
+  WidthBytes := Info.GetPixelsSize(Format, Width, 1);
+  if RowLength = 0 then
+    RowLength := WidthBytes;
+  // Create new image if needed - don't need to allocate new one if there is already
+  // one with desired size and format
+  if (Image.Width <> Width) or (Image.Height <> Height) or (Image.Format <> Format) then
+    NewImage(Width, Height, Format, Image);
+  // Move past the header
+  IO.Seek(Handle, Offset, smFromCurrent);
+  // Read scanlines from input
+  for I := 0 to Height - 1 do
+  begin
+    IO.Read(Handle, @PByteArray(Image.Bits)[I * WidthBytes], WidthBytes);
+    IO.Seek(Handle, RowLength - WidthBytes, smFromCurrent);
+  end;
+end;
+
+procedure ReadRawImageFromFile(const FileName: string; Width, Height: Integer;
+  Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer);
+var
+  Handle: TImagingHandle;
+begin
+  Assert(FileName <> '');
+  // Set IO ops to file ops and open given file
+  SetFileIO;
+  Handle := IO.Open(PChar(FileName), omReadOnly);
+  try
+    ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength);
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+procedure ReadRawImageFromStream(Stream: TStream; Width, Height: Integer;
+  Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer);
+var
+  Handle: TImagingHandle;
+begin
+  Assert(Stream <> nil);
+  if Stream.Size - Stream.Position = 0 then
+    RaiseImaging(SErrorEmptyStream, []);
+  // Set IO ops to stream ops and open given stream
+  SetStreamIO;
+  Handle := IO.Open(Pointer(Stream), omReadOnly);
+  try
+    ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength);
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+procedure ReadRawImageFromMemory(Data: Pointer; DataSize: Integer; Width, Height: Integer;
+  Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer);
+var
+  Handle: TImagingHandle;
+  MemRec: TMemoryIORec;
+begin
+  Assert((Data <> nil) and (DataSize > 0));
+  // Set IO ops to memory ops and open given stream
+  SetMemoryIO;
+  MemRec := PrepareMemIO(Data, DataSize);
+  Handle := IO.Open(@MemRec, omReadOnly);
+  try
+    ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength);
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+procedure ReadRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer;
+  var Image: TImageData; Offset, RowLength: Integer);
+var
+  DestScanBytes, RectBytes, I: Integer;
+  Info: PImageFormatInfo;
+  Src, Dest: PByte;
+begin
+  Assert(Data <> nil);
+  Assert((Left + Width <= Image.Width) and (Top + Height <= Image.Height));
+  Info := ImageFormatInfos[Image.Format];
+
+  // Calc scanline size
+  DestScanBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1);
+  RectBytes := Info.GetPixelsSize(Info.Format, Width, 1);
+  if RowLength = 0 then
+    RowLength := RectBytes;
+
+  Src := Data;
+  Dest := @PByteArray(Image.Bits)[Top * DestScanBytes + Info.GetPixelsSize(Info.Format, Left, 1)];
+  // Move past the header
+  Inc(Src, Offset);
+
+  // Read lines into rect in the existing image
+  for I := 0 to Height - 1 do
+  begin
+    Move(Src^, Dest^, RectBytes);
+    Inc(Src, RowLength);
+    Inc(Dest, DestScanBytes);
+  end;
+end;
+
+procedure WriteRawImage(Handle: TImagingHandle; const Image: TImageData;
+  Offset, RowLength: Integer);
+var
+  WidthBytes, I: Integer;
+  Info: PImageFormatInfo;
+begin
+  Info := ImageFormatInfos[Image.Format];
+  // Calc scanline size
+  WidthBytes := Info.GetPixelsSize(Image.Format, Image.Width, 1);
+  if RowLength = 0 then
+    RowLength := WidthBytes;
+  // Move past the header
+  IO.Seek(Handle, Offset, smFromCurrent);
+  // Write scanlines to output
+  for I := 0 to Image.Height - 1 do
+  begin
+    IO.Write(Handle, @PByteArray(Image.Bits)[I * WidthBytes], WidthBytes);
+    IO.Seek(Handle, RowLength - WidthBytes, smFromCurrent);
+  end;
+end;
+
+procedure WriteRawImageToFile(const FileName: string; const Image: TImageData;
+  Offset, RowLength: Integer);
+var
+  Handle: TImagingHandle;
+begin
+  Assert(FileName <> '');
+  // Set IO ops to file ops and open given file
+  SetFileIO;
+  Handle := IO.Open(PChar(FileName), omCreate);
+  try
+    WriteRawImage(Handle, Image, Offset, RowLength);
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+procedure WriteRawImageToStream(Stream: TStream; const Image: TImageData;
+  Offset, RowLength: Integer);
+var
+  Handle: TImagingHandle;
+begin
+  Assert(Stream <> nil);
+  // Set IO ops to stream ops and open given stream
+  SetStreamIO;
+  Handle := IO.Open(Pointer(Stream), omCreate);
+  try
+    WriteRawImage(Handle, Image, Offset, RowLength);
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+procedure WriteRawImageToMemory(Data: Pointer; DataSize: Integer; const Image: TImageData;
+  Offset, RowLength: Integer);
+var
+  Handle: TImagingHandle;
+  MemRec: TMemoryIORec;
+begin
+  Assert((Data <> nil) and (DataSize > 0));
+  // Set IO ops to memory ops and open given stream
+  SetMemoryIO;
+  MemRec := PrepareMemIO(Data, DataSize);
+  Handle := IO.Open(@MemRec, omCreate);
+  try
+    WriteRawImage(Handle, Image, Offset, RowLength);
+  finally
+    IO.Close(Handle);
+  end;
+end;
+
+procedure WriteRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer;
+  const Image: TImageData; Offset, RowLength: Integer);
+var
+  SrcScanBytes, RectBytes, I: Integer;
+  Info: PImageFormatInfo;
+  Src, Dest: PByte;
+begin
+  Assert(Data <> nil);
+  Assert((Left + Width <= Image.Width) and (Top + Height <= Image.Height));
+  Info := ImageFormatInfos[Image.Format];
+
+  // Calc scanline size
+  SrcScanBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1);
+  RectBytes := Info.GetPixelsSize(Info.Format, Width, 1);
+  if RowLength = 0 then
+    RowLength := RectBytes;
+
+  Src := @PByteArray(Image.Bits)[Top * SrcScanBytes + Info.GetPixelsSize(Info.Format, Left, 1)];
+  Dest := Data;
+  // Move past the header
+  Inc(Dest, Offset);
+
+  // Write lines from rect of the existing image
+  for I := 0 to Height - 1 do
+  begin
+    Move(Src^, Dest^, RectBytes);
+    Inc(Dest, RowLength);
+    Inc(Src, SrcScanBytes);
+  end;
+end;
+
+{ Convenience/helper Functions }
+
+procedure ResizeImageToFit(const SrcImage: TImageData; FitWidth, FitHeight: Integer;
+  Filter: TResizeFilter; var DestImage: TImageData);
+var
+  CurSize, FitSize, DestSize: TSize;
+begin
+  if not TestImage(SrcImage) then
+    raise EImagingError.Create(SErrorInvalidInputImage);
+
+  FitSize.CX := FitWidth;
+  FitSize.CY := FitHeight;
+  CurSize.CX := SrcImage.Width;
+  CurSize.CY := SrcImage.Height;
+  DestSize := ImagingUtility.ScaleSizeToFit(CurSize, FitSize);
+
+  NewImage(Max(DestSize.CX, 1), Max(DestSize.CY, 1), SrcImage.Format, DestImage);
+  if SrcImage.Palette <> nil then
+    CopyPalette(SrcImage.Palette, DestImage.Palette, 0, 0, ImageFormatInfos[SrcImage.Format].PaletteEntries);
+
+  StretchRect(SrcImage, 0, 0, CurSize.CX, CurSize.CY, DestImage, 0, 0,
+    DestSize.CX, DestSize.CY, Filter);
+end;
+
+{ ------------------------------------------------------------------------
+                           Other Imaging Stuff
+  ------------------------------------------------------------------------}
+
+function GetFormatName(Format: TImageFormat): string;
+begin
+  if ImageFormatInfos[Format] <> nil then
+    Result := ImageFormatInfos[Format].Name
+  else
+    Result := SUnknownFormat;
+end;
+
+function ImageToStr(const Image: TImageData): string;
+var
+  ImgSize: Integer;
+begin
+  if TestImage(Image) then
+  with Image do
+  begin
+    ImgSize := Size;
+    if ImgSize > 8192 then
+      ImgSize := ImgSize div 1024;
+    Result := SysUtils.Format(SImageInfo, [@Image, Width, Height,
+      GetFormatName(Format), ImgSize + 0.0, Iff(ImgSize = Size, 'B', 'KiB'), Bits,
+      Palette]);
+  end
+  else
+    Result := SysUtils.Format(SImageInfoInvalid, [@Image]);
+end;
+
+function GetVersionStr: string;
+begin
+  Result := Format('%.1d.%.2d.%.1d', [ImagingVersionMajor,
+    ImagingVersionMinor, ImagingVersionPatch]);
+end;
+
+function IffFormat(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+procedure RegisterImageFileFormat(AClass: TImageFileFormatClass);
+begin
+  Assert(AClass <> nil);
+  if ImageFileFormats = nil then
+    ImageFileFormats := TList.Create;
+  if GlobalMetadata = nil then
+    GlobalMetadata := TMetadata.Create;
+  if ImageFileFormats <> nil then
+    ImageFileFormats.Add(AClass.Create);
+end;
+
+function RegisterOption(OptionId: LongInt; Variable: PLongInt): Boolean;
+begin
+  Result := False;
+  if Options = nil then
+    InitOptions;
+
+  Assert(Variable <> nil);
+
+  if OptionId >= Length(Options) then
+    SetLength(Options, OptionId + InitialOptions);
+  if (OptionId >= 0) and (OptionId < Length(Options)) {and (Options[OptionId] = nil) - must be able to override existing } then
+  begin
+    Options[OptionId] := Variable;
+    Result := True;
+  end;
+end;
+
+function FindImageFileFormatByExt(const Ext: string): TImageFileFormat;
+var
+  I: LongInt;
+begin
+  Result := nil;
+  for I := ImageFileFormats.Count - 1 downto 0 do
+    if TImageFileFormat(ImageFileFormats[I]).Extensions.IndexOf(Ext) >= 0 then
+    begin
+      Result := TImageFileFormat(ImageFileFormats[I]);
+      Exit;
+    end;
+end;
+
+function FindImageFileFormatByName(const FileName: string): TImageFileFormat;
+var
+  I: LongInt;
+begin
+  Result := nil;
+  for I := ImageFileFormats.Count - 1 downto 0 do
+    if TImageFileFormat(ImageFileFormats[I]).TestFileName(FileName) then
+    begin
+      Result := TImageFileFormat(ImageFileFormats[I]);
+      Exit;
+    end;
+end;
+
+function FindImageFileFormatByClass(AClass: TImageFileFormatClass): TImageFileFormat;
+var
+  I: LongInt;
+begin
+  Result := nil;
+  for I := 0 to ImageFileFormats.Count - 1 do
+    if TImageFileFormat(ImageFileFormats[I]) is AClass then
+    begin
+      Result := TObject(ImageFileFormats[I]) as TImageFileFormat;
+      Break;
+    end;
+end;
+
+function GetFileFormatCount: LongInt;
+begin
+  Result := ImageFileFormats.Count;
+end;
+
+function GetFileFormatAtIndex(Index: LongInt): TImageFileFormat;
+begin
+  if (Index >= 0) and (Index < ImageFileFormats.Count) then
+    Result := TImageFileFormat(ImageFileFormats[Index])
+  else
+    Result := nil;
+end;
+
+function GetImageFileFormatsFilter(OpenFileFilter: Boolean): string;
+var
+  I, J, Count: LongInt;
+  Descriptions: string;
+  Filters, CurFilter: string;
+  FileFormat: TImageFileFormat;
+begin
+  Descriptions := '';
+  Filters := '';
+  Count := 0;
+
+  for I := 0 to ImageFileFormats.Count - 1 do
+  begin
+    FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat;
+
+    // If we are creating filter for save dialog and this format cannot save
+    // files the we skip it
+    if not OpenFileFilter and not FileFormat.CanSave then
+      Continue;
+
+    CurFilter := '';
+    for J := 0 to FileFormat.Masks.Count - 1 do
+    begin
+      CurFilter := CurFilter + FileFormat.Masks[J];
+      if J < FileFormat.Masks.Count - 1 then
+        CurFilter := CurFilter + ';';
+    end;
+
+    FmtStr(Descriptions, '%s%s (%s)|%2:s', [Descriptions, FileFormat.Name, CurFilter]);
+    if Filters <> '' then
+      FmtStr(Filters, '%s;%s', [Filters, CurFilter])
+    else
+      Filters := CurFilter;
+
+    if I < ImageFileFormats.Count - 1 then
+        Descriptions := Descriptions + '|';
+
+    Inc(Count);
+  end;
+
+  if (Count > 1) and OpenFileFilter then
+    FmtStr(Descriptions, '%s (%s)|%1:s|%s', [SAllFilter, Filters, Descriptions]);
+
+  Result := Descriptions;
+end;
+
+function GetFilterIndexExtension(Index: LongInt; OpenFileFilter: Boolean): string;
+var
+  I, Count: LongInt;
+  FileFormat: TImageFileFormat;
+begin
+  // -1 because filter indices are in 1..n range
+  Index := Index - 1;
+  Result := '';
+  if OpenFileFilter then
+  begin
+    if Index > 0 then
+      Index := Index - 1;
+  end;
+
+  if (Index >= 0) and (Index < ImageFileFormats.Count) then
+  begin
+    Count := 0;
+    for I := 0 to ImageFileFormats.Count - 1 do
+    begin
+      FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat;
+      if not OpenFileFilter and not FileFormat.CanSave then
+        Continue;
+      if Index = Count then
+      begin
+        if FileFormat.Extensions.Count > 0 then
+          Result := FileFormat.Extensions[0];
+        Exit;
+      end;
+      Inc(Count);
+    end;
+  end;
+end;
+
+function GetFileNameFilterIndex(const FileName: string; OpenFileFilter: Boolean): LongInt;
+var
+  I: LongInt;
+  FileFormat: TImageFileFormat;
+begin
+  Result := 0;
+  for I := 0 to ImageFileFormats.Count - 1 do
+  begin
+    FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat;
+    if not OpenFileFilter and not FileFormat.CanSave then
+      Continue;
+    if FileFormat.TestFileName(FileName) then
+    begin
+      // +1 because filter indices are in 1..n range
+      Inc(Result);
+      if OpenFileFilter then
+        Inc(Result);
+      Exit;
+    end;
+    Inc(Result);
+  end;
+  Result := -1;
+end;
+
+function GetIO: TIOFunctions;
+begin
+  Result := IO;
+end;
+
+procedure RaiseImaging(const Msg: string; const Args: array of const);
+var
+  WholeMsg: string;
+begin
+  WholeMsg := Msg;
+  if GetExceptObject <> nil then
+  begin
+    WholeMsg := WholeMsg + ' ' + SExceptMsg + ': ' +
+      GetExceptObject.Message;
+  end;
+  raise EImagingError.CreateFmt(WholeMsg, Args);
+end;
+
+procedure RaiseImaging(const Msg: string);
+begin
+  RaiseImaging(Msg, []);
+end;
+
+{ Internal unit functions }
+
+function CheckOptionValue(OptionId, Value: LongInt): LongInt;
+begin
+  case OptionId of
+    ImagingColorReductionMask:
+      Result := ClampInt(Value, 0, $FF);
+    ImagingLoadOverrideFormat, ImagingSaveOverrideFormat:
+      Result := Iff(ImagingFormats.IsImageFormatValid(TImageFormat(Value)),
+        Value, LongInt(ifUnknown));
+    ImagingMipMapFilter: Result := ClampInt(Value, Ord(Low(TSamplingFilter)),
+        Ord(High(TSamplingFilter)));
+  else
+    Result := Value;
+  end;
+end;
+
+procedure SetFileIO;
+begin
+  IO := FileIO;
+end;
+
+procedure SetStreamIO;
+begin
+  IO := StreamIO;
+end;
+
+procedure SetMemoryIO;
+begin
+  IO := MemoryIO;
+end;
+
+procedure InitImageFormats;
+begin
+  ImagingFormats.InitImageFormats(ImageFormatInfos);
+end;
+
+procedure FreeImageFileFormats;
+var
+  I: LongInt;
+begin
+  if ImageFileFormats <> nil then
+    for I := 0 to ImageFileFormats.Count - 1 do
+      TImageFileFormat(ImageFileFormats[I]).Free;
+  FreeAndNil(ImageFileFormats);
+end;
+
+procedure InitOptions;
+begin
+  SetLength(Options, InitialOptions);
+  OptionStack := TOptionStack.Create;
+end;
+
+procedure FreeOptions;
+begin
+  SetLength(Options, 0);
+  FreeAndNil(OptionStack);
+end;
+
+{
+  TImageFileFormat class implementation
+}
+
+constructor TImageFileFormat.Create(AMetadata: TMetadata);
+begin
+  inherited Create;
+  FName := SUnknownFormat;
+  FExtensions := TStringList.Create;
+  FMasks := TStringList.Create;
+  if AMetadata = nil then
+    FMetadata := GlobalMetadata
+  else
+    FMetadata := AMetadata;
+  Define;
+end;
+
+destructor TImageFileFormat.Destroy;
+begin
+  FExtensions.Free;
+  FMasks.Free;
+  inherited Destroy;
+end;
+
+procedure TImageFileFormat.Define;
+begin
+end;
+
+function TImageFileFormat.PrepareLoad(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean;
+begin
+  FMetadata.ClearMetaItems; // Clear old metadata
+  FreeImagesInArray(Images);
+  SetLength(Images, 0);
+  Result := Handle <> nil;
+end;
+
+function TImageFileFormat.PostLoadCheck(var Images: TDynImageDataArray;
+  LoadResult: Boolean): Boolean;
+var
+  I: LongInt;
+begin
+  if not LoadResult then
+  begin
+    FreeImagesInArray(Images);
+    SetLength(Images, 0);
+    Result := False;
+  end
+  else
+  begin
+    Result := (Length(Images) > 0) and TestImagesInArray(Images);
+
+    if Result then
+    begin
+      // Convert to overriden format if it is set
+      if LoadOverrideFormat <> ifUnknown then
+        for I := Low(Images) to High(Images) do
+          ConvertImage(Images[I], LoadOverrideFormat);
+    end;
+  end;
+end;
+
+function TImageFileFormat.PrepareSave(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; var Index: Integer): Boolean;
+var
+  Len, I: LongInt;
+begin
+  CheckOptionsValidity;
+  Result := False;
+  if CanSave then
+  begin
+    Len := Length(Images);
+    Assert(Len > 0);
+
+    // If there are no images to be saved exit
+    if Len = 0 then Exit;
+
+    // Check index of image to be saved (-1 as index means save all images)
+    if IsMultiImageFormat then
+    begin
+      if (Index >= Len) then
+        Index := 0;
+
+      if Index < 0 then
+      begin
+        Index := 0;
+        FFirstIdx := 0;
+        FLastIdx := Len - 1;
+      end
+      else
+      begin
+        FFirstIdx := Index;
+        FLastIdx := Index;
+      end;
+
+      for I := FFirstIdx to FLastIdx - 1 do
+      begin
+        if not TestImage(Images[I]) then
+          Exit;
+      end;
+    end
+    else
+    begin
+      if (Index >= Len) or (Index < 0) then
+        Index := 0;
+      if not TestImage(Images[Index]) then
+        Exit;
+    end;
+
+    Result := True;
+  end;
+end;
+
+procedure TImageFileFormat.AddMasks(const AMasks: string);
+var
+  I: LongInt;
+  Ext: string;
+begin
+  FExtensions.Clear;
+  FMasks.CommaText := AMasks;
+  FMasks.Delimiter := ';';
+
+  for I := 0 to FMasks.Count - 1 do
+  begin
+    FMasks[I] := Trim(FMasks[I]);
+    Ext := GetFileExt(FMasks[I]);
+    if (Ext <> '') and (Ext <> '*') then
+      FExtensions.Add(Ext);
+  end;
+end;
+
+function TImageFileFormat.GetFormatInfo(Format: TImageFormat): TImageFormatInfo;
+begin
+  Result := ImageFormatInfos[Format]^;
+end;
+
+function TImageFileFormat.GetSupportedFormats: TImageFormats;
+begin
+  Result := FSupportedFormats;
+end;
+
+function TImageFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean;
+begin
+  Result := False;
+  RaiseImaging(SFileFormatCanNotLoad, [FName]);
+end;
+
+function TImageFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+begin
+  Result := False;
+  RaiseImaging(SFileFormatCanNotSave, [FName]);
+end;
+
+procedure TImageFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+begin
+end;
+
+function TImageFileFormat.IsSupported(const Image: TImageData): Boolean;
+begin
+  Result := Image.Format in GetSupportedFormats;
+end;
+
+function TImageFileFormat.LoadFromFile(const FileName: string;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Handle: TImagingHandle;
+begin
+  Result := False;
+  if CanLoad then
+  try
+    // Set IO ops to file ops and open given file
+    SetFileIO;
+    Handle := IO.Open(PChar(FileName), omReadOnly);
+    try
+      // Test if file contains valid image and if so then load it
+      if TestFormat(Handle) then
+      begin
+        Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and
+          LoadData(Handle, Images, OnlyFirstlevel);
+        Result := PostLoadCheck(Images, Result);
+      end
+      else
+        RaiseImaging(SFileNotValid, [FileName, Name]);
+    finally
+      IO.Close(Handle);
+    end;
+  except
+    RaiseImaging(SErrorLoadingFile, [FileName, FExtensions[0]]);
+  end;
+end;
+
+function TImageFileFormat.LoadFromStream(Stream: TStream;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Handle: TImagingHandle;
+  OldPosition: Int64;
+begin
+  Result := False;
+  OldPosition := Stream.Position;
+  if CanLoad then
+  try
+    // Set IO ops to stream ops and "open" given memory
+    SetStreamIO;
+    Handle := IO.Open(Pointer(Stream), omReadOnly);
+    try
+      // Test if stream contains valid image and if so then load it
+      if TestFormat(Handle) then
+      begin
+        Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and
+          LoadData(Handle, Images, OnlyFirstlevel);
+        Result := PostLoadCheck(Images, Result);
+      end
+      else
+        RaiseImaging(SStreamNotValid, [@Stream, Name]);
+    finally
+      IO.Close(Handle);
+    end;
+  except
+    Stream.Position := OldPosition;
+    FreeImagesInArray(Images);
+    RaiseImaging(SErrorLoadingStream, [@Stream, FExtensions[0]]);
+  end;
+end;
+
+function TImageFileFormat.LoadFromMemory(Data: Pointer; Size: LongInt; var
+  Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Handle: TImagingHandle;
+  IORec: TMemoryIORec;
+begin
+  Result := False;
+  if CanLoad then
+  try
+    // Set IO ops to memory ops and "open" given memory
+    SetMemoryIO;
+    IORec := PrepareMemIO(Data, Size);
+    Handle := IO.Open(@IORec,omReadOnly);
+    try
+      // Test if memory contains valid image and if so then load it
+      if TestFormat(Handle) then
+      begin
+        Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and
+          LoadData(Handle, Images, OnlyFirstlevel);
+        Result := PostLoadCheck(Images, Result);
+      end
+      else
+        RaiseImaging(SMemoryNotValid, [Data, Size, Name]);
+    finally
+      IO.Close(Handle);
+    end;
+  except
+    RaiseImaging(SErrorLoadingMemory, [Data, Size, FExtensions[0]]);
+  end;
+end;
+
+function TImageFileFormat.SaveToFile(const FileName: string;
+  const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Handle: TImagingHandle;
+  Len, Index, I: LongInt;
+  Ext, FName: string;
+begin
+  Result := False;
+  if CanSave and TestImagesInArray(Images) then
+  try
+    SetFileIO;
+    Len := Length(Images);
+    if IsMultiImageFormat or
+      (not IsMultiImageFormat and (OnlyFirstLevel or (Len = 1))) then
+    begin
+      Handle := IO.Open(PChar(FileName), GetSaveOpenMode);
+      try
+        if OnlyFirstLevel then
+          Index := 0
+        else
+          Index := -1;
+        // Write multi image to one file
+        Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index);
+      finally
+        IO.Close(Handle);
+      end;
+    end
+    else
+    begin
+      // Write multi image to file sequence
+      Ext := ExtractFileExt(FileName);
+      FName := ChangeFileExt(FileName, '');
+      Result := True;
+      for I := 0 to Len - 1 do
+      begin
+        Handle := IO.Open(PChar(Format(FName + '%.3d' + Ext, [I])), GetSaveOpenMode);
+        try
+          Index := I;
+          Result := Result and PrepareSave(Handle, Images, Index) and
+            SaveData(Handle, Images, Index);
+          if not Result then
+            Break;
+        finally
+          IO.Close(Handle);
+        end;
+      end;
+    end;
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorSavingFile, [FileName, FExtensions[0]]);
+  end;
+end;
+
+function TImageFileFormat.SaveToStream(Stream: TStream;
+  const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Handle: TImagingHandle;
+  Len, Index, I: LongInt;
+  OldPosition: Int64;
+begin
+  Result := False;
+  OldPosition := Stream.Position;
+  if CanSave and TestImagesInArray(Images) then
+  try
+    SetStreamIO;
+    Handle := IO.Open(PChar(Stream), GetSaveOpenMode);
+    try
+      if IsMultiImageFormat or OnlyFirstLevel then
+      begin
+        if OnlyFirstLevel then
+          Index := 0
+        else
+          Index := -1;
+        // Write multi image in one run
+        Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index);
+      end
+      else
+      begin
+        // Write multi image to sequence
+        Result := True;
+        Len := Length(Images);
+        for I := 0 to Len - 1 do
+        begin
+          Index := I;
+          Result := Result and PrepareSave(Handle, Images, Index) and
+            SaveData(Handle, Images, Index);
+          if not Result then
+            Break;
+        end;
+      end;
+    finally
+      IO.Close(Handle);
+    end;
+  except
+    Stream.Position := OldPosition;
+    raise UpdateExceptMessage(GetExceptObject, SErrorSavingStream, [@Stream, FExtensions[0]]);
+  end;
+end;
+
+function TImageFileFormat.SaveToMemory(Data: Pointer; var Size: LongInt;
+  const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Handle: TImagingHandle;
+  Len, Index, I: LongInt;
+  IORec: TMemoryIORec;
+begin
+  Result := False;
+  if CanSave and TestImagesInArray(Images) then
+  try
+    SetMemoryIO;
+    IORec := PrepareMemIO(Data, Size);
+    Handle := IO.Open(PChar(@IORec), GetSaveOpenMode);
+    try
+      if IsMultiImageFormat or OnlyFirstLevel then
+      begin
+        if OnlyFirstLevel then
+          Index := 0
+        else
+          Index := -1;
+        // Write multi image in one run
+        Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index);
+      end
+      else
+      begin
+        // Write multi image to sequence
+        Result := True;
+        Len := Length(Images);
+        for I := 0 to Len - 1 do
+        begin
+          Index := I;
+          Result := Result and PrepareSave(Handle, Images, Index) and
+            SaveData(Handle, Images, Index);
+          if not Result then
+            Break;
+        end;
+      end;
+      Size := IORec.Position;
+    finally
+      IO.Close(Handle);
+    end;
+  except
+    raise UpdateExceptMessage(GetExceptObject, SErrorSavingMemory, [Data, Size, FExtensions[0]]);
+  end;
+end;
+
+function TImageFileFormat.MakeCompatible(const Image: TImageData;
+  var Compatible: TImageData; out MustBeFreed: Boolean): Boolean;
+begin
+  InitImage(Compatible);
+
+  if SaveOverrideFormat <> ifUnknown then
+  begin
+    // Save format override is active. Clone input and convert it to override format.
+    CloneImage(Image, Compatible);
+    ConvertImage(Compatible, SaveOverrideFormat);
+    // Now check if override format is supported by file format. If it is not
+    // then file format specific conversion (virtual method) is called.
+    Result := IsSupported(Compatible);
+    if not Result then
+    begin
+      ConvertToSupported(Compatible, GetFormatInfo(Compatible.Format));
+      Result := IsSupported(Compatible);
+    end;
+  end     // Add IsCompatible function! not only checking by Format
+  else if IsSupported(Image) then
+  begin
+    // No save format override and input is in format supported by this
+    // file format. Just copy Image's fields to Compatible
+    Compatible := Image;
+    Result := True;
+  end
+  else
+  begin
+    // No override and input's format is not compatible with file format.
+    // Clone it and the call file format specific conversion (virtual method).
+    CloneImage(Image, Compatible);
+    ConvertToSupported(Compatible, GetFormatInfo(Compatible.Format));
+    Result := IsSupported(Compatible);
+  end;
+  // Tell the user that he must free Compatible after he's done with it
+  // (if necessary).
+  MustBeFreed := Image.Bits <> Compatible.Bits;
+end;
+
+function TImageFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+begin
+  Result := False;
+end;
+
+function TImageFileFormat.TestFileName(const FileName: string): Boolean;
+var
+  I: LongInt;
+  OnlyName: string;
+begin
+  OnlyName := ExtractFileName(FileName);
+  // For each mask test if filename matches it
+  for I := 0 to FMasks.Count - 1 do
+    if StrMaskMatch(OnlyName, FMasks[I], False) then
+    begin
+      Result := True;
+      Exit;
+    end;
+  Result := False;
+end;
+
+procedure TImageFileFormat.CheckOptionsValidity;
+begin
+end;
+
+function TImageFileFormat.GetCanLoad: Boolean;
+begin
+  Result := ffLoad in FFeatures;
+end;
+
+function TImageFileFormat.GetCanSave: Boolean;
+begin
+  Result := ffSave in FFeatures;
+end;
+
+function TImageFileFormat.GetIsMultiImageFormat: Boolean;
+begin
+  Result := ffMultiImage in FFeatures;
+end;
+
+function TImageFileFormat.GetSaveOpenMode: TOpenMode;
+begin
+  // TODO: fix
+  //if ffReadOnSave in FFeatures then
+  //  Result := omReadWrite
+  //else
+    Result := omCreate;
+end;
+
+{ TOptionStack  class implementation }
+
+constructor TOptionStack.Create;
+begin
+  inherited Create;
+  FPosition := -1;
+end;
+
+destructor TOptionStack.Destroy;
+var
+  I: LongInt;
+begin
+  for I := 0 to OptionStackDepth - 1 do
+    SetLength(FStack[I], 0);
+  inherited Destroy;
+end;
+
+function TOptionStack.Pop: Boolean;
+var
+  I: LongInt;
+begin
+  Result := False;
+  if FPosition >= 0  then
+  begin
+    SetLength(Options, Length(FStack[FPosition]));
+    for I := 0 to Length(FStack[FPosition]) - 1 do
+      if Options[I] <> nil then
+        Options[I]^ := FStack[FPosition, I];
+    Dec(FPosition);
+    Result := True;
+  end;
+end;
+
+function TOptionStack.Push: Boolean;
+var
+  I: LongInt;
+begin
+  Result := False;
+  if FPosition < OptionStackDepth - 1 then
+  begin
+    Inc(FPosition);
+    SetLength(FStack[FPosition], Length(Options));
+    for I := 0 to Length(Options) - 1 do
+      if Options[I] <> nil then
+        FStack[FPosition, I] := Options[I]^;
+    Result := True;
+  end;
+end;
+
+{ TMetadata }
+
+procedure TMetadata.SetMetaItem(const Id: string; const Value: Variant;
+  ImageIndex: Integer);
+begin
+  AddMetaToList(FLoadMetaItems, Id, Value, ImageIndex);
+end;
+
+procedure TMetadata.SetMetaItemForSaving(const Id: string; const Value: Variant;
+  ImageIndex: Integer);
+begin
+  AddMetaToList(FSaveMetaItems, Id, Value, ImageIndex);
+end;
+
+procedure TMetadata.AddMetaToList(List: TStringList; const Id: string;
+  const Value: Variant; ImageIndex: Integer);
+var
+  Item: TMetadataItem;
+  Idx: Integer;
+  FullId: string;
+begin
+  FullId := GetMetaItemName(Id, ImageIndex);
+  if List.Find(FullId, Idx) then
+    (List.Objects[Idx] as TMetadataItem).Value := Value
+  else
+  begin
+    Item := TMetadataItem.Create;
+    Item.Id := Id;
+    Item.ImageIndex := ImageIndex;
+    Item.Value := Value;
+    List.AddObject(FullId, Item);
+  end;
+end;
+
+procedure TMetadata.ClearMetaItems;
+begin
+  ClearMetaList(FLoadMetaItems);
+end;
+
+procedure TMetadata.ClearMetaItemsForSaving;
+begin
+  ClearMetaList(FSaveMetaItems);
+end;
+
+procedure TMetadata.ClearMetaList(List: TStringList);
+var
+  I: Integer;
+begin
+  for I := 0 to List.Count - 1 do
+    List.Objects[I].Free;
+  List.Clear;
+end;
+
+procedure TMetadata.CopyLoadedMetaItemsForSaving;
+var
+  I: Integer;
+  Copy, Orig: TMetadataItem;
+begin
+  ClearMetaItemsForSaving;
+  for I := 0 to FLoadMetaItems.Count - 1 do
+  begin
+    Orig := TMetadataItem(FLoadMetaItems.Objects[I]);
+    Copy := TMetadataItem.Create;
+    Copy.Id := Orig.Id;
+    Copy.ImageIndex := Orig.ImageIndex;
+    Copy.Value := Orig.Value;
+    FSaveMetaItems.AddObject(GetMetaItemName(Copy.Id, Copy.ImageIndex), Copy);
+  end;
+end;
+
+constructor TMetadata.Create;
+begin
+  inherited;
+  FLoadMetaItems := TStringList.Create;
+  FLoadMetaItems.Sorted := True;
+  FSaveMetaItems := TStringList.Create;
+  FSaveMetaItems.Sorted := True;
+end;
+
+destructor TMetadata.Destroy;
+begin
+  ClearMetaItems;
+  ClearMetaItemsForSaving;
+  FLoadMetaItems.Free;
+  FSaveMetaItems.Free;
+  inherited;
+end;
+
+function TMetadata.GetMetaById(const Id: string): Variant;
+var
+  Idx: Integer;
+begin
+  if FLoadMetaItems.Find(Id, Idx) then
+    Result := (FLoadMetaItems.Objects[Idx] as TMetadataItem).Value
+  else
+    Result := Variants.Null;
+end;
+
+function TMetadata.GetMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant;
+begin
+  Result := GetMetaById(GetMetaItemName(Id, ImageIndex));
+end;
+
+function TMetadata.GetSaveMetaById(const Id: string): Variant;
+var
+  Idx: Integer;
+begin
+  if FSaveMetaItems.Find(Id, Idx) then
+    Result := (FSaveMetaItems.Objects[Idx] as TMetadataItem).Value
+  else
+    Result := Variants.Null;
+end;
+
+function TMetadata.GetSaveMetaByIdMulti(const Id: string;
+  ImageIndex: Integer): Variant;
+begin
+  Result := GetSaveMetaById(GetMetaItemName(Id, ImageIndex));
+end;
+
+function TMetadata.GetMetaByIdx(Index: Integer): TMetadataItem;
+begin
+  Result := FLoadMetaItems.Objects[Index] as TMetadataItem;
+end;
+
+function TMetadata.GetMetaCount: Integer;
+begin
+  Result := FLoadMetaItems.Count;
+end;
+
+function TMetadata.GetMetaItemName(const Id: string;
+  ImageIndex: Integer): string;
+begin
+  Result := Iff(ImageIndex = 0, Id, Format(SMetaIdForSubImage, [Id, ImageIndex]));
+end;
+
+function TMetadata.GetPhysicalPixelSize(ResUnit: TResolutionUnit; var XSize,
+  YSize: Single; MetaForSave: Boolean; ImageIndex: Integer): Boolean;
+type
+  TGetter = function(const Id: string; ImageIndex: Integer): Variant of object;
+var
+  Getter: TGetter;
+  XMeta, YMeta: Variant;
+begin
+  if MetaForSave then
+    Getter := GetSaveMetaByIdMulti
+  else
+    Getter := GetMetaByIdMulti;
+
+  XMeta := Getter(SMetaPhysicalPixelSizeX, ImageIndex);
+  YMeta := Getter(SMetaPhysicalPixelSizeY, ImageIndex);
+  XSize := -1;
+  YSize := -1;
+
+  Result := not VarIsNull(XMeta) or not VarIsNull(YMeta);
+
+  if not Result then
+    Exit;
+
+  if not VarIsNull(XMeta) then
+    XSize := XMeta;
+  if not VarIsNull(YMeta) then
+    YSize := YMeta;
+
+  if XSize < 0 then
+    XSize := YSize;
+  if YSize < 0 then
+    YSize := XSize;
+
+  TranslateUnits(ResUnit, XSize, YSize);
+end;
+
+procedure TMetadata.SetPhysicalPixelSize(ResUnit: TResolutionUnit; XSize,
+  YSize: Single; MetaForSave: Boolean; ImageIndex: Integer);
+type
+  TAdder = procedure(const Id: string; const Value: Variant; ImageIndex: Integer) of object;
+var
+  Adder: TAdder;
+begin
+  TranslateUnits(ResUnit, XSize, YSize);
+
+  if MetaForSave then
+    Adder := SetMetaItemForSaving
+  else
+    Adder := SetMetaItem;
+
+  Adder(SMetaPhysicalPixelSizeX, XSize, ImageIndex);
+  Adder(SMetaPhysicalPixelSizeY, YSize, ImageIndex);
+end;
+
+procedure TMetadata.TranslateUnits(ResolutionUnit: TResolutionUnit; var XRes,
+  YRes: Single);
+var
+  UnitSize: Single;
+begin
+  case ResolutionUnit of
+    ruDpi: UnitSize := 25400;
+    ruDpm: UnitSize := 1e06;
+    ruDpcm: UnitSize := 1e04;
+  else
+    UnitSize := 1;
+  end;
+  if ResolutionUnit <> ruSizeInMicroMeters then
+  begin
+    XRes := UnitSize / XRes;
+    YRes := UnitSize / YRes;
+  end;
+end;
+
+function TMetadata.HasMetaItem(const Id: string; ImageIndex: Integer): Boolean;
+begin
+  Result := GetMetaByIdMulti(Id, ImageIndex) <> Variants.Null;
+end;
+
+function TMetadata.HasMetaItemForSaving(const Id: string; ImageIndex: Integer): Boolean;
+begin
+  Result := GetSaveMetaByIdMulti(Id, ImageIndex) <> Variants.Null;
+end;
+
+initialization
+{$IFDEF MEMCHECK}
+  {$IF CompilerVersion >= 18}
+    System.ReportMemoryLeaksOnShutdown := True;
+  {$IFEND}
+{$ENDIF}
+  if GlobalMetadata = nil then
+    GlobalMetadata := TMetadata.Create;
+  if ImageFileFormats = nil then
+    ImageFileFormats := TList.Create;
+  InitImageFormats;
+  RegisterOption(ImagingColorReductionMask, @ColorReductionMask);
+  RegisterOption(ImagingLoadOverrideFormat, @LoadOverrideFormat);
+  RegisterOption(ImagingSaveOverrideFormat, @SaveOverrideFormat);
+  RegisterOption(ImagingMipMapFilter, @MipMapFilter);
+  RegisterOption(ImagingBinaryTreshold, @BinaryTreshold);
+finalization
+  FreeOptions;
+  FreeImageFileFormats;
+  GlobalMetadata.Free;
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 ---------------------------------------------------
+    - Updated IO Open functions according to changes in ImagingTypes.
+    - Fixed bug in SplitImage that could cause wrong size of edge chunks.
+    - Metadata support fixes and extensions (frame delays, animation loops).
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Started reworking exception raising to keep the original class type
+      (e.g. in NewImage EOutOfMemory could be raised but was hidden
+      by EImagingError raised afterwards in NewImage try/except).
+    - Fixed possible AV in Rotate45 subproc of RotateImage.
+    - Added ReadRawXXX and WriteRawXXX functions for raw image bits IO.
+    - Implemented ImagingBinaryTreshold option.
+    - Added support for simple image metadata loading/saving.
+    - Moved file format definition (name, exts, caps, ...) from
+      constructor to new Define method.
+    - Fixed some memory leaks caused by failures during image loading.
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Extended RotateImage to allow arbitrary angle rotations.
+    - Reversed the order file formats list is searched so
+      if you register a new one it will be found sooner than
+      built in formats.
+    - Fixed memory leak in ResizeImage ocurring when resizing
+      indexed images.
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - Added position/size checks to LoadFromStream functions.
+    - Changed conditional compilation in impl. uses section to reflect changes
+      in LINK symbols.
+
+  -- 0.24.3 Changes/Bug Fixes ---------------------------------
+    - GenerateMipMaps now generates all smaller levels from
+      original big image (better results when using more advanced filters).
+      Also conversion to compatible image format is now done here not
+      in FillMipMapLevel (that is called for every mipmap level).
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - MakePaletteForImages now works correctly for indexed and special format images
+    - Fixed bug in StretchRect: Image was not properly stretched if
+      src and dst dimensions differed only in height.
+    - ConvertImage now fills new image with zeroes to avoid random data in
+      some conversions (RGB->XRGB)
+    - Changed RegisterOption procedure to function
+    - Changed bunch of palette functions from low level interface to procedure
+      (there was no reason for them to be functions).
+    - Changed FreeImage and FreeImagesInArray functions to procedures.
+    - Added many assertions, come try-finally, other checks, and small code
+      and doc changes.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - GenerateMipMaps threw failed assertion when input was indexed or special,
+      fixed.
+    - Added CheckOptionsValidity to TImageFileFormat and its decendants.
+    - Unit ImagingExtras which registers file formats in Extras package
+      is now automatically added to uses clause if LINK_EXTRAS symbol is
+      defined in ImagingOptions.inc file.
+    - Added EnumFileFormats function to low level interface.
+    - Fixed bug in SwapChannels which could cause AV when swapping alpha
+      channel of A8R8G8B8 images.
+    - Converting loaded images to ImagingOverrideFormat is now done
+      in PostLoadCheck method to avoid code duplicity.
+    - Added GetFileFormatCount and GetFileFormatAtIndex functions
+    - Bug in ConvertImage: if some format was converted to similar format
+      only with swapped channels (R16G16B16<>B16G16R16) then channels were
+      swapped correctly but new data format (swapped one) was not set.
+    - Made TImageFileFormat.MakeCompatible public non-virtual method
+      (and modified its function). Created new virtual
+      ConvertToSupported which should be overriden by descendants.
+      Main reason for doint this is to avoid duplicate code that was in all
+      TImageFileFormat's descendants.
+    - Changed TImageFileFormat.GetFormatInfo's result type to TImageFormatInfo.
+    - Split overloaded FindImageFileFormat functions to
+      FindImageFileFormatByClass and FindImageFileFormatByExt and created new
+      FindImageFileFormatByName which operates on whole filenames.
+    - Function GetExtensionFilterIndex renamed to GetFileNameFilterIndex
+      (because it now works with filenames not extensions).
+    - DetermineFileFormat now first searches by filename and if not found
+      then by data.
+    - Added TestFileName method to TImageFileFormat.
+    - Updated GetImageFileFormatsFilter to uses Masks instead of Extensions
+      property of TImageFileFormat. Also you can now request
+      OpenDialog and SaveDialog type filters
+    - Added Masks property and AddMasks method to TImageFileFormat.
+      AddMasks replaces AddExtensions, it uses filename masks instead
+      of sime filename extensions to identify supported files.
+    - Changed TImageFileFormat.LoadData procedure to function and
+      moved varios duplicate code from its descandats (check index,...)
+      here to TImageFileFormat helper methods.
+    - Changed TImageFileFormat.SaveData procedure to function and
+      moved varios duplicate code from its descandats (check index,...)
+      here to TImageFileFormat helper methods.
+    - Removed RAISE_EXCEPTIONS define, exceptions are now raised everytime
+    - Added MustBeFreed parameter to TImageFileFormat.MakeComptible method
+      that indicates that compatible image returned by this method must be
+      freed after its usage.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - fixed bug in NewImage: if given format was ifDefault it wasn't
+      replaced with DefaultImageFormat constant which caused problems later
+      in other units
+    - fixed bug in RotateImage which caused that rotated special format
+      images were whole black
+    - LoadImageFromXXX and LoadMultiImageFromXXX now use DetermineXXXFormat
+      when choosing proper loader, this eliminated need for Ext parameter
+      in stream and memory loading functions
+    - added GetVersionStr function
+    - fixed bug in ResizeImage which caued indexed images to lose their
+      palette during process resulting in whole black image
+    - Clipping in ...Rect functions now uses clipping procs from ImagingUtility,
+      it also works better
+    - FillRect optimization for 8, 16, and 32 bit formats
+    - added pixel set/get functions to low level interface:
+      GetPixelDirect, SetPixelDirect, GetPixel32, SetPixel32,
+      GetPixelFP, SetPixelFP
+    - removed GetPixelBytes low level intf function - redundant
+      (same data can be obtained by GetImageFormatInfo)
+    - made small changes in many parts of library to compile
+      on AMD64 CPU (Linux with FPC)
+    - changed InitImage to procedure (function was pointless)
+    - Method TestFormat of TImageFileFormat class made public
+      (was protected)
+    - added function IsFileFormatSupported to low level interface
+      (contributed by Paul Michell)
+    - fixed some missing format arguments from error strings
+      which caused Format function to raise exception
+    - removed forgotten debug code that disabled filtered resizing of images with
+      channel bitcounts > 8
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - changed order of parameters of CopyRect function
+    - GenerateMipMaps now filters mipmap levels
+    - ResizeImage functions was extended to allow bilinear and bicubic filtering
+    - added StretchRect function to low level interface
+    - added functions GetImageFileFormatsFilter, GetFilterIndexExtension,
+      and GetExtensionFilterIndex
+
+  -- 0.15 Changes/Bug Fixes -----------------------------------
+    - added function RotateImage to low level interface
+    - moved TImageFormatInfo record and types required by it to
+      ImagingTypes unit, changed GetImageFormatInfo low level
+      interface function to return TImageFormatInfo instead of short info
+    - added checking of options values validity before they are used
+    - fixed possible memory leak in CloneImage
+    - added ReplaceColor function to low level interface
+    - new function FindImageFileFormat by class added
+
+  -- 0.13 Changes/Bug Fixes -----------------------------------
+    - added DetermineFileFormat, DetermineStreamFormat, DetermineMemoryFormat,
+      GetPixelsSize functions to low level interface
+    - added NewPalette, CopyPalette, FreePalette functions
+      to low level interface
+    - added MapImageToPalette, FillRect, SplitImage, MakePaletteForImages
+      functions to low level interface
+    - fixed buggy FillCustomPalette function (possible div by zero and others)
+    - added CopyRect function to low level interface
+    - Member functions of TImageFormatInfo record implemented for all formats
+    - before saving images TestImagesInArray is called now
+    - added TestImagesInArray function to low level interface
+    - added GenerateMipMaps function to low level interface
+    - stream position in load/save from/to stream is now set to position before
+      function was called if error occurs
+    - when error occured during load/save from/to file file handle
+      was not released
+    - CloneImage returned always False
+
+}
+end.
diff --git a/src/lib/vampimg/ImagingBitmap.pas b/src/lib/vampimg/ImagingBitmap.pas
new file mode 100644 (file)
index 0000000..4c4aac6
--- /dev/null
@@ -0,0 +1,855 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{
+  This unit contains image format loader/saver for Windows Bitmap images.
+}
+unit ImagingBitmap;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  ImagingTypes, Imaging, ImagingUtility, ImagingFormats, ImagingIO;
+
+type
+  { Class for loading and saving Windows Bitmap images.
+    It can load/save 8bit indexed, 16, 24, 32 bit RGB or ARGB
+    images with or without RLE compression. It can also load 1/4 bit
+    indexed images and OS2 bitmaps.}
+  TBitmapFileFormat = class(TImageFileFormat)
+  protected
+    FUseRLE: LongBool;
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  published
+    { Controls that RLE compression is used during saving. Accessible trough
+      ImagingBitmapRLE option.}
+    property UseRLE: LongBool read FUseRLE write FUseRLE;
+  end;
+
+implementation
+
+const
+  SBitmapFormatName = 'Windows Bitmap Image';
+  SBitmapMasks =      '*.bmp,*.dib';
+  BitmapSupportedFormats: TImageFormats = [ifIndex8, ifA1R5G5B5, ifA4R4G4B4,
+    ifR5G6B5, ifR8G8B8, ifA8R8G8B8, ifX1R5G5B5, ifX4R4G4B4, ifX8R8G8B8];
+  BitmapDefaultRLE = True;
+
+const
+  { Bitmap file identifier 'BM'.}
+  BMMagic: Word = 19778;
+
+  { Constants for the TBitmapInfoHeader.Compression field.}
+  BI_RGB = 0;
+  BI_RLE8 = 1;
+  BI_RLE4 = 2;
+  BI_BITFIELDS = 3;
+
+  V3InfoHeaderSize = 40;
+  V4InfoHeaderSize = 108;
+
+type
+  { File Header for Windows/OS2 bitmap file.}
+  TBitmapFileHeader = packed record
+    ID: Word;           // Is always 19778 : 'BM'
+    Size: LongWord;     // Filesize
+    Reserved1: Word;
+    Reserved2: Word;
+    Offset: LongWord;   // Offset from start pos to beginning of image bits
+  end;
+
+  { Info Header for Windows bitmap file version 4.}
+  TBitmapInfoHeader = packed record
+    Size: LongWord;
+    Width: LongInt;
+    Height: LongInt;
+    Planes: Word;
+    BitCount: Word;
+    Compression: LongWord;
+    SizeImage: LongWord;
+    XPelsPerMeter: LongInt;
+    YPelsPerMeter: LongInt;
+    ClrUsed: LongInt;
+    ClrImportant: LongInt;
+    RedMask: LongWord;
+    GreenMask: LongWord;
+    BlueMask: LongWord;
+    AlphaMask: LongWord;
+    CSType: LongWord;
+    EndPoints: array[0..8] of LongWord;
+    GammaRed: LongWord;
+    GammaGreen: LongWord;
+    GammaBlue: LongWord;
+  end;
+
+  { Info Header for OS2 bitmaps.}
+  TBitmapCoreHeader = packed record
+    Size: LongWord;
+    Width: Word;
+    Height: Word;
+    Planes: Word;
+    BitCount: Word;
+  end;
+
+  { Used in RLE encoding and decoding.}
+  TRLEOpcode = packed record
+    Count: Byte;
+    Command: Byte;
+  end;
+  PRLEOpcode = ^TRLEOpcode;
+
+{ TBitmapFileFormat class implementation }
+
+procedure TBitmapFileFormat.Define;
+begin
+  inherited;
+  FName := SBitmapFormatName;
+  FFeatures := [ffLoad, ffSave];
+  FSupportedFormats := BitmapSupportedFormats;
+
+  FUseRLE := BitmapDefaultRLE;
+
+  AddMasks(SBitmapMasks);
+  RegisterOption(ImagingBitmapRLE, @FUseRLE);
+end;
+
+function TBitmapFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  BF: TBitmapFileHeader;
+  BI: TBitmapInfoHeader;
+  BC: TBitmapCoreHeader;
+  IsOS2: Boolean;
+  PalRGB: PPalette24;
+  I, FPalSize, AlignedSize, StartPos, HeaderSize, AlignedWidthBytes, WidthBytes: LongInt;
+  Info: TImageFormatInfo;
+  Data: Pointer;
+
+  procedure LoadRGB;
+  var
+    I: LongInt;
+    LineBuffer: PByte;
+  begin
+    with Images[0], GetIO do
+    begin
+      // If BI.Height is < 0 then image data are stored non-flipped
+      // but default in windows is flipped so if Height is positive we must
+      // flip it
+
+      if BI.BitCount < 8 then
+      begin
+        // For 1 and 4 bit images load aligned data, they will be converted to
+        // 8 bit and unaligned later
+        GetMem(Data, AlignedSize);
+
+        if BI.Height < 0 then
+          Read(Handle, Data, AlignedSize)
+        else
+          for I := Height - 1 downto 0 do
+            Read(Handle, @PByteArray(Data)[I * AlignedWidthBytes], AlignedWidthBytes);
+      end
+      else
+      begin
+        // Images with pixels of size >= 1 Byte are read line by line and
+        // copied to image bits without padding bytes
+        GetMem(LineBuffer, AlignedWidthBytes);
+        try
+          if BI.Height < 0 then
+            for I := 0 to Height - 1 do
+            begin
+              Read(Handle, LineBuffer, AlignedWidthBytes);
+              Move(LineBuffer^, PByteArray(Bits)[I * WidthBytes], WidthBytes);
+            end
+          else
+            for I := Height - 1 downto 0 do
+            begin
+              Read(Handle, LineBuffer, AlignedWidthBytes);
+              Move(LineBuffer^, PByteArray(Bits)[I * WidthBytes], WidthBytes);
+            end;
+        finally
+          FreeMemNil(LineBuffer);
+        end;
+      end;
+    end;
+  end;
+
+  procedure LoadRLE4;
+  var
+    RLESrc: PByteArray;
+    Row, Col, WriteRow, I: LongInt;
+    SrcPos: LongWord;
+    DeltaX, DeltaY, Low, High: Byte;
+    Pixels: PByteArray;
+    OpCode: TRLEOpcode;
+    NegHeightBitmap: Boolean;
+  begin
+    GetMem(RLESrc, BI.SizeImage);
+    GetIO.Read(Handle, RLESrc, BI.SizeImage);
+    with Images[0] do
+    try
+      Low := 0;
+      Pixels := Bits;
+      SrcPos := 0;
+      NegHeightBitmap := BI.Height < 0;
+      Row := 0; // Current row in dest image
+      Col := 0; // Current column in dest image
+      // Row in dest image where actuall writting will be done
+      WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row);
+      while (Row < Height) and (SrcPos < BI.SizeImage) do
+      begin
+        // Read RLE op-code
+        OpCode := PRLEOpcode(@RLESrc[SrcPos])^;
+        Inc(SrcPos, SizeOf(OpCode));
+        if OpCode.Count = 0 then
+        begin
+          // A byte Count of zero means that this is a special
+          // instruction.
+          case OpCode.Command of
+            0:
+              begin
+                // Move to next row
+                Inc(Row);
+                WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row);
+                Col := 0;
+              end ;
+            1: Break; // Image is finished
+            2:
+              begin
+                // Move to a new relative position
+                DeltaX := RLESrc[SrcPos];
+                DeltaY := RLESrc[SrcPos + 1];
+                Inc(SrcPos, 2);
+                Inc(Col, DeltaX);
+                Inc(Row, DeltaY);
+              end
+          else
+            // Do not read data after EOF
+            if SrcPos + OpCode.Command > BI.SizeImage then
+              OpCode.Command := BI.SizeImage - SrcPos;
+            // Take padding bytes and nibbles into account
+            if Col + OpCode.Command > Width then
+              OpCode.Command := Width - Col;
+            // Store absolute data. Command code is the
+            // number of absolute bytes to store
+            for I := 0 to OpCode.Command - 1 do
+            begin
+              if (I and 1) = 0 then
+              begin
+                High := RLESrc[SrcPos] shr 4;
+                Low := RLESrc[SrcPos] and $F;
+                Pixels[WriteRow * Width + Col] := High;
+                Inc(SrcPos);
+              end
+              else
+                Pixels[WriteRow * Width + Col] := Low;
+              Inc(Col);
+            end;
+            // Odd number of bytes is followed by a pad byte
+            if (OpCode.Command mod 4) in [1, 2] then
+              Inc(SrcPos);
+          end;
+        end
+        else
+        begin
+          // Take padding bytes and nibbles into account
+          if Col + OpCode.Count > Width then
+            OpCode.Count := Width - Col;
+          // Store a run of the same color value
+          for I := 0 to OpCode.Count - 1 do
+          begin
+            if (I and 1) = 0 then
+              Pixels[WriteRow * Width + Col] := OpCode.Command shr 4
+            else
+              Pixels[WriteRow * Width + Col] := OpCode.Command and $F;
+            Inc(Col);
+          end;
+        end;
+      end;
+    finally
+      FreeMem(RLESrc);
+    end;
+  end;
+
+  procedure LoadRLE8;
+  var
+    RLESrc: PByteArray;
+    SrcCount, Row, Col, WriteRow: LongInt;
+    SrcPos: LongWord;
+    DeltaX, DeltaY: Byte;
+    Pixels: PByteArray;
+    OpCode: TRLEOpcode;
+    NegHeightBitmap: Boolean;
+  begin
+    GetMem(RLESrc, BI.SizeImage);
+    GetIO.Read(Handle, RLESrc, BI.SizeImage);
+    with Images[0] do
+    try
+      Pixels := Bits;
+      SrcPos := 0;
+      NegHeightBitmap := BI.Height < 0;
+      Row := 0; // Current row in dest image
+      Col := 0; // Current column in dest image
+      // Row in dest image where actuall writting will be done
+      WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row);
+      while (Row < Height) and (SrcPos < BI.SizeImage) do
+      begin
+        // Read RLE op-code
+        OpCode := PRLEOpcode(@RLESrc[SrcPos])^;
+        Inc(SrcPos, SizeOf(OpCode));
+        if OpCode.Count = 0 then
+        begin
+          // A byte Count of zero means that this is a special
+          // instruction.
+          case OpCode.Command of
+            0:
+              begin
+                // Move to next row
+                Inc(Row);
+                WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row);
+                Col := 0;
+              end ;
+            1: Break; // Image is finished
+            2:
+              begin
+                // Move to a new relative position
+                DeltaX := RLESrc[SrcPos];
+                DeltaY := RLESrc[SrcPos + 1];
+                Inc(SrcPos, 2);
+                Inc(Col, DeltaX);
+                Inc(Row, DeltaY);
+              end
+          else
+            SrcCount := OpCode.Command;
+            // Do not read data after EOF
+            if SrcPos + OpCode.Command > BI.SizeImage then
+              OpCode.Command := BI.SizeImage - SrcPos;
+            // Take padding bytes into account
+            if Col + OpCode.Command > Width then
+              OpCode.Command := Width - Col;
+            // Store absolute data. Command code is the
+            // number of absolute bytes to store
+            Move(RLESrc[SrcPos], Pixels[WriteRow * Width + Col], OpCode.Command);
+            Inc(SrcPos, SrcCount);
+            Inc(Col, OpCode.Command);
+            // Odd number of bytes is followed by a pad byte
+            if (SrcCount mod 2) = 1 then
+              Inc(SrcPos);
+          end;
+        end
+        else
+        begin
+          // Take padding bytes into account
+          if Col + OpCode.Count > Width then
+            OpCode.Count := Width - Col;
+          // Store a run of the same color value. Count is number of bytes to store
+          FillChar(Pixels [WriteRow * Width + Col], OpCode.Count, OpCode.Command);
+          Inc(Col, OpCode.Count);
+        end;
+      end;
+    finally
+      FreeMem(RLESrc);
+    end;
+  end;
+
+begin
+  Data := nil;
+  SetLength(Images, 1);
+  with GetIO, Images[0] do
+  try
+    FillChar(BI, SizeOf(BI), 0);
+    StartPos := Tell(Handle);
+    Read(Handle, @BF, SizeOf(BF));
+    Read(Handle, @BI.Size, SizeOf(BI.Size));
+    IsOS2 := BI.Size = SizeOf(TBitmapCoreHeader);
+
+    // Bitmap Info reading
+    if IsOS2 then
+    begin
+      // OS/2 type bitmap, reads info header without 4 already read bytes
+      Read(Handle, @PByteArray(@BC)[SizeOf(BI.Size)],
+        SizeOf(TBitmapCoreHeader) - SizeOf(BI.Size));
+      with BI do
+      begin
+        ClrUsed := 0;
+        Compression := BI_RGB;
+        BitCount := BC.BitCount;
+        Height := BC.Height;
+        Width := BC.Width;
+      end;
+    end
+    else
+    begin
+      // Windows type bitmap
+      HeaderSize := Min(BI.Size - SizeOf(BI.Size), SizeOf(BI) - SizeOf(BI.Size)); // do not read more than size of BI!
+      Read(Handle, @PByteArray(@BI)[SizeOf(BI.Size)], HeaderSize);
+      // SizeImage can be 0 for BI_RGB images, but it is here because of:
+      // I saved 8bit bitmap in Paint Shop Pro 8 as OS2 RLE compressed.
+      // It wrote strange 64 Byte Info header with SizeImage set to 0
+      // Some progs were able to open it, some were not.
+      if BI.SizeImage = 0 then
+        BI.SizeImage := BF.Size - BF.Offset;
+    end;
+    // Bit mask reading. Only read it if there is V3 header, V4 header has
+    // masks laoded already (only masks for RGB in V3).
+    if (BI.Compression = BI_BITFIELDS) and (BI.Size = V3InfoHeaderSize) then
+      Read(Handle, @BI.RedMask, SizeOf(BI.RedMask) * 3);
+
+    case BI.BitCount of
+      1, 4, 8: Format := ifIndex8;
+      16:
+        if BI.RedMask = $0F00 then
+          // Set XRGB4 or ARGB4 according to value of alpha mask
+          Format := IffFormat(BI.AlphaMask = 0, ifX4R4G4B4, ifA4R4G4B4)
+        else if BI.RedMask = $F800 then
+          Format := ifR5G6B5
+        else
+          // R5G5B5 is default 16bit format (with Compression = BI_RGB or masks).
+          // We set it to A1.. and later there is a check if there are any alpha values
+          // and if not it is changed to X1R5G5B5
+          Format := ifA1R5G5B5;
+      24: Format := ifR8G8B8;
+      32: Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later
+    end;
+
+    NewImage(BI.Width, Abs(BI.Height), Format, Images[0]);
+    Info := GetFormatInfo(Format);
+    WidthBytes := Width * Info.BytesPerPixel;
+    AlignedWidthBytes := (((Width * BI.BitCount) + 31) shr 5) * 4;
+    AlignedSize := Height * LongInt(AlignedWidthBytes);
+
+    // Palette settings and reading
+    if BI.BitCount <= 8 then
+    begin
+      // Seek to the begining of palette
+      Seek(Handle, StartPos + SizeOf(TBitmapFileHeader) + LongInt(BI.Size),
+        smFromBeginning);
+      if IsOS2 then
+      begin
+        // OS/2 type
+        FPalSize := 1 shl BI.BitCount;
+        GetMem(PalRGB, FPalSize * SizeOf(TColor24Rec));
+        try
+          Read(Handle, PalRGB, FPalSize * SizeOf(TColor24Rec));
+          for I := 0 to FPalSize - 1 do
+          with PalRGB[I] do
+          begin
+            Palette[I].R := R;
+            Palette[I].G := G;
+            Palette[I].B := B;
+          end;
+        finally
+          FreeMemNil(PalRGB);
+        end;
+      end
+      else
+      begin
+        // Windows type
+        FPalSize := BI.ClrUsed;
+        if FPalSize = 0 then
+          FPalSize := 1 shl BI.BitCount;
+        Read(Handle, Palette, FPalSize * SizeOf(TColor32Rec));
+      end;
+      for I := 0 to Info.PaletteEntries - 1 do
+        Palette[I].A := $FF;
+    end;
+
+    // Seek to the beginning of image bits
+    Seek(Handle, StartPos + LongInt(BF.Offset), smFromBeginning);
+
+    case BI.Compression of
+      BI_RGB: LoadRGB;
+      BI_RLE4: LoadRLE4;
+      BI_RLE8: LoadRLE8;
+      BI_BITFIELDS: LoadRGB;
+    end;
+
+    if BI.AlphaMask = 0 then
+    begin
+      // Alpha mask is not stored in file (V3) or not defined.
+      // Check alpha channels of loaded images if they might contain them.
+      if Format = ifA1R5G5B5 then
+      begin
+        // Check if there is alpha channel present in A1R5GB5 images, if it is not
+        // change format to X1R5G5B5
+        if not Has16BitImageAlpha(Width * Height, Bits) then
+          Format := ifX1R5G5B5;
+      end
+      else if Format = ifA8R8G8B8 then
+      begin
+        // Check if there is alpha channel present in A8R8G8B8 images, if it is not
+        // change format to X8R8G8B8
+        if not Has32BitImageAlpha(Width * Height, Bits) then
+          Format := ifX8R8G8B8;
+      end;
+    end;
+
+    if BI.BitCount < 8 then
+    begin
+      // 1 and 4 bpp images are supported only for loading which is now
+      // so we now convert them to 8bpp (and unalign scanlines).
+      case BI.BitCount of
+        1: Convert1To8(Data, Bits, Width, Height, AlignedWidthBytes, False);
+        4:
+          begin
+            // RLE4 bitmaps are translated to 8bit during RLE decoding
+            if BI.Compression <> BI_RLE4 then
+               Convert4To8(Data, Bits, Width, Height, AlignedWidthBytes, False);
+          end;
+      end;
+      // Enlarge palette
+      ReallocMem(Palette, Info.PaletteEntries * SizeOf(TColor32Rec));
+    end;
+
+    Result := True;
+  finally
+    FreeMemNil(Data);
+  end;
+end;
+
+function TBitmapFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+var
+  StartPos, EndPos, I, Pad, PadSize, WidthBytes: LongInt;
+  BF: TBitmapFileHeader;
+  BI: TBitmapInfoHeader;
+  Info: TImageFormatInfo;
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+
+  procedure SaveRLE8;
+  const
+    BufferSize = 8 * 1024;
+  var
+    X, Y, I, SrcPos: LongInt;
+    DiffCount, SameCount: Byte;
+    Pixels: PByteArray;
+    Buffer: array[0..BufferSize - 1] of Byte;
+    BufferPos: LongInt;
+
+    procedure WriteByte(ByteToWrite: Byte);
+    begin
+      if BufferPos = BufferSize then
+      begin
+        // Flush buffer if necessary
+        GetIO.Write(Handle, @Buffer, BufferPos);
+        BufferPos := 0;
+      end;
+      Buffer[BufferPos] := ByteToWrite;
+      Inc(BufferPos);
+    end;
+
+  begin
+    BufferPos := 0;
+    with GetIO, ImageToSave do
+    begin
+      for Y := Height - 1 downto 0 do
+      begin
+        X := 0;
+        SrcPos := 0;
+        Pixels := @PByteArray(Bits)[Y * Width];
+
+        while X < Width do
+        begin
+          SameCount := 1;
+          DiffCount := 0;
+          // Determine run length
+          while X + SameCount < Width do
+          begin
+            // If we reach max run length or byte with different value
+            // we end this run
+            if (SameCount = 255) or (Pixels[SrcPos + SameCount] <> Pixels[SrcPos]) then
+              Break;
+            Inc(SameCount);
+          end;
+
+          if SameCount = 1 then
+          begin
+            // If there are not some bytes with the same value we
+            // compute how many different bytes are there
+            while X + DiffCount < Width do
+            begin
+              // Stop diff byte counting if there two bytes with the same value
+              // or DiffCount is too big
+              if (DiffCount = 255) or (Pixels[SrcPos + DiffCount + 1] =
+                Pixels[SrcPos + DiffCount]) then
+                Break;
+              Inc(DiffCount);
+            end;
+          end;
+
+          // Now store absolute data (direct copy image->file) or
+          // store RLE code only (number of repeats + byte to be repeated)
+          if DiffCount > 2 then
+          begin
+            // Save 'Absolute Data' (0 + number of bytes) but only
+            // if number is >2 because (0+1) and (0+2) are other special commands
+            WriteByte(0);
+            WriteByte(DiffCount);
+            // Write absolute data to buffer
+            for I := 0 to DiffCount - 1 do
+              WriteByte(Pixels[SrcPos + I]);
+            Inc(X, DiffCount);
+            Inc(SrcPos, DiffCount);
+            // Odd number of bytes must be padded
+            if (DiffCount mod 2) = 1 then
+              WriteByte(0);
+          end
+          else
+          begin
+            // Save number of repeats and byte that should be repeated
+            WriteByte(SameCount);
+            WriteByte(Pixels[SrcPos]);
+            Inc(X, SameCount);
+            Inc(SrcPos, SameCount);
+          end;
+        end;
+        // Save 'End Of Line' command
+        WriteByte(0);
+        WriteByte(0);
+      end;
+      // Save 'End Of Bitmap' command
+      WriteByte(0);
+      WriteByte(1);
+      // Flush buffer
+      GetIO.Write(Handle, @Buffer, BufferPos);
+    end;
+  end;
+
+begin
+  Result := False;
+  if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
+  with GetIO, ImageToSave do
+  try
+    Info := GetFormatInfo(Format);
+    StartPos := Tell(Handle);
+    FillChar(BF, SizeOf(BF), 0);
+    FillChar(BI, SizeOf(BI), 0);
+    // Other fields will be filled later - we don't know all values now
+    BF.ID := BMMagic;
+    Write(Handle, @BF, SizeOf(BF));
+    if Info.HasAlphaChannel and (Info.BytesPerPixel = 2){V4 temp hack} then
+      // Save images with alpha in V4 format
+      BI.Size := V4InfoHeaderSize
+    else
+      // Save images without alpha in V3 format - for better compatibility
+      BI.Size := V3InfoHeaderSize;
+    BI.Width := Width;
+    BI.Height := Height;
+    BI.Planes := 1;
+    BI.BitCount := Info.BytesPerPixel * 8;
+    BI.XPelsPerMeter := 2835; // 72 dpi
+    BI.YPelsPerMeter := 2835; // 72 dpi
+    // Set compression
+    if (Info.BytesPerPixel = 1) and FUseRLE then
+      BI.Compression := BI_RLE8
+    else if (Info.HasAlphaChannel or
+      ((BI.BitCount = 16) and (Format <> ifX1R5G5B5))) and (Info.BytesPerPixel = 2){V4 temp hack} then
+      BI.Compression := BI_BITFIELDS
+    else
+      BI.Compression := BI_RGB;
+    // Write header (first time)
+    Write(Handle, @BI, BI.Size);
+
+    // Write mask info
+    if BI.Compression = BI_BITFIELDS then
+    begin
+      if BI.BitCount = 16 then
+      with Info.PixelFormat^ do
+      begin
+        BI.RedMask   := RBitMask;
+        BI.GreenMask := GBitMask;
+        BI.BlueMask  := BBitMask;
+        BI.AlphaMask := ABitMask;
+      end
+      else
+      begin
+        // Set masks for A8R8G8B8
+        BI.RedMask   := $00FF0000;
+        BI.GreenMask := $0000FF00;
+        BI.BlueMask  := $000000FF;
+        BI.AlphaMask := $FF000000;
+      end;
+      // If V3 header is used RGB masks must be written to file separately.
+      // V4 header has embedded masks (V4 is default for formats with alpha).
+      if BI.Size = V3InfoHeaderSize then
+        Write(Handle, @BI.RedMask, SizeOf(BI.RedMask) * 3);
+    end;
+    // Write palette
+    if Palette <> nil then
+      Write(Handle, Palette, Info.PaletteEntries * SizeOf(TColor32Rec));
+
+    BF.Offset := Tell(Handle) - StartPos;
+
+    if BI.Compression <> BI_RLE8 then
+    begin
+      // Save uncompressed data, scanlines must be filled with pad bytes
+      // to be multiples of 4, save as bottom-up (Windows native) bitmap
+      Pad := 0;
+      WidthBytes := Width * Info.BytesPerPixel;
+      PadSize := ((Width * BI.BitCount + 31) div 32) * 4 - WidthBytes;
+
+      for I := Height - 1 downto 0 do
+      begin
+        Write(Handle, @PByteArray(Bits)[I * WidthBytes], WidthBytes);
+        if PadSize > 0 then
+          Write(Handle, @Pad, PadSize);
+      end;
+    end
+    else
+    begin
+      // Save data with RLE8 compression
+      SaveRLE8;
+    end;
+
+    EndPos := Tell(Handle);
+    Seek(Handle, StartPos, smFromBeginning);
+    // Rewrite header with new values
+    BF.Size := EndPos - StartPos;
+    BI.SizeImage := BF.Size - BF.Offset;
+    Write(Handle, @BF, SizeOf(BF));
+    Write(Handle, @BI, BI.Size);
+    Seek(Handle, EndPos, smFromBeginning);
+
+    Result := True;
+  finally
+    if MustBeFreed then
+      FreeImage(ImageToSave);
+  end;
+end;
+
+procedure TBitmapFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if Info.IsFloatingPoint then
+    // Convert FP image to RGB/ARGB according to presence of alpha channel
+    ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8)
+  else if Info.HasGrayChannel or Info.IsIndexed then
+    // Convert all grayscale and indexed images to Index8 unless they have alpha
+    // (preserve it)
+    ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifIndex8)
+  else if Info.HasAlphaChannel then
+    // Convert images with alpha channel to A8R8G8B8
+    ConvFormat := ifA8R8G8B8
+  else if Info.UsePixelFormat then
+    // Convert 16bit RGB images (no alpha) to X1R5G5B5
+    ConvFormat := ifX1R5G5B5
+  else
+    // Convert all other formats to R8G8B8
+    ConvFormat := ifR8G8B8;
+
+  ConvertImage(Image, ConvFormat);
+end;
+
+function TBitmapFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Hdr: TBitmapFileHeader;
+  ReadCount: LongInt;
+begin
+  Result := False;
+  if Handle <> nil then
+  with GetIO do
+  begin
+    ReadCount := Read(Handle, @Hdr, SizeOf(Hdr));
+    Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (Hdr.ID = BMMagic) and (ReadCount = SizeOf(Hdr));
+  end;
+end;
+
+initialization
+  RegisterImageFileFormat(TBitmapFileFormat);
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+    - Add option to choose to save V3 or V4 headers.
+
+  -- 0.25.0 Changes/Bug Fixes ---------------------------------
+    - Fixed problem with indexed BMP loading - some pal entries
+      could end up with alpha=0.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Now saves bitmaps as bottom-up for better compatibility
+      (mainly Lazarus' TImage!).
+    - Fixed crash when loading bitmaps with headers larger than V4.
+    - Temp hacks to disable V4 headers for 32bit images (compatibility with
+      other soft).
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Removed temporary data allocation for image with aligned scanlines.
+      They are now directly written to output so memory requirements are
+      much lower now.
+    - Now uses and recognizes BITMAPINFOHEADERV4 when loading/saving.
+      Mainly for formats with alpha channels.
+    - Added ifR5G6B5 to supported formats, changed converting to supported
+      formats little bit.
+    - Rewritten SaveRLE8 nested procedure. Old code was long and
+      mysterious - new is short and much more readable.
+    - MakeCompatible method moved to base class, put ConvertToSupported here.
+      GetSupportedFormats removed, it is now set in constructor.
+    - Rewritten LoadRLE4 and LoadRLE8 nested procedures.
+      Should be less buggy an more readable (load inspired by Colosseum Builders' code).
+    - Made public properties for options registered to SetOption/GetOption
+      functions.
+    - Addded alpha check to 32b bitmap loading too (teh same as in 16b
+      bitmap loading).
+    - Moved Convert1To8 and Convert4To8 to ImagingFormats
+    - Changed extensions to filename masks.
+    - Changed SaveData, LoadData, and MakeCompatible methods according
+      to changes in base class in Imaging unit.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - fixed wrong const that caused A4R4G4B4 BMPs to load as A1R5G5B5
+    - fixed the bug that caused 8bit RLE compressed bitmaps to load as
+      whole black
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - 16 bit images are usually without alpha but some has alpha
+      channel and there is no indication of it - so I have added
+      a check: if all pixels of image are with alpha = 0 image is treated
+      as X1R5G5B5 otherwise as A1R5G5B5
+
+  -- 0.13 Changes/Bug Fixes -----------------------------------
+    - when loading 1/4 bit images with dword aligned dimensions
+      there was ugly memory rewritting bug causing image corruption
+
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingCanvases.pas b/src/lib/vampimg/ImagingCanvases.pas
new file mode 100644 (file)
index 0000000..448191c
--- /dev/null
@@ -0,0 +1,2110 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains canvas classes for drawing and applying effects.}
+unit ImagingCanvases;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, Types, Classes, ImagingTypes, Imaging, ImagingClasses,
+  ImagingFormats, ImagingUtility;
+
+const
+  { Color constants in ifA8R8G8B8 format.}
+  pcClear   = $00000000;
+  pcBlack   = $FF000000;
+  pcWhite   = $FFFFFFFF;
+  pcMaroon  = $FF800000;
+  pcGreen   = $FF008000;
+  pcOlive   = $FF808000;
+  pcNavy    = $FF000080;
+  pcPurple  = $FF800080;
+  pcTeal    = $FF008080;
+  pcGray    = $FF808080;
+  pcSilver  = $FFC0C0C0;
+  pcRed     = $FFFF0000;
+  pcLime    = $FF00FF00;
+  pcYellow  = $FFFFFF00;
+  pcBlue    = $FF0000FF;
+  pcFuchsia = $FFFF00FF;
+  pcAqua    = $FF00FFFF;
+  pcLtGray  = $FFC0C0C0;
+  pcDkGray  = $FF808080;
+
+  MaxPenWidth = 256;
+
+type
+  EImagingCanvasError = class(EImagingError);
+  EImagingCanvasBlendingError = class(EImagingError);
+
+  { Fill mode used when drawing filled objects on canvas.}
+  TFillMode = (
+    fmSolid,  // Solid fill using current fill color
+    fmClear   // No filling done
+  );
+
+  { Pen mode used when drawing lines, object outlines, and similar on canvas.}
+  TPenMode = (
+    pmSolid,  // Draws solid lines using current pen color.
+    pmClear   // No drawing done
+  );
+
+  { Source and destination blending factors for drawing functions with blending.
+    Blending formula: SrcColor * SrcFactor + DestColor * DestFactor }
+  TBlendingFactor = (
+    bfIgnore,           // Don't care
+    bfZero,             // For Src and Dest, Factor = (0, 0, 0, 0)
+    bfOne,              // For Src and Dest, Factor = (1, 1, 1, 1)
+    bfSrcAlpha,         // For Src and Dest, Factor = (Src.A, Src.A, Src.A, Src.A)
+    bfOneMinusSrcAlpha, // For Src and Dest, Factor = (1 - Src.A, 1 - Src.A, 1 - Src.A, 1 - Src.A)
+    bfDstAlpha,         // For Src and Dest, Factor = (Dest.A, Dest.A, Dest.A, Dest.A)
+    bfOneMinusDstAlpha, // For Src and Dest, Factor = (1 - Dest.A, 1 - Dest.A, 1 - Dest.A, 1 - Dest.A)
+    bfSrcColor,         // For Dest,         Factor = (Src.R, Src.R, Src.B, Src.A)
+    bfOneMinusSrcColor, // For Dest,         Factor = (1 - Src.R, 1 - Src.G, 1 - Src.B, 1 - Src.A)
+    bfDstColor,         // For Src,          Factor = (Dest.R, Dest.G, Dest.B, Dest.A)
+    bfOneMinusDstColor  // For Src,          Factor = (1 - Dest.R, 1 - Dest.G, 1 - Dest.B, 1 - Dest.A)
+  );
+
+  { Procedure for custom pixel write modes with blending.}
+  TPixelWriteProc = procedure(const SrcPix: TColorFPRec; DestPtr: PByte;
+    DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
+
+  { Represents 3x3 convolution filter kernel.}
+  TConvolutionFilter3x3 = record
+    Kernel: array[0..2, 0..2] of LongInt;
+    Divisor: LongInt;
+    Bias: Single;
+  end;
+
+  { Represents 5x5 convolution filter kernel.}
+  TConvolutionFilter5x5 = record
+    Kernel: array[0..4, 0..4] of LongInt;
+    Divisor: LongInt;
+    Bias: Single;
+  end;
+
+  TPointTransformFunction = function(const Pixel: TColorFPRec;
+    Param1, Param2, Param3: Single): TColorFPRec;
+
+  TDynFPPixelArray = array of TColorFPRec;
+
+  THistogramArray = array[Byte] of Integer;
+
+  TSelectPixelFunction = function(var Pixels: TDynFPPixelArray): TColorFPRec;
+
+  { Base canvas class for drawing objects, applying effects, and other.
+    Constructor takes TBaseImage (or pointer to TImageData). Source image
+    bits are not copied but referenced so all canvas functions affect
+    source image and vice versa. When you change format or resolution of
+    source image you must call UpdateCanvasState method (so canvas could
+    recompute some data size related stuff).
+
+    TImagingCanvas works for all image data formats except special ones
+    (compressed). Because of this its methods are quite slow (they usually work
+    with colors in ifA32R32G32B32F format). If you want fast drawing you
+    can use one of fast canvas clases. These descendants of TImagingCanvas
+    work only for few select formats (or only one) but they are optimized thus
+    much faster.
+  }
+  TImagingCanvas = class(TObject)
+  private
+    FDataSizeOnUpdate: LongInt;
+    FLineRecursion: Boolean;
+    function GetPixel32(X, Y: LongInt): TColor32; virtual;
+    function GetPixelFP(X, Y: LongInt): TColorFPRec; virtual;
+    function GetValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetPixel32(X, Y: LongInt; const Value: TColor32); virtual;
+    procedure SetPixelFP(X, Y: LongInt; const Value: TColorFPRec); virtual;
+    procedure SetPenColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetPenColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetPenWidth(const Value: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetFillColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetFillColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetClipRect(const Value: TRect);
+    procedure CheckBeforeBlending(SrcFactor, DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas);
+  protected
+    FPData: PImageData;
+    FClipRect: TRect;
+    FPenColorFP: TColorFPRec;
+    FPenColor32: TColor32;
+    FPenMode: TPenMode;
+    FPenWidth: LongInt;
+    FFillColorFP: TColorFPRec;
+    FFillColor32: TColor32;
+    FFillMode: TFillMode;
+    FNativeColor: TColorFPRec;
+    FFormatInfo: TImageFormatInfo;
+
+    { Returns pointer to pixel at given position.}
+    function GetPixelPointer(X, Y: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    { Translates given FP color to native format of canvas and stores it
+      in FNativeColor field (its bit copy) or user pointer (in overloaded method).}
+    procedure TranslateFPToNative(const Color: TColorFPRec); overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure TranslateFPToNative(const Color: TColorFPRec; Native: Pointer); overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    { Clipping function used by horizontal and vertical line drawing functions.}
+    function ClipAxisParallelLine(var A1, A2, B: LongInt;
+      AStart, AStop, BStart, BStop: LongInt): Boolean;
+    { Internal horizontal line drawer used mainly for filling inside of objects
+      like ellipses and circles.}
+    procedure HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer; Bpp: LongInt); virtual;
+    procedure CopyPixelInternal(X, Y: LongInt; Pixel: Pointer; Bpp: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure DrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+      DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc);
+    procedure StretchDrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+      const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor;
+      Filter: TResizeFilter; PixelWriteProc: TPixelWriteProc);
+  public
+    constructor CreateForData(ImageDataPointer: PImageData);
+    constructor CreateForImage(Image: TBaseImage);
+    destructor Destroy; override;
+
+    { Call this method when you change size or format of image this canvas
+      operates on (like calling ResizeImage, ConvertImage, or changing Format
+      property of TBaseImage descendants).}
+    procedure UpdateCanvasState; virtual;
+    { Resets clipping rectangle to Rect(0, 0, ImageWidth, ImageHeight).}
+    procedure ResetClipRect;
+
+    { Clears entire canvas with current fill color (ignores clipping rectangle
+      and always uses fmSolid fill mode).}
+    procedure Clear;
+
+    { Draws horizontal line with current pen settings.}
+    procedure HorzLine(X1, X2, Y: LongInt); virtual;
+    { Draws vertical line with current pen settings.}
+    procedure VertLine(X, Y1, Y2: LongInt); virtual;
+    { Draws line from [X1, Y1] to [X2, Y2] with current pen settings.}
+    procedure Line(X1, Y1, X2, Y2: LongInt); virtual;
+    { Draws a rectangle using current pen settings.}
+    procedure FrameRect(const Rect: TRect);
+    { Fills given rectangle with current fill settings.}
+    procedure FillRect(const Rect: TRect); virtual;
+    { Fills given rectangle with current fill settings and pixel blending.}
+    procedure FillRectBlend(const Rect: TRect; SrcFactor, DestFactor: TBlendingFactor);
+    { Draws rectangle which is outlined by using the current pen settings and
+      filled by using the current fill settings.}
+    procedure Rectangle(const Rect: TRect);
+    { Draws ellipse which is outlined by using the current pen settings and
+      filled by using the current fill settings. Rect specifies bounding rectangle
+      of ellipse to be drawn.}
+    procedure Ellipse(const Rect: TRect);
+    { Fills area of canvas with current fill color starting at point [X, Y] and
+      coloring its neighbors. Default flood fill mode changes color of all
+      neighbors with the same color as pixel [X, Y]. With BoundaryFillMode
+      set to True neighbors are recolored regardless of their old color,
+      but area which will be recolored has boundary (specified by current pen color).}
+    procedure FloodFill(X, Y: Integer; BoundaryFillMode: Boolean = False);
+
+    { Draws contents of this canvas onto another canvas with pixel blending.
+      Blending factors are chosen using TBlendingFactor parameters.
+      Resulting destination pixel color is:
+        SrcColor * SrcFactor +  DstColor * DstFactor}
+    procedure DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+      DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor);
+    { Draws contents of this canvas onto another one with typical alpha
+      blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)}
+    procedure DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); virtual;
+    { Draws contents of this canvas onto another one using additive blending
+      (source and dest factors are bfOne).}
+    procedure DrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer);
+    { Draws stretched and filtered contents of this canvas onto another canvas
+      with pixel blending. Blending factors are chosen using TBlendingFactor parameters.
+      Resulting destination pixel color is:
+        SrcColor * SrcFactor +  DstColor * DstFactor}
+    procedure StretchDrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+      const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor;
+      Filter: TResizeFilter = rfBilinear);
+    { Draws contents of this canvas onto another one with typical alpha
+      blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)}
+    procedure StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+      const DestRect: TRect; Filter: TResizeFilter = rfBilinear); virtual;
+    { Draws contents of this canvas onto another one using additive blending
+      (source and dest factors are bfOne).}
+    procedure StretchDrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+      const DestRect: TRect; Filter: TResizeFilter = rfBilinear);
+
+    { Convolves canvas' image with given 3x3 filter kernel. You can use
+      predefined filter kernels or define your own.}
+    procedure ApplyConvolution3x3(const Filter: TConvolutionFilter3x3);
+    { Convolves canvas' image with given 5x5 filter kernel. You can use
+      predefined filter kernels or define your own.}
+    procedure ApplyConvolution5x5(const Filter: TConvolutionFilter5x5);
+    { Computes 2D convolution of canvas' image and given filter kernel.
+      Kernel is in row format and KernelSize must be odd number >= 3. Divisor
+      is normalizing value based on Kernel (usually sum of all kernel's cells).
+      The Bias number shifts each color value by a fixed amount (color values
+      are usually in range [0, 1] during processing). If ClampChannels
+      is True all output color values are clamped to [0, 1]. You can use
+      predefined filter kernels or define your own.}
+    procedure ApplyConvolution(Kernel: PLongInt; KernelSize, Divisor: LongInt;
+      Bias: Single = 0.0; ClampChannels: Boolean = True); virtual;
+
+    { Applies custom non-linear filter. Filter size is diameter of pixel
+      neighborhood. Typical values are 3, 5, or 7. }
+    procedure ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction);
+    { Applies median non-linear filter with user defined pixel neighborhood.
+      Selects median pixel from the neighborhood as new pixel
+      (current implementation is quite slow).}
+    procedure ApplyMedianFilter(FilterSize: Integer);
+    { Applies min non-linear filter with user defined pixel neighborhood.
+      Selects min pixel from the neighborhood as new pixel.}
+    procedure ApplyMinFilter(FilterSize: Integer);
+    { Applies max non-linear filter with user defined pixel neighborhood.
+      Selects max pixel from the neighborhood as new pixel.}
+    procedure ApplyMaxFilter(FilterSize: Integer);
+
+    { Transforms pixels one by one by given function. Pixel neighbors are
+      not taken into account. Param 1-3 are optional parameters
+      for transform function.}
+    procedure PointTransform(Transform: TPointTransformFunction;
+      Param1, Param2, Param3: Single);
+    { Modifies image contrast and brightness. Parameters should be
+      in range <-100; 100>.}
+    procedure ModifyContrastBrightness(Contrast, Brightness: Single);
+    { Gamma correction of individual color channels. Range is (0, +inf),
+      1.0 means no change.}
+    procedure GammaCorection(Red, Green, Blue: Single);
+    { Inverts colors of all image pixels, makes negative image. Ignores alpha channel.}
+    procedure InvertColors; virtual;
+    { Simple single level thresholding with threshold level (in range [0, 1])
+      for each color channel.}
+    procedure Threshold(Red, Green, Blue: Single);
+    { Adjusts the color levels of the image by scaling the
+      colors falling between specified white and black points to full [0, 1] range.
+      The black point specifies the darkest color in the image, white point
+      specifies the lightest color, and mid point is gamma aplied to image.
+      Black and white point must be in range [0, 1].}
+    procedure AdjustColorLevels(BlackPoint, WhitePoint: Single; MidPoint: Single = 1.0);
+    { Premultiplies color channel values by alpha. Needed for some platforms/APIs
+      to display images with alpha properly.}
+    procedure PremultiplyAlpha;
+    { Reverses PremultiplyAlpha operation.}
+    procedure UnPremultiplyAlpha;
+
+    { Calculates image histogram for each channel and also gray values. Each
+      channel has 256 values available. Channel values of data formats with higher
+      precision are scaled and rounded. Example: Red[126] specifies number of pixels
+      in image with red channel = 126.}
+    procedure GetHistogram(out Red, Green, Blue, Alpha, Gray: THistogramArray);
+    { Fills image channel with given value leaving other channels intact.
+      Use ChannelAlpha, ChannelRed, etc. constants from ImagingTypes as
+      channel identifier.}
+    procedure FillChannel(ChannelId: Integer; NewChannelValue: Byte); overload;
+    { Fills image channel with given value leaving other channels intact.
+      Use ChannelAlpha, ChannelRed, etc. constants from ImagingTypes as
+      channel identifier.}
+    procedure FillChannelFP(ChannelId: Integer; NewChannelValue: Single); overload;
+
+    { Color used when drawing lines, frames, and outlines of objects.}
+    property PenColor32: TColor32 read FPenColor32 write SetPenColor32;
+    { Color used when drawing lines, frames, and outlines of objects.}
+    property PenColorFP: TColorFPRec read FPenColorFP write SetPenColorFP;
+    { Pen mode used when drawing lines, object outlines, and similar on canvas.}
+    property PenMode: TPenMode read FPenMode write FPenMode;
+    { Width with which objects like lines, frames, etc. (everything which uses
+      PenColor) are drawn.}
+    property PenWidth: LongInt read FPenWidth write SetPenWidth;
+    { Color used for filling when drawing various objects.}
+    property FillColor32: TColor32 read FFillColor32 write SetFillColor32;
+    { Color used for filling when drawing various objects.}
+    property FillColorFP: TColorFPRec read FFillColorFP write SetFillColorFP;
+    { Fill mode used when drawing filled objects on canvas.}
+    property FillMode: TFillMode read FFillMode write FFillMode;
+    { Specifies the current color of the pixels of canvas. Native pixel is
+      read from canvas and then translated to 32bit ARGB. Reverse operation
+      is made when setting pixel color.}
+    property Pixels32[X, Y: LongInt]: TColor32 read GetPixel32 write SetPixel32;
+    { Specifies the current color of the pixels of canvas. Native pixel is
+      read from canvas and then translated to FP ARGB. Reverse operation
+      is made when setting pixel color.}
+    property PixelsFP[X, Y: LongInt]: TColorFPRec read GetPixelFP write SetPixelFP;
+    { Clipping rectangle of this canvas. No pixels outside this rectangle are
+      altered by canvas methods if Clipping property is True. Clip rect gets
+      reseted when UpdateCanvasState is called.}
+    property ClipRect: TRect read FClipRect write SetClipRect;
+    { Extended format information.}
+    property FormatInfo: TImageFormatInfo read FFormatInfo;
+    { Indicates that this canvas is in valid state. If False canvas oprations
+      may crash.}
+    property Valid: Boolean read GetValid;
+
+    { Returns all formats supported by this canvas class.}
+    class function GetSupportedFormats: TImageFormats; virtual;
+  end;
+
+  TImagingCanvasClass = class of TImagingCanvas;
+
+  TScanlineArray = array[0..MaxInt div SizeOf(Pointer) - 1] of PColor32RecArray;
+  PScanlineArray = ^TScanlineArray;
+
+  { Fast canvas class for ifA8R8G8B8 format images.}
+  TFastARGB32Canvas = class(TImagingCanvas)
+  protected
+    FScanlines: PScanlineArray;
+    procedure AlphaBlendPixels(SrcPix, DestPix: PColor32Rec); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetPixel32(X, Y: LongInt): TColor32; override;
+    procedure SetPixel32(X, Y: LongInt; const Value: TColor32); override;
+  public
+    destructor Destroy; override;
+
+    procedure UpdateCanvasState; override;
+
+    procedure DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); override;
+    procedure StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+      const DestRect: TRect; Filter: TResizeFilter = rfBilinear); override;
+    procedure InvertColors; override;
+
+    property Scanlines: PScanlineArray read FScanlines;
+
+    class function GetSupportedFormats: TImageFormats; override;
+  end;
+
+const
+  { Kernel for 3x3 average smoothing filter.}
+  FilterAverage3x3: TConvolutionFilter3x3 = (
+    Kernel: ((1, 1, 1),
+             (1, 1, 1),
+             (1, 1, 1));
+    Divisor: 9);
+
+  { Kernel for 5x5 average smoothing filter.}
+  FilterAverage5x5: TConvolutionFilter5x5 = (
+    Kernel: ((1, 1, 1, 1, 1),
+             (1, 1, 1, 1, 1),
+             (1, 1, 1, 1, 1),
+             (1, 1, 1, 1, 1),
+             (1, 1, 1, 1, 1));
+    Divisor: 25);
+
+  { Kernel for 3x3 Gaussian smoothing filter.}
+  FilterGaussian3x3: TConvolutionFilter3x3 = (
+    Kernel: ((1, 2, 1),
+             (2, 4, 2),
+             (1, 2, 1));
+    Divisor: 16);
+
+  { Kernel for 5x5 Gaussian smoothing filter.}
+  FilterGaussian5x5: TConvolutionFilter5x5 = (
+    Kernel: ((1,  4,  6,  4, 1),
+             (4, 16, 24, 16, 4),
+             (6, 24, 36, 24, 6),
+             (4, 16, 24, 16, 4),
+             (1,  4,  6,  4, 1));
+    Divisor: 256);
+
+  { Kernel for 3x3 Sobel horizontal edge detection filter (1st derivative approximation).}
+  FilterSobelHorz3x3: TConvolutionFilter3x3 = (
+    Kernel: (( 1,  2,  1),
+             ( 0,  0,  0),
+             (-1, -2, -1));
+    Divisor: 1);
+
+  { Kernel for 3x3 Sobel vertical edge detection filter (1st derivative approximation).}
+  FilterSobelVert3x3: TConvolutionFilter3x3 = (
+    Kernel: ((-1, 0, 1),
+             (-2, 0, 2),
+             (-1, 0, 1));
+    Divisor: 1);
+
+  { Kernel for 3x3 Prewitt horizontal edge detection filter.}
+  FilterPrewittHorz3x3: TConvolutionFilter3x3 = (
+    Kernel: (( 1,  1,  1),
+             ( 0,  0,  0),
+             (-1, -1, -1));
+    Divisor: 1);
+
+  { Kernel for 3x3 Prewitt vertical edge detection filter.}
+  FilterPrewittVert3x3: TConvolutionFilter3x3 = (
+    Kernel: ((-1, 0, 1),
+             (-1, 0, 1),
+             (-1, 0, 1));
+    Divisor: 1);
+
+  { Kernel for 3x3 Kirsh horizontal edge detection filter.}
+  FilterKirshHorz3x3: TConvolutionFilter3x3 = (
+    Kernel: (( 5,  5,  5),
+             (-3,  0, -3),
+             (-3, -3, -3));
+    Divisor: 1);
+
+  { Kernel for 3x3 Kirsh vertical edge detection filter.}
+  FilterKirshVert3x3: TConvolutionFilter3x3 = (
+    Kernel: ((5, -3, -3),
+             (5,  0, -3),
+             (5, -3, -3));
+    Divisor: 1);
+
+  { Kernel for 3x3 Laplace omni-directional edge detection filter
+    (2nd derivative approximation).}
+  FilterLaplace3x3: TConvolutionFilter3x3 = (
+    Kernel: ((-1, -1, -1),
+             (-1,  8, -1),
+             (-1, -1, -1));
+    Divisor: 1);
+
+  { Kernel for 5x5 Laplace omni-directional edge detection filter
+    (2nd derivative approximation).}
+  FilterLaplace5x5: TConvolutionFilter5x5 = (
+    Kernel: ((-1, -1, -1, -1, -1),
+             (-1, -1, -1, -1, -1),
+             (-1, -1, 24, -1, -1),
+             (-1, -1, -1, -1, -1),
+             (-1, -1, -1, -1, -1));
+    Divisor: 1);
+
+  { Kernel for 3x3 spharpening filter (Laplacian + original color).}
+  FilterSharpen3x3: TConvolutionFilter3x3 = (
+    Kernel: ((-1, -1, -1),
+             (-1,  9, -1),
+             (-1, -1, -1));
+    Divisor: 1);
+
+  { Kernel for 5x5 spharpening filter (Laplacian + original color).}
+  FilterSharpen5x5: TConvolutionFilter5x5 = (
+    Kernel: ((-1, -1, -1, -1, -1),
+             (-1, -1, -1, -1, -1),
+             (-1, -1, 25, -1, -1),
+             (-1, -1, -1, -1, -1),
+             (-1, -1, -1, -1, -1));
+    Divisor: 1);
+
+  { Kernel for 5x5 glow filter.}
+  FilterGlow5x5: TConvolutionFilter5x5 = (
+    Kernel: (( 1, 2,   2, 2, 1),
+             ( 2, 0,   0, 0, 2),
+             ( 2, 0, -20, 0, 2),
+             ( 2, 0,   0, 0, 2),
+             ( 1, 2,   2, 2, 1));
+    Divisor: 8);
+
+  { Kernel for 3x3 edge enhancement filter.}
+  FilterEdgeEnhance3x3: TConvolutionFilter3x3 = (
+    Kernel: ((-1, -2, -1),
+             (-2, 16, -2),
+             (-1, -2, -1));
+    Divisor: 4);
+
+  { Kernel for 3x3 contour enhancement filter.}
+  FilterTraceControur3x3: TConvolutionFilter3x3 = (
+    Kernel: ((-6, -6, -2),
+             (-1, 32, -1),
+             (-6, -2, -6));
+    Divisor: 4;
+    Bias:    240/255);
+
+  { Kernel for filter that negates all images pixels.}
+  FilterNegative3x3: TConvolutionFilter3x3 = (
+    Kernel: ((0,  0, 0),
+             (0, -1, 0),
+             (0,  0, 0));
+    Divisor: 1;
+    Bias:    1);
+
+  { Kernel for 3x3 horz/vert embossing filter.}
+  FilterEmboss3x3: TConvolutionFilter3x3 = (
+    Kernel: ((2,  0,  0),
+             (0, -1,  0),
+             (0,  0, -1));
+    Divisor: 1;
+    Bias:    0.5);
+
+
+{ You can register your own canvas class. List of registered canvases is used
+  by FindBestCanvasForImage functions to find best canvas for given image.
+  If two different canvases which support the same image data format are
+  registered then the one that was registered later is returned (so you can
+  override builtin Imaging canvases).}
+procedure RegisterCanvas(CanvasClass: TImagingCanvasClass);
+{ Returns best canvas for given TImageFormat.}
+function FindBestCanvasForImage(ImageFormat: TImageFormat): TImagingCanvasClass; overload;
+{ Returns best canvas for given TImageData.}
+function FindBestCanvasForImage(const ImageData: TImageData): TImagingCanvasClass; overload;
+{ Returns best canvas for given TBaseImage.}
+function FindBestCanvasForImage(Image: TBaseImage): TImagingCanvasClass; overload;
+
+implementation
+
+resourcestring
+  SConstructorInvalidPointer = 'Invalid pointer (%p) to TImageData passed to TImagingCanvas constructor.';
+  SConstructorInvalidImage = 'Invalid image data passed to TImagingCanvas constructor (%s).';
+  SConstructorUnsupportedFormat = 'Image passed to TImagingCanvas constructor is in unsupported format (%s)';
+
+var
+  // list with all registered TImagingCanvas classes
+  CanvasClasses: TList = nil;
+
+procedure RegisterCanvas(CanvasClass: TImagingCanvasClass);
+begin
+  Assert(CanvasClass <> nil);
+  if CanvasClasses = nil then
+    CanvasClasses := TList.Create;
+  if CanvasClasses.IndexOf(CanvasClass) < 0 then
+    CanvasClasses.Add(CanvasClass);
+end;
+
+function FindBestCanvasForImage(ImageFormat: TImageFormat): TImagingCanvasClass; overload;
+var
+  I: LongInt;
+begin
+  for I := CanvasClasses.Count - 1 downto 0 do
+  begin
+    if ImageFormat in TImagingCanvasClass(CanvasClasses[I]).GetSupportedFormats then
+    begin
+      Result := TImagingCanvasClass(CanvasClasses[I]);
+      Exit;
+    end;
+  end;
+  Result := TImagingCanvas;
+end;
+
+function FindBestCanvasForImage(const ImageData: TImageData): TImagingCanvasClass;
+begin
+  Result := FindBestCanvasForImage(ImageData.Format);
+end;
+
+function FindBestCanvasForImage(Image: TBaseImage): TImagingCanvasClass;
+begin
+  Result := FindBestCanvasForImage(Image.Format);
+end;
+
+{ Canvas helper functions }
+
+procedure PixelBlendProc(const SrcPix: TColorFPRec; DestPtr: PByte;
+  DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
+var
+  DestPix, FSrc, FDst: TColorFPRec;
+begin
+  // Get set pixel color
+  DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil);
+  // Determine current blending factors
+  case SrcFactor of
+    bfZero:             FSrc := ColorFP(0, 0, 0, 0);
+    bfOne:              FSrc := ColorFP(1, 1, 1, 1);
+    bfSrcAlpha:         FSrc := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A);
+    bfOneMinusSrcAlpha: FSrc := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A);
+    bfDstAlpha:         FSrc := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A);
+    bfOneMinusDstAlpha: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A);
+    bfDstColor:         FSrc := ColorFP(DestPix.A, DestPix.R, DestPix.G, DestPix.B);
+    bfOneMinusDstColor: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.R, 1 - DestPix.G, 1 - DestPix.B);
+  end;
+  case DestFactor of
+    bfZero:             FDst := ColorFP(0, 0, 0, 0);
+    bfOne:              FDst := ColorFP(1, 1, 1, 1);
+    bfSrcAlpha:         FDst := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A);
+    bfOneMinusSrcAlpha: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A);
+    bfDstAlpha:         FDst := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A);
+    bfOneMinusDstAlpha: FDst := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A);
+    bfSrcColor:         FDst := ColorFP(SrcPix.A, SrcPix.R, SrcPix.G, SrcPix.B);
+    bfOneMinusSrcColor: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.R, 1 - SrcPix.G, 1 - SrcPix.B);
+  end;
+  // Compute blending formula
+  DestPix.R := SrcPix.R * FSrc.R + DestPix.R * FDst.R;
+  DestPix.G := SrcPix.G * FSrc.G + DestPix.G * FDst.G;
+  DestPix.B := SrcPix.B * FSrc.B + DestPix.B * FDst.B;
+  DestPix.A := SrcPix.A * FSrc.A + DestPix.A * FDst.A;
+  // Write blended pixel
+  DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix);
+end;
+
+procedure PixelAlphaProc(const SrcPix: TColorFPRec; DestPtr: PByte;
+  DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
+var
+  DestPix: TColorFPRec;
+  SrcAlpha, DestAlpha: Single;
+begin
+  DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil);
+  // Blend the two pixels (Src 'over' Dest alpha composition operation)
+  DestPix.A := SrcPix.A + DestPix.A - SrcPix.A * DestPix.A;
+  if DestPix.A = 0 then
+    SrcAlpha := 0
+  else
+    SrcAlpha := SrcPix.A / DestPix.A;
+  DestAlpha := 1.0 - SrcAlpha;
+  DestPix.R := SrcPix.R * SrcAlpha + DestPix.R * DestAlpha;
+  DestPix.G := SrcPix.G * SrcAlpha + DestPix.G * DestAlpha;
+  DestPix.B := SrcPix.B * SrcAlpha + DestPix.B * DestAlpha;
+  // Write blended pixel
+  DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix);
+end;
+
+procedure PixelAddProc(const SrcPix: TColorFPRec; DestPtr: PByte;
+  DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor);
+var
+  DestPix: TColorFPRec;
+begin
+  // Just add Src and Dest
+  DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil);
+  DestPix.R := SrcPix.R + DestPix.R;
+  DestPix.G := SrcPix.G + DestPix.G;
+  DestPix.B := SrcPix.B + DestPix.B;
+  DestPix.A := SrcPix.A + DestPix.A;
+  DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix);
+end;
+
+function CompareColors(const C1, C2: TColorFPRec): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
+begin
+  Result := (C1.R * GrayConv.R + C1.G * GrayConv.G + C1.B * GrayConv.B) -
+    (C2.R * GrayConv.R + C2.G * GrayConv.G + C2.B * GrayConv.B);
+end;
+
+function MedianSelect(var Pixels: TDynFPPixelArray): TColorFPRec;
+
+  procedure QuickSort(L, R: Integer);
+  var
+    I, J: Integer;
+    P, Temp: TColorFPRec;
+  begin
+    repeat
+      I := L;
+      J := R;
+      P := Pixels[(L + R) shr 1];
+      repeat
+        while CompareColors(Pixels[I], P) < 0 do Inc(I);
+        while CompareColors(Pixels[J], P) > 0 do Dec(J);
+        if I <= J then
+        begin
+          Temp := Pixels[I];
+          Pixels[I] := Pixels[J];
+          Pixels[J] := Temp;
+          Inc(I);
+          Dec(J);
+        end;
+      until I > J;
+      if L < J then
+        QuickSort(L, J);
+      L := I;
+    until I >= R;
+  end;
+
+begin
+  // First sort pixels
+  QuickSort(0, High(Pixels));
+  // Select middle pixel
+  Result := Pixels[Length(Pixels) div 2];
+end;
+
+function MinSelect(var Pixels: TDynFPPixelArray): TColorFPRec;
+var
+  I: Integer;
+begin
+  Result := Pixels[0];
+  for I := 1 to High(Pixels) do
+  begin
+    if CompareColors(Pixels[I], Result) < 0 then
+      Result := Pixels[I];
+  end;
+end;
+
+function MaxSelect(var Pixels: TDynFPPixelArray): TColorFPRec;
+var
+  I: Integer;
+begin
+  Result := Pixels[0];
+  for I := 1 to High(Pixels) do
+  begin
+    if CompareColors(Pixels[I], Result) > 0 then
+      Result := Pixels[I];
+  end;
+end;
+
+function TransformContrastBrightness(const Pixel: TColorFPRec; C, B, P3: Single): TColorFPRec;
+begin
+  Result.A := Pixel.A;
+  Result.R := Pixel.R * C + B;
+  Result.G := Pixel.G * C + B;
+  Result.B := Pixel.B * C + B;
+end;
+
+function TransformGamma(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec;
+begin
+  Result.A := Pixel.A;
+  Result.R := Power(Pixel.R, 1.0 / R);
+  Result.G := Power(Pixel.G, 1.0 / G);
+  Result.B := Power(Pixel.B, 1.0 / B);
+end;
+
+function TransformInvert(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec;
+begin
+  Result.A := Pixel.A;
+  Result.R := 1.0 - Pixel.R;
+  Result.G := 1.0 - Pixel.G;
+  Result.B := 1.0 - Pixel.B;
+end;
+
+function TransformThreshold(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec;
+begin
+  Result.A := Pixel.A;
+  Result.R := IffFloat(Pixel.R >= R, 1.0, 0.0);
+  Result.G := IffFloat(Pixel.G >= G, 1.0, 0.0);
+  Result.B := IffFloat(Pixel.B >= B, 1.0, 0.0);
+end;
+
+function TransformLevels(const Pixel: TColorFPRec; BlackPoint, WhitePoint, Exp: Single): TColorFPRec;
+begin
+  Result.A := Pixel.A;
+  if Pixel.R > BlackPoint then
+    Result.R := Power((Pixel.R - BlackPoint) / (WhitePoint - BlackPoint), Exp)
+  else
+    Result.R := 0.0;
+  if Pixel.G > BlackPoint then
+    Result.G := Power((Pixel.G - BlackPoint) / (WhitePoint - BlackPoint), Exp)
+  else
+    Result.G := 0.0;
+  if Pixel.B > BlackPoint then
+    Result.B := Power((Pixel.B - BlackPoint) / (WhitePoint - BlackPoint), Exp)
+  else
+    Result.B := 0.0;
+end;
+
+function TransformPremultiplyAlpha(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec;
+begin
+  Result.A := Pixel.A;
+  Result.R := Result.R * Pixel.A;
+  Result.G := Result.G * Pixel.A;
+  Result.B := Result.B * Pixel.A;
+end;
+
+function TransformUnPremultiplyAlpha(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec;
+begin
+  Result.A := Pixel.A;
+  if Pixel.A <> 0.0 then
+  begin
+    Result.R := Result.R / Pixel.A;
+    Result.G := Result.G / Pixel.A;
+    Result.B := Result.B / Pixel.A;
+  end
+  else
+  begin
+    Result.R := 0;
+    Result.G := 0;
+    Result.B := 0;
+  end;
+end;
+
+
+{ TImagingCanvas class implementation }
+
+constructor TImagingCanvas.CreateForData(ImageDataPointer: PImageData);
+begin
+  if ImageDataPointer = nil then
+    raise EImagingCanvasError.CreateFmt(SConstructorInvalidPointer, [ImageDataPointer]);
+
+  if not TestImage(ImageDataPointer^) then
+    raise EImagingCanvasError.CreateFmt(SConstructorInvalidImage, [Imaging.ImageToStr(ImageDataPointer^)]);
+
+  if not (ImageDataPointer.Format in GetSupportedFormats) then
+    raise EImagingCanvasError.CreateFmt(SConstructorUnsupportedFormat, [Imaging.ImageToStr(ImageDataPointer^)]);
+
+  FPData := ImageDataPointer;
+  FPenWidth := 1;
+  SetPenColor32(pcWhite);
+  SetFillColor32(pcBlack);
+  FFillMode := fmSolid;
+
+  UpdateCanvasState;
+end;
+
+constructor TImagingCanvas.CreateForImage(Image: TBaseImage);
+begin
+  CreateForData(Image.ImageDataPointer);
+end;
+
+destructor TImagingCanvas.Destroy;
+begin
+  inherited Destroy;
+end;
+
+function TImagingCanvas.GetPixel32(X, Y: LongInt): TColor32;
+begin
+  Result := Imaging.GetPixel32(FPData^, X, Y).Color;
+end;
+
+function TImagingCanvas.GetPixelFP(X, Y: LongInt): TColorFPRec;
+begin
+  Result := Imaging.GetPixelFP(FPData^, X, Y);
+end;
+
+function TImagingCanvas.GetValid: Boolean;
+begin
+  Result := (FPData <> nil) and (FDataSizeOnUpdate = FPData.Size);
+end;
+
+procedure TImagingCanvas.SetPixel32(X, Y: LongInt; const Value: TColor32);
+begin
+  if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and
+    (X < FClipRect.Right) and (Y < FClipRect.Bottom) then
+  begin
+    Imaging.SetPixel32(FPData^, X, Y, TColor32Rec(Value));
+  end;
+end;
+
+procedure TImagingCanvas.SetPixelFP(X, Y: LongInt; const Value: TColorFPRec);
+begin
+  if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and
+    (X < FClipRect.Right) and (Y < FClipRect.Bottom) then
+  begin
+    Imaging.SetPixelFP(FPData^, X, Y, TColorFPRec(Value));
+  end;
+end;
+
+procedure TImagingCanvas.SetPenColor32(const Value: TColor32);
+begin
+  FPenColor32 := Value;
+  TranslatePixel(@FPenColor32, @FPenColorFP, ifA8R8G8B8, ifA32R32G32B32F, nil, nil);
+end;
+
+procedure TImagingCanvas.SetPenColorFP(const Value: TColorFPRec);
+begin
+  FPenColorFP := Value;
+  TranslatePixel(@FPenColorFP, @FPenColor32, ifA32R32G32B32F, ifA8R8G8B8, nil, nil);
+end;
+
+procedure TImagingCanvas.SetPenWidth(const Value: LongInt);
+begin
+  FPenWidth := ClampInt(Value, 0, MaxPenWidth);
+end;
+
+procedure TImagingCanvas.SetFillColor32(const Value: TColor32);
+begin
+  FFillColor32 := Value;
+  TranslatePixel(@FFillColor32, @FFillColorFP, ifA8R8G8B8, ifA32R32G32B32F, nil, nil);
+end;
+
+procedure TImagingCanvas.SetFillColorFP(const Value: TColorFPRec);
+begin
+  FFillColorFP := Value;
+  TranslatePixel(@FFillColorFP, @FFillColor32, ifA32R32G32B32F, ifA8R8G8B8, nil, nil);
+end;
+
+procedure TImagingCanvas.SetClipRect(const Value: TRect);
+begin
+  FClipRect := Value;
+  SwapMin(FClipRect.Left, FClipRect.Right);
+  SwapMin(FClipRect.Top, FClipRect.Bottom);
+  IntersectRect(FClipRect, FClipRect, Rect(0, 0, FPData.Width, FPData.Height));
+end;
+
+procedure TImagingCanvas.CheckBeforeBlending(SrcFactor,
+  DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas);
+begin
+  if SrcFactor in [bfSrcColor, bfOneMinusSrcColor] then
+    raise EImagingCanvasBlendingError.Create('Invalid source blending factor. Check the documentation for TBlendingFactor.');
+  if DestFactor in [bfDstColor, bfOneMinusDstColor] then
+    raise EImagingCanvasBlendingError.Create('Invalid destination blending factor. Check the documentation for TBlendingFactor.');
+  if DestCanvas.FormatInfo.IsIndexed then
+    raise EImagingCanvasBlendingError.Create('Blending destination canvas cannot be in indexed mode.');
+end;
+
+function TImagingCanvas.GetPixelPointer(X, Y: LongInt): Pointer;
+begin
+  Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * FFormatInfo.BytesPerPixel]
+end;
+
+procedure TImagingCanvas.TranslateFPToNative(const Color: TColorFPRec);
+begin
+  TranslateFPToNative(Color, @FNativeColor);
+end;
+
+procedure TImagingCanvas.TranslateFPToNative(const Color: TColorFPRec;
+  Native: Pointer);
+begin
+  ImagingFormats.TranslatePixel(@Color, Native, ifA32R32G32B32F,
+    FPData.Format, nil, FPData.Palette);
+end;
+
+procedure TImagingCanvas.UpdateCanvasState;
+begin
+  FDataSizeOnUpdate := FPData.Size;
+  ResetClipRect;
+  Imaging.GetImageFormatInfo(FPData.Format, FFormatInfo)
+end;
+
+procedure TImagingCanvas.ResetClipRect;
+begin
+  FClipRect := Rect(0, 0, FPData.Width, FPData.Height)
+end;
+
+procedure TImagingCanvas.Clear;
+begin
+  TranslateFPToNative(FFillColorFP);
+  Imaging.FillRect(FPData^, 0, 0, FPData.Width, FPData.Height, @FNativeColor);
+end;
+
+function TImagingCanvas.ClipAxisParallelLine(var A1, A2, B: LongInt;
+  AStart, AStop, BStart, BStop: LongInt): Boolean;
+begin
+  if (B >= BStart) and (B < BStop) then
+  begin
+    SwapMin(A1, A2);
+    if A1 < AStart then A1 := AStart;
+    if A2 >= AStop then A2 := AStop - 1;
+    Result := True;
+  end
+  else
+    Result := False;
+end;
+
+procedure TImagingCanvas.HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer;
+  Bpp: LongInt);
+var
+  I, WidthBytes: LongInt;
+  PixelPtr: PByte;
+begin
+  if (Y >= FClipRect.Top) and (Y < FClipRect.Bottom) then
+  begin
+    SwapMin(X1, X2);
+    X1 := Max(X1, FClipRect.Left);
+    X2 := Min(X2, FClipRect.Right);
+    PixelPtr := GetPixelPointer(X1, Y);
+    WidthBytes := (X2 - X1) * Bpp;
+    case Bpp of
+      1: FillMemoryByte(PixelPtr, WidthBytes, PByte(Color)^);
+      2: FillMemoryWord(PixelPtr, WidthBytes, PWord(Color)^);
+      4: FillMemoryLongWord(PixelPtr, WidthBytes, PLongWord(Color)^);
+    else
+      for I := X1 to X2 do
+      begin
+        ImagingFormats.CopyPixel(Color, PixelPtr, Bpp);
+        Inc(PixelPtr, Bpp);
+       end;
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.CopyPixelInternal(X, Y: LongInt; Pixel: Pointer;
+  Bpp: LongInt);
+begin
+  if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and
+    (X < FClipRect.Right) and (Y < FClipRect.Bottom) then
+  begin
+    ImagingFormats.CopyPixel(Pixel, GetPixelPointer(X, Y), Bpp);
+  end;
+end;
+
+procedure TImagingCanvas.HorzLine(X1, X2, Y: LongInt);
+var
+  DstRect: TRect;
+begin
+  if FPenMode = pmClear then Exit;
+  SwapMin(X1, X2);
+  if IntersectRect(DstRect, Rect(X1, Y - FPenWidth div 2, X2,
+    Y + FPenWidth div 2 + FPenWidth mod 2), FClipRect) then
+  begin
+    TranslateFPToNative(FPenColorFP);
+    Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left,
+      DstRect.Bottom - DstRect.Top, @FNativeColor);
+  end;
+end;
+
+procedure TImagingCanvas.VertLine(X, Y1, Y2: LongInt);
+var
+  DstRect: TRect;
+begin
+  if FPenMode = pmClear then Exit;
+  SwapMin(Y1, Y2);
+  if IntersectRect(DstRect, Rect(X - FPenWidth div 2, Y1,
+    X + FPenWidth div 2 + FPenWidth mod 2, Y2), FClipRect) then
+  begin
+    TranslateFPToNative(FPenColorFP);
+    Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left,
+      DstRect.Bottom - DstRect.Top, @FNativeColor);
+  end;
+end;
+
+procedure TImagingCanvas.Line(X1, Y1, X2, Y2: LongInt);
+var
+  Steep: Boolean;
+  Error, YStep, DeltaX, DeltaY, X, Y, I, Bpp, W1, W2, Code1, Code2: LongInt;
+begin
+  if FPenMode = pmClear then Exit;
+
+  // If line is vertical or horizontal just call appropriate method
+  if X2 = X1 then
+  begin
+    VertLine(X1, Y1, Y2);
+    Exit;
+  end;
+  if Y2 = Y1 then
+  begin
+    HorzLine(X1, X2, Y1);
+    Exit;
+  end;
+
+  // Determine if line is steep (angle with X-axis > 45 degrees)
+  Steep := Abs(Y2 - Y1) > Abs(X2 - X1);
+
+  // If we need to draw thick line we just draw more 1 pixel lines around
+  // the one we already drawn. Setting FLineRecursion assures that we
+  // won't be doing recursions till the end of the world.
+  if (FPenWidth > 1) and not FLineRecursion then
+  begin
+    FLineRecursion := True;
+    W1 := FPenWidth div 2;
+    W2 := W1;
+    if FPenWidth mod 2 = 0 then
+      Dec(W1);
+    if Steep then
+    begin
+      // Add lines left/right
+      for I := 1 to W1 do
+        Line(X1, Y1 - I, X2, Y2 - I);
+      for I := 1 to W2 do
+        Line(X1, Y1 + I, X2, Y2 + I);
+    end
+    else
+    begin
+      // Add lines above/under
+      for I := 1 to W1 do
+        Line(X1 - I, Y1, X2 - I, Y2);
+      for I := 1 to W2 do
+        Line(X1 + I, Y1, X2 + I, Y2);
+    end;
+    FLineRecursion := False;
+  end;
+
+  with FClipRect do
+  begin
+    // Use part of Cohen-Sutherland line clipping to determine if any part of line
+    // is in ClipRect
+    Code1 := Ord(X1 < Left) + Ord(X1 > Right) shl 1 + Ord(Y1 < Top) shl 2 + Ord(Y1 > Bottom) shl 3;
+    Code2 := Ord(X2 < Left) + Ord(X2 > Right) shl 1 + Ord(Y2 < Top) shl 2 + Ord(Y2 > Bottom) shl 3;
+  end;
+
+  if (Code1 and Code2) = 0 then
+  begin
+    TranslateFPToNative(FPenColorFP);
+    Bpp := FFormatInfo.BytesPerPixel;
+
+    // If line is steep swap X and Y coordinates so later we just have one loop
+    // of two (where only one is used according to steepness).
+    if Steep then
+    begin
+      SwapValues(X1, Y1);
+      SwapValues(X2, Y2);
+    end;
+    if X1 > X2 then
+    begin
+      SwapValues(X1, X2);
+      SwapValues(Y1, Y2);
+    end;
+
+    DeltaX := X2 - X1;
+    DeltaY := Abs(Y2 - Y1);
+    YStep := Iff(Y2 > Y1, 1, -1);
+    Error := 0;
+    Y := Y1;
+
+    // Draw line using Bresenham algorithm. No real line clipping here,
+    // just don't draw pixels outsize clip rect.
+    for X := X1 to X2 do
+    begin
+      if Steep then
+        CopyPixelInternal(Y, X, @FNativeColor, Bpp)
+      else
+        CopyPixelInternal(X, Y, @FNativeColor, Bpp);
+      Error := Error + DeltaY;
+      if Error * 2 >= DeltaX then
+      begin
+        Inc(Y, YStep);
+        Dec(Error, DeltaX);
+      end;
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.FrameRect(const Rect: TRect);
+var
+  HalfPen, PenMod: LongInt;
+begin
+  if FPenMode = pmClear then Exit;
+  HalfPen := FPenWidth div 2;
+  PenMod := FPenWidth mod 2;
+  HorzLine(Rect.Left - HalfPen, Rect.Right + HalfPen + PenMod - 1, Rect.Top);
+  HorzLine(Rect.Left - HalfPen, Rect.Right + HalfPen + PenMod - 1, Rect.Bottom - 1);
+  VertLine(Rect.Left, Rect.Top, Rect.Bottom);
+  VertLine(Rect.Right - 1, Rect.Top, Rect.Bottom);
+end;
+
+procedure TImagingCanvas.FillRect(const Rect: TRect);
+var
+  DstRect: TRect;
+begin
+  if (FFillMode <> fmClear) and IntersectRect(DstRect, Rect, FClipRect) then
+  begin
+    TranslateFPToNative(FFillColorFP);
+    Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left,
+      DstRect.Bottom - DstRect.Top, @FNativeColor);
+  end;
+end;
+
+procedure TImagingCanvas.FillRectBlend(const Rect: TRect; SrcFactor,
+  DestFactor: TBlendingFactor);
+var
+  DstRect: TRect;
+  X, Y: Integer;
+  Line: PByte;
+begin
+  if (FFillMode <> fmClear) and IntersectRect(DstRect, Rect, FClipRect) then
+  begin
+    CheckBeforeBlending(SrcFactor, DestFactor, Self);
+    for Y := DstRect.Top to DstRect.Bottom - 1 do
+    begin
+      Line := @PByteArray(FPData.Bits)[(Y * FPData.Width + DstRect.Left) * FFormatInfo.BytesPerPixel];
+      for X := DstRect.Left to DstRect.Right - 1 do
+      begin
+        PixelBlendProc(FFillColorFP, Line, @FFormatInfo, SrcFactor, DestFactor);
+        Inc(Line, FFormatInfo.BytesPerPixel);
+      end;
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.Rectangle(const Rect: TRect);
+begin
+  FillRect(Rect);
+  FrameRect(Rect);
+end;
+
+procedure TImagingCanvas.Ellipse(const Rect: TRect);
+var
+ RadX, RadY, DeltaX, DeltaY, R, RX, RY: LongInt;
+ X1, X2, Y1, Y2, Bpp, OldY: LongInt;
+ Fill, Pen: TColorFPRec;
+begin
+  // TODO: Use PenWidth
+  X1 := Rect.Left;
+  X2 := Rect.Right;
+  Y1 := Rect.Top;
+  Y2 := Rect.Bottom;
+
+  TranslateFPToNative(FPenColorFP, @Pen);
+  TranslateFPToNative(FFillColorFP, @Fill);
+  Bpp := FFormatInfo.BytesPerPixel;
+
+  SwapMin(X1, X2);
+  SwapMin(Y1, Y2);
+
+  RadX := (X2 - X1) div 2;
+  RadY := (Y2 - Y1) div 2;
+
+  Y1 := Y1 + RadY;
+  Y2 := Y1;
+  OldY := Y1;
+
+  DeltaX := (RadX * RadX);
+  DeltaY := (RadY * RadY);
+  R  := RadX * RadY * RadY;
+  RX := R;
+  RY := 0;
+
+  if (FFillMode <> fmClear) then
+    HorzLineInternal(X1, X2, Y1, @Fill, Bpp);
+  CopyPixelInternal(X1, Y1, @Pen, Bpp);
+  CopyPixelInternal(X2, Y1, @Pen, Bpp);
+
+  while RadX > 0 do
+  begin
+    if R > 0 then
+    begin
+      Inc(Y1);
+      Dec(Y2);
+      Inc(RY, DeltaX);
+      Dec(R, RY);
+    end;
+    if R <= 0 then
+    begin
+      Dec(RadX);
+      Inc(X1);
+      Dec(X2);
+      Dec(RX, DeltaY);
+      Inc(R, RX);
+    end;
+
+    if (OldY <> Y1) and (FFillMode <> fmClear) then
+    begin
+      HorzLineInternal(X1, X2, Y1, @Fill, Bpp);
+      HorzLineInternal(X1, X2, Y2, @Fill, Bpp);
+    end;
+    OldY := Y1;
+
+    CopyPixelInternal(X1, Y1, @Pen, Bpp);
+    CopyPixelInternal(X2, Y1, @Pen, Bpp);
+    CopyPixelInternal(X1, Y2, @Pen, Bpp);
+    CopyPixelInternal(X2, Y2, @Pen, Bpp);
+  end;
+end;
+
+procedure TImagingCanvas.FloodFill(X, Y: Integer; BoundaryFillMode: Boolean);
+var
+  Stack: array of TPoint;
+  StackPos, Y1: Integer;
+  OldColor: TColor32;
+  SpanLeft, SpanRight: Boolean;
+
+  procedure Push(AX, AY: Integer);
+  begin
+    if StackPos < High(Stack) then
+    begin
+      Inc(StackPos);
+      Stack[StackPos].X := AX;
+      Stack[StackPos].Y := AY;
+    end
+    else
+    begin
+      SetLength(Stack, Length(Stack) + FPData.Width);
+      Push(AX, AY);
+    end;
+  end;
+
+  function Pop(out AX, AY: Integer): Boolean;
+  begin
+    if StackPos > 0 then
+    begin
+      AX := Stack[StackPos].X;
+      AY := Stack[StackPos].Y;
+      Dec(StackPos);
+      Result := True;
+    end
+    else
+      Result := False;
+  end;
+
+  function Compare(AX, AY: Integer): Boolean;
+  var
+    Color: TColor32;
+  begin
+    Color := GetPixel32(AX, AY);
+    if BoundaryFillMode then
+      Result := (Color <> FFillColor32) and (Color <> FPenColor32)
+    else
+      Result := Color = OldColor;
+  end;
+
+begin
+  // Scanline Floodfill Algorithm With Stack
+  // http://student.kuleuven.be/~m0216922/CG/floodfill.html
+
+  if not PtInRect(FClipRect, Point(X, Y)) then Exit;
+
+  SetLength(Stack, FPData.Width * 4);
+  StackPos := 0;
+
+  OldColor := GetPixel32(X, Y);
+
+  Push(X, Y);
+
+  while Pop(X, Y) do
+  begin
+    Y1 := Y;
+    while (Y1 >= FClipRect.Top) and Compare(X, Y1) do
+      Dec(Y1);
+
+    Inc(Y1);
+    SpanLeft := False;
+    SpanRight := False;
+
+    while (Y1 < FClipRect.Bottom) and Compare(X, Y1) do
+    begin
+      SetPixel32(X, Y1, FFillColor32);
+      if not SpanLeft and (X > FClipRect.Left) and Compare(X - 1, Y1) then
+      begin
+        Push(X - 1, Y1);
+        SpanLeft := True;
+      end
+      else if SpanLeft and (X > FClipRect.Left) and not Compare(X - 1, Y1) then
+        SpanLeft := False
+      else if not SpanRight and (X < FClipRect.Right - 1) and Compare(X + 1, Y1)then
+      begin
+        Push(X + 1, Y1);
+        SpanRight := True;
+      end
+      else if SpanRight and (X < FClipRect.Right - 1) and not Compare(X + 1, Y1) then
+        SpanRight := False;
+
+      Inc(Y1);
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.DrawInternal(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; DestX, DestY: Integer; SrcFactor,
+  DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc);
+var
+  X, Y, SrcX, SrcY, Width, Height, SrcBpp, DestBpp: Integer;
+  PSrc: TColorFPRec;
+  SrcPointer, DestPointer: PByte;
+begin
+  CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas);
+  SrcX := SrcRect.Left;
+  SrcY := SrcRect.Top;
+  Width := SrcRect.Right - SrcRect.Left;
+  Height := SrcRect.Bottom - SrcRect.Top;
+  SrcBpp := FFormatInfo.BytesPerPixel;
+  DestBpp := DestCanvas.FFormatInfo.BytesPerPixel;
+  // Clip src and dst rects
+  ClipCopyBounds(SrcX, SrcY, Width, Height, DestX, DestY,
+    FPData.Width, FPData.Height, DestCanvas.ClipRect);
+
+  for Y := 0 to Height - 1 do
+  begin
+    // Get src and dst scanlines
+    SrcPointer := @PByteArray(FPData.Bits)[((SrcY + Y) * FPData.Width + SrcX) * SrcBpp];
+    DestPointer := @PByteArray(DestCanvas.FPData.Bits)[((DestY + Y) * DestCanvas.FPData.Width + DestX) * DestBpp];
+
+    for X := 0 to Width - 1 do
+    begin
+      PSrc := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, FPData.Palette);
+      // Call pixel writer procedure - combine source and dest pixels
+      PixelWriteProc(PSrc, DestPointer, @DestCanvas.FFormatInfo, SrcFactor, DestFactor);
+      // Increment pixel pointers
+      Inc(SrcPointer, SrcBpp);
+      Inc(DestPointer, DestBpp);
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+  DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor);
+begin
+  DrawInternal(SrcRect, DestCanvas, DestX, DestY, SrcFactor, DestFactor, PixelBlendProc);
+end;
+
+procedure TImagingCanvas.DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas;
+  DestX, DestY: Integer);
+begin
+  DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAlphaProc);
+end;
+
+procedure TImagingCanvas.DrawAdd(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; DestX, DestY: Integer);
+begin
+  DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAddProc);
+end;
+
+procedure TImagingCanvas.StretchDrawInternal(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; const DestRect: TRect;
+  SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter;
+  PixelWriteProc: TPixelWriteProc);
+const
+  FilterMapping: array[TResizeFilter] of TSamplingFilter =
+    (sfNearest, sfLinear, DefaultCubicFilter, sfLanczos);
+var
+  X, Y, I, J, SrcX, SrcY, SrcWidth, SrcHeight: Integer;
+  DestX, DestY, DestWidth, DestHeight, SrcBpp, DestBpp: Integer;
+  SrcPix: TColorFPRec;
+  MapX, MapY: TMappingTable;
+  XMinimum, XMaximum: Integer;
+  LineBuffer: array of TColorFPRec;
+  ClusterX, ClusterY: TCluster;
+  Weight, AccumA, AccumR, AccumG, AccumB: Single;
+  DestLine: PByte;
+  FilterFunction: TFilterFunction;
+  Radius: Single;
+begin
+  CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas);
+  SrcX := SrcRect.Left;
+  SrcY := SrcRect.Top;
+  SrcWidth := SrcRect.Right - SrcRect.Left;
+  SrcHeight := SrcRect.Bottom - SrcRect.Top;
+  DestX := DestRect.Left;
+  DestY := DestRect.Top;
+  DestWidth := DestRect.Right - DestRect.Left;
+  DestHeight := DestRect.Bottom - DestRect.Top;
+  SrcBpp := FFormatInfo.BytesPerPixel;
+  DestBpp := DestCanvas.FFormatInfo.BytesPerPixel;
+  // Get actual resampling filter and radius
+  FilterFunction := SamplingFilterFunctions[FilterMapping[Filter]];
+  Radius := SamplingFilterRadii[FilterMapping[Filter]];
+  // Clip src and dst rects
+  ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DestX, DestY, DestWidth, DestHeight,
+      FPData.Width, FPData.Height, DestCanvas.ClipRect);
+  // Generate mapping tables
+  MapX := BuildMappingTable(DestX, DestX + DestWidth, SrcX, SrcX + SrcWidth,
+    FPData.Width, FilterFunction, Radius, False);
+  MapY := BuildMappingTable(DestY, DestY + DestHeight, SrcY, SrcY + SrcHeight,
+    FPData.Height, FilterFunction, Radius, False);
+  FindExtremes(MapX, XMinimum, XMaximum);
+  SetLength(LineBuffer, XMaximum - XMinimum + 1);
+
+  for J := 0 to DestHeight - 1 do
+  begin
+    ClusterY := MapY[J];
+    for X := XMinimum to XMaximum do
+    begin
+      AccumA := 0.0;
+      AccumR := 0.0;
+      AccumG := 0.0;
+      AccumB := 0.0;
+      for Y := 0 to Length(ClusterY) - 1 do
+      begin
+        Weight := ClusterY[Y].Weight;
+        SrcPix := FFormatInfo.GetPixelFP(@PByteArray(FPData.Bits)[(ClusterY[Y].Pos * FPData.Width + X) * SrcBpp],
+          @FFormatInfo, FPData.Palette);
+        AccumB := AccumB + SrcPix.B * Weight;
+        AccumG := AccumG + SrcPix.G * Weight;
+        AccumR := AccumR + SrcPix.R * Weight;
+        AccumA := AccumA + SrcPix.A * Weight;
+      end;
+      with LineBuffer[X - XMinimum] do
+      begin
+        A := AccumA;
+        R := AccumR;
+        G := AccumG;
+        B := AccumB;
+      end;
+    end;
+
+    DestLine := @PByteArray(DestCanvas.FPData.Bits)[((J + DestY) * DestCanvas.FPData.Width + DestX) * DestBpp];
+
+    for I := 0 to DestWidth - 1 do
+    begin
+      ClusterX := MapX[I];
+      AccumA := 0.0;
+      AccumR := 0.0;
+      AccumG := 0.0;
+      AccumB := 0.0;
+      for X := 0 to Length(ClusterX) - 1 do
+      begin
+        Weight := ClusterX[X].Weight;
+        with LineBuffer[ClusterX[X].Pos - XMinimum] do
+        begin
+          AccumB := AccumB + B * Weight;
+          AccumG := AccumG + G * Weight;
+          AccumR := AccumR + R * Weight;
+          AccumA := AccumA + A * Weight;
+        end;
+      end;
+
+      SrcPix.A := AccumA;
+      SrcPix.R := AccumR;
+      SrcPix.G := AccumG;
+      SrcPix.B := AccumB;
+
+      // Write resulting blended pixel
+      PixelWriteProc(SrcPix, DestLine, @DestCanvas.FFormatInfo, SrcFactor, DestFactor);
+      Inc(DestLine, DestBpp);
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.StretchDrawBlend(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; const DestRect: TRect;
+  SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter);
+begin
+  StretchDrawInternal(SrcRect, DestCanvas, DestRect, SrcFactor, DestFactor, Filter, PixelBlendProc);
+end;
+
+procedure TImagingCanvas.StretchDrawAlpha(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter);
+begin
+  StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAlphaProc);
+end;
+
+procedure TImagingCanvas.StretchDrawAdd(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter);
+begin
+  StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAddProc);
+end;
+
+procedure TImagingCanvas.ApplyConvolution(Kernel: PLongInt; KernelSize,
+  Divisor: LongInt; Bias: Single; ClampChannels: Boolean);
+var
+  X, Y, I, J, PosY, PosX, SizeDiv2, KernelValue, WidthBytes, Bpp: LongInt;
+  R, G, B, DivFloat: Single;
+  Pixel: TColorFPRec;
+  TempImage: TImageData;
+  DstPointer, SrcPointer: PByte;
+begin
+  SizeDiv2 := KernelSize div 2;
+  DivFloat := IffFloat(Divisor > 1, 1.0 / Divisor, 1.0);
+  Bpp := FFormatInfo.BytesPerPixel;
+  WidthBytes := FPData.Width * Bpp;
+
+  InitImage(TempImage);
+  CloneImage(FPData^, TempImage);
+
+  try
+    // For every pixel in clip rect
+    for Y := FClipRect.Top to FClipRect.Bottom - 1 do
+    begin
+      DstPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp];
+
+      for X := FClipRect.Left to FClipRect.Right - 1 do
+      begin
+        // Reset accumulators
+        R := 0.0;
+        G := 0.0;
+        B := 0.0;
+
+        for J := 0 to KernelSize - 1 do
+        begin
+          PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1);
+
+          for I := 0 to KernelSize - 1 do
+          begin
+            PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1);
+            SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp];
+
+            // Get pixels from neighbourhood of current pixel and add their
+            // colors to accumulators weighted by filter kernel values
+            Pixel := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, TempImage.Palette);
+            KernelValue := PLongIntArray(Kernel)[J * KernelSize + I];
+
+            R := R + Pixel.R * KernelValue;
+            G := G + Pixel.G * KernelValue;
+            B := B + Pixel.B * KernelValue;
+          end;
+        end;
+
+        Pixel := FFormatInfo.GetPixelFP(DstPointer, @FFormatInfo, FPData.Palette);
+
+        Pixel.R := R * DivFloat + Bias;
+        Pixel.G := G * DivFloat + Bias;
+        Pixel.B := B * DivFloat + Bias;
+
+        if ClampChannels then
+          ClampFloatPixel(Pixel);
+
+        // Set resulting pixel color
+        FFormatInfo.SetPixelFP(DstPointer, @FFormatInfo, FPData.Palette, Pixel);
+
+        Inc(DstPointer, Bpp);
+      end;
+    end;
+
+  finally
+    FreeImage(TempImage);
+  end;
+end;
+
+procedure TImagingCanvas.ApplyConvolution3x3(const Filter: TConvolutionFilter3x3);
+begin
+  ApplyConvolution(@Filter.Kernel, 3, Filter.Divisor, Filter.Bias, True);
+end;
+
+procedure TImagingCanvas.ApplyConvolution5x5(const Filter: TConvolutionFilter5x5);
+begin
+  ApplyConvolution(@Filter.Kernel, 5, Filter.Divisor, Filter.Bias, True);
+end;
+
+procedure TImagingCanvas.ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction);
+var
+  X, Y, I, J, PosY, PosX, SizeDiv2, WidthBytes, Bpp: LongInt;
+  Pixel: TColorFPRec;
+  TempImage: TImageData;
+  DstPointer, SrcPointer: PByte;
+  NeighPixels: TDynFPPixelArray;
+begin
+  SizeDiv2 := FilterSize div 2;
+  Bpp := FFormatInfo.BytesPerPixel;
+  WidthBytes := FPData.Width * Bpp;
+  SetLength(NeighPixels, FilterSize * FilterSize);
+
+  InitImage(TempImage);
+  CloneImage(FPData^, TempImage);
+
+  try
+    // For every pixel in clip rect
+    for Y := FClipRect.Top to FClipRect.Bottom - 1 do
+    begin
+      DstPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp];
+
+      for X := FClipRect.Left to FClipRect.Right - 1 do
+      begin
+        for J := 0 to FilterSize - 1 do
+        begin
+          PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1);
+
+          for I := 0 to FilterSize - 1 do
+          begin
+            PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1);
+            SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp];
+
+            // Get pixels from neighbourhood of current pixel and store them
+            Pixel := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, TempImage.Palette);
+            NeighPixels[J * FilterSize + I] := Pixel;
+          end;
+        end;
+
+        // Choose pixel using custom function
+        Pixel := SelectFunc(NeighPixels);
+        // Set resulting pixel color
+        FFormatInfo.SetPixelFP(DstPointer, @FFormatInfo, FPData.Palette, Pixel);
+
+        Inc(DstPointer, Bpp);
+      end;
+    end;
+
+  finally
+    FreeImage(TempImage);
+  end;
+end;
+
+procedure TImagingCanvas.ApplyMedianFilter(FilterSize: Integer);
+begin
+  ApplyNonLinearFilter(FilterSize, MedianSelect);
+end;
+
+procedure TImagingCanvas.ApplyMinFilter(FilterSize: Integer);
+begin
+  ApplyNonLinearFilter(FilterSize, MinSelect);
+end;
+
+procedure TImagingCanvas.ApplyMaxFilter(FilterSize: Integer);
+begin
+  ApplyNonLinearFilter(FilterSize, MaxSelect);
+end;
+
+procedure TImagingCanvas.PointTransform(Transform: TPointTransformFunction;
+  Param1, Param2, Param3: Single);
+var
+  X, Y, Bpp, WidthBytes: Integer;
+  PixPointer: PByte;
+  Pixel: TColorFPRec;
+begin
+  Bpp := FFormatInfo.BytesPerPixel;
+  WidthBytes := FPData.Width * Bpp;
+
+  // For every pixel in clip rect
+  for Y := FClipRect.Top to FClipRect.Bottom - 1 do
+  begin
+    PixPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp];
+    for X := FClipRect.Left to FClipRect.Right - 1 do
+    begin
+      Pixel := FFormatInfo.GetPixelFP(PixPointer, @FFormatInfo, FPData.Palette);
+
+      FFormatInfo.SetPixelFP(PixPointer, @FFormatInfo, FPData.Palette,
+        Transform(Pixel, Param1, Param2, Param3));
+
+      Inc(PixPointer, Bpp);
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.ModifyContrastBrightness(Contrast, Brightness: Single);
+begin
+  PointTransform(TransformContrastBrightness, 1.0 + Contrast / 100,
+    Brightness / 100, 0);
+end;
+
+procedure TImagingCanvas.GammaCorection(Red, Green, Blue: Single);
+begin
+  PointTransform(TransformGamma, Red, Green, Blue);
+end;
+
+procedure TImagingCanvas.InvertColors;
+begin
+  PointTransform(TransformInvert, 0, 0, 0);
+end;
+
+procedure TImagingCanvas.Threshold(Red, Green, Blue: Single);
+begin
+  PointTransform(TransformThreshold, Red, Green, Blue);
+end;
+
+procedure TImagingCanvas.AdjustColorLevels(BlackPoint, WhitePoint, MidPoint: Single);
+begin
+  PointTransform(TransformLevels, BlackPoint, WhitePoint, 1.0 / MidPoint);
+end;
+
+procedure TImagingCanvas.PremultiplyAlpha;
+begin
+  PointTransform(TransformPremultiplyAlpha, 0, 0, 0);
+end;
+
+procedure TImagingCanvas.UnPremultiplyAlpha;
+begin
+  PointTransform(TransformUnPremultiplyAlpha, 0, 0, 0);
+end;
+
+procedure TImagingCanvas.GetHistogram(out Red, Green, Blue, Alpha,
+  Gray: THistogramArray);
+var
+  X, Y, Bpp: Integer;
+  PixPointer: PByte;
+  Color32: TColor32Rec;
+begin
+  FillChar(Red,   SizeOf(Red), 0);
+  FillChar(Green, SizeOf(Green), 0);
+  FillChar(Blue,  SizeOf(Blue), 0);
+  FillChar(Alpha, SizeOf(Alpha), 0);
+  FillChar(Gray,  SizeOf(Gray), 0);
+
+  Bpp := FFormatInfo.BytesPerPixel;
+
+  for Y := FClipRect.Top to FClipRect.Bottom - 1 do
+  begin
+    PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp];
+    for X := FClipRect.Left to FClipRect.Right - 1 do
+    begin
+      Color32 := FFormatInfo.GetPixel32(PixPointer, @FFormatInfo, FPData.Palette);
+
+      Inc(Red[Color32.R]);
+      Inc(Green[Color32.G]);
+      Inc(Blue[Color32.B]);
+      Inc(Alpha[Color32.A]);
+      Inc(Gray[Round(GrayConv.R * Color32.R + GrayConv.G * Color32.G + GrayConv.B * Color32.B)]);
+
+      Inc(PixPointer, Bpp);
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.FillChannel(ChannelId: Integer; NewChannelValue: Byte);
+var
+  X, Y, Bpp: Integer;
+  PixPointer: PByte;
+  Color32: TColor32Rec;
+begin
+  Bpp := FFormatInfo.BytesPerPixel;
+
+  for Y := FClipRect.Top to FClipRect.Bottom - 1 do
+  begin
+    PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp];
+    for X := FClipRect.Left to FClipRect.Right - 1 do
+    begin
+      Color32 := FFormatInfo.GetPixel32(PixPointer, @FFormatInfo, FPData.Palette);
+      Color32.Channels[ChannelId] := NewChannelValue;
+      FFormatInfo.SetPixel32(PixPointer, @FFormatInfo, FPData.Palette, Color32);
+
+      Inc(PixPointer, Bpp);
+    end;
+  end;
+end;
+
+procedure TImagingCanvas.FillChannelFP(ChannelId: Integer; NewChannelValue: Single);
+var
+  X, Y, Bpp: Integer;
+  PixPointer: PByte;
+  ColorFP: TColorFPRec;
+begin
+  Bpp := FFormatInfo.BytesPerPixel;
+
+  for Y := FClipRect.Top to FClipRect.Bottom - 1 do
+  begin
+    PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp];
+    for X := FClipRect.Left to FClipRect.Right - 1 do
+    begin
+      ColorFP := FFormatInfo.GetPixelFP(PixPointer, @FFormatInfo, FPData.Palette);
+      ColorFP.Channels[ChannelId] := NewChannelValue;
+      FFormatInfo.SetPixelFP(PixPointer, @FFormatInfo, FPData.Palette, ColorFP);
+
+      Inc(PixPointer, Bpp);
+    end;
+  end;
+end;
+
+class function TImagingCanvas.GetSupportedFormats: TImageFormats;
+begin
+  Result := [ifIndex8..Pred(ifDXT1)];
+end;
+
+{ TFastARGB32Canvas }
+
+destructor TFastARGB32Canvas.Destroy;
+begin
+  FreeMem(FScanlines);
+  inherited Destroy;
+end;
+
+procedure TFastARGB32Canvas.AlphaBlendPixels(SrcPix, DestPix: PColor32Rec);
+var
+  SrcAlpha, DestAlpha, FinalAlpha: Integer;
+begin
+  FinalAlpha := SrcPix.A + 1 + (DestPix.A * (256 - SrcPix.A)) shr 8;
+  if FinalAlpha = 0 then
+    SrcAlpha := 0
+  else
+    SrcAlpha := (SrcPix.A shl 8) div FinalAlpha;
+  DestAlpha := 256 - SrcAlpha;
+
+  DestPix.A := ClampToByte(FinalAlpha);
+  DestPix.R := (SrcPix.R * SrcAlpha + DestPix.R * DestAlpha) shr 8;
+  DestPix.G := (SrcPix.G * SrcAlpha + DestPix.G * DestAlpha) shr 8;
+  DestPix.B := (SrcPix.B * SrcAlpha + DestPix.B * DestAlpha) shr 8;
+end;
+
+procedure TFastARGB32Canvas.DrawAlpha(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; DestX, DestY: Integer);
+var
+  X, Y, SrcX, SrcY, Width, Height: Integer;
+  SrcPix, DestPix: PColor32Rec;
+begin
+  if DestCanvas.ClassType <> Self.ClassType then
+  begin
+    inherited;
+    Exit;
+  end;
+
+  SrcX := SrcRect.Left;
+  SrcY := SrcRect.Top;
+  Width := SrcRect.Right - SrcRect.Left;
+  Height := SrcRect.Bottom - SrcRect.Top;
+  ClipCopyBounds(SrcX, SrcY, Width, Height, DestX, DestY,
+    FPData.Width, FPData.Height, DestCanvas.ClipRect);
+
+  for Y := 0 to Height - 1 do
+  begin
+    SrcPix := @FScanlines[SrcY + Y, SrcX];
+    DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[DestY + Y, DestX];
+    for X := 0 to Width - 1 do
+    begin
+      AlphaBlendPixels(SrcPix, DestPix);
+      Inc(SrcPix);
+      Inc(DestPix);
+    end;
+  end;
+end;
+
+function TFastARGB32Canvas.GetPixel32(X, Y: LongInt): TColor32;
+begin
+  Result := FScanlines[Y, X].Color;
+end;
+
+procedure TFastARGB32Canvas.SetPixel32(X, Y: LongInt; const Value: TColor32);
+begin
+  if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and
+    (X < FClipRect.Right) and (Y < FClipRect.Bottom) then
+  begin
+    FScanlines[Y, X].Color := Value;
+  end;
+end;
+
+procedure TFastARGB32Canvas.StretchDrawAlpha(const SrcRect: TRect;
+  DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter);
+var
+  X, Y, ScaleX, ScaleY, Yp, Xp, Weight1, Weight2, Weight3, Weight4, InvFracY, T1, T2: Integer;
+  FracX, FracY: Cardinal;
+  SrcX, SrcY, SrcWidth, SrcHeight: Integer;
+  DestX, DestY, DestWidth, DestHeight: Integer;
+  SrcLine, SrcLine2: PColor32RecArray;
+  DestPix: PColor32Rec;
+  Accum: TColor32Rec;
+begin
+  if (Filter = rfBicubic) or (DestCanvas.ClassType <> Self.ClassType) then
+  begin
+    inherited;
+    Exit;
+  end;
+
+  SrcX := SrcRect.Left;
+  SrcY := SrcRect.Top;
+  SrcWidth := SrcRect.Right - SrcRect.Left;
+  SrcHeight := SrcRect.Bottom - SrcRect.Top;
+  DestX := DestRect.Left;
+  DestY := DestRect.Top;
+  DestWidth := DestRect.Right - DestRect.Left;
+  DestHeight := DestRect.Bottom - DestRect.Top;
+  // Clip src and dst rects
+  ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DestX, DestY, DestWidth, DestHeight,
+      FPData.Width, FPData.Height, DestCanvas.ClipRect);
+  ScaleX := (SrcWidth shl 16) div DestWidth;
+  ScaleY := (SrcHeight shl 16) div DestHeight;
+
+  // Nearest and linear filtering using fixed point math
+
+  if Filter = rfNearest then
+  begin
+    Yp := 0;
+    for Y := DestY to DestY + DestHeight - 1 do
+    begin
+      Xp := 0;
+      SrcLine := @FScanlines[SrcY + Yp shr 16, SrcX];
+      DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[Y, DestX];
+      for X := 0 to DestWidth - 1 do
+      begin
+        AlphaBlendPixels(@SrcLine[Xp shr 16], DestPix);
+        Inc(DestPix);
+        Inc(Xp, ScaleX);
+      end;
+      Inc(Yp, ScaleY);
+    end;
+  end
+  else
+  begin
+    Yp := (ScaleY shr 1) - $8000;
+    for Y := DestY to DestY + DestHeight - 1 do
+    begin
+      DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[Y, DestX];
+      if Yp < 0 then
+      begin
+        T1 := 0;
+        FracY := 0;
+        InvFracY := $10000;
+      end
+      else
+      begin
+        T1 := Yp shr 16;
+        FracY := Yp and $FFFF;
+        InvFracY := (not Yp and $FFFF) + 1;
+      end;
+
+      T2 := Iff(T1 < SrcHeight - 1, T1 + 1, T1);
+      SrcLine :=  @Scanlines[T1 + SrcY, SrcX];
+      SrcLine2 := @Scanlines[T2 + SrcY, SrcX];
+      Xp := (ScaleX shr 1) - $8000;
+
+      for X := 0 to DestWidth - 1 do
+      begin
+        if Xp < 0 then
+        begin
+          T1 := 0;
+          FracX := 0;
+        end
+        else
+        begin
+          T1 := Xp shr 16;
+          FracX := Xp and $FFFF;
+        end;
+
+        T2 := Iff(T1 < SrcWidth - 1, T1 + 1, T1);
+        Weight2:= Integer((Cardinal(InvFracY) * FracX) shr 16); // cast to Card, Int can overflow here
+        Weight1:= InvFracY - Weight2;
+        Weight4:= Integer((Cardinal(FracY) * FracX) shr 16);
+        Weight3:= FracY - Weight4;
+
+        Accum.B := (SrcLine[T1].B * Weight1 + SrcLine[T2].B * Weight2 +
+          SrcLine2[T1].B * Weight3 + SrcLine2[T2].B * Weight4 + $8000) shr 16;
+        Accum.G := (SrcLine[T1].G * Weight1 + SrcLine[T2].G * Weight2 +
+          SrcLine2[T1].G * Weight3 + SrcLine2[T2].G * Weight4 + $8000) shr 16;
+        Accum.R := (SrcLine[T1].R * Weight1 + SrcLine[T2].R * Weight2 +
+          SrcLine2[T1].R * Weight3 + SrcLine2[T2].R * Weight4 + $8000) shr 16;
+        Accum.A := (SrcLine[T1].A * Weight1 + SrcLine[T2].A * Weight2 +
+          SrcLine2[T1].A * Weight3 + SrcLine2[T2].A * Weight4 + $8000) shr 16;
+
+        AlphaBlendPixels(@Accum, DestPix);
+
+        Inc(Xp, ScaleX);
+        Inc(DestPix);
+      end;
+      Inc(Yp, ScaleY);
+     end;
+  end;
+end;
+
+procedure TFastARGB32Canvas.UpdateCanvasState;
+var
+  I: LongInt;
+  ScanPos: PLongWord;
+begin
+  inherited UpdateCanvasState;
+
+  // Realloc and update scanline array
+  ReallocMem(FScanlines, FPData.Height * SizeOf(PColor32RecArray));
+  ScanPos := FPData.Bits;
+
+  for I := 0 to FPData.Height - 1 do
+  begin
+    FScanlines[I] := PColor32RecArray(ScanPos);
+    Inc(ScanPos, FPData.Width);
+  end;
+end;
+
+class function TFastARGB32Canvas.GetSupportedFormats: TImageFormats;
+begin
+  Result := [ifA8R8G8B8];
+end;
+
+procedure TFastARGB32Canvas.InvertColors;
+var
+  X, Y: Integer;
+  PixPtr: PColor32Rec;
+begin
+  for Y := FClipRect.Top to FClipRect.Bottom - 1 do
+  begin
+    PixPtr := @FScanlines[Y, FClipRect.Left];
+    for X := FClipRect.Left to FClipRect.Right - 1 do
+    begin
+      PixPtr.R := not PixPtr.R;
+      PixPtr.G := not PixPtr.G;
+      PixPtr.B := not PixPtr.B;
+      Inc(PixPtr);
+    end;
+  end;
+end;
+
+initialization
+  RegisterCanvas(TFastARGB32Canvas);
+
+finalization
+  FreeAndNil(CanvasClasses);
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - more more more ...
+    - implement pen width everywhere
+    - more objects (arc, polygon)
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Fixed bug that could raise floating point error in DrawAlpha
+      and StretchDrawAlpha.
+    - Fixed bug in TImagingCanvas.Line that caused not drawing
+      of horz or vert lines.
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Added some methods to TFastARGB32Canvas (InvertColors, DrawAlpha/StretchDrawAlpha)
+    - Fixed DrawAlpha/StretchDrawAlpha destination alpha calculation.
+    - Added PremultiplyAlpha and UnPremultiplyAlpha methods.
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - Added FillChannel methods.
+    - Added FloodFill method.
+    - Added GetHistogram method.
+    - Fixed "Invalid FP operation" in AdjustColorLevels in FPC compiled exes
+      (thanks to Carlos González).
+    - Added TImagingCanvas.AdjustColorLevels method.
+
+  -- 0.25.0 Changes/Bug Fixes ---------------------------------
+    - Fixed error that could cause AV in linear and nonlinear filters.
+    - Added blended rect filling function FillRectBlend.
+    - Added drawing function with blending (DrawAlpha, StretchDrawAlpha,
+        StretchDrawAdd, DrawBlend, StretchDrawBlend, ...)
+    - Added non-linear filters (min, max, median).
+    - Added point transforms (invert, contrast, gamma, brightness).
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Added some new filter kernels for convolution.
+    - Added FillMode and PenMode properties.
+    - Added FrameRect, Rectangle, Ellipse, and Line methods.
+    - Removed HorzLine and VertLine from TFastARGB32Canvas - new versions
+      in general canvas is now as fast as those in TFastARGB32Canvas
+      (only in case of A8R8G8B8 images of course).
+    - Added PenWidth property, updated HorzLine and VertLine to use it.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - added TFastARGB32Canvas
+    - added convolutions, hline, vline
+    - unit created, intial stuff added
+
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingClasses.pas b/src/lib/vampimg/ImagingClasses.pas
new file mode 100644 (file)
index 0000000..b196fdd
--- /dev/null
@@ -0,0 +1,1091 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains class based wrapper to Imaging library.}
+unit ImagingClasses;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  Types, Classes, ImagingTypes, Imaging, ImagingFormats, ImagingUtility;
+
+type
+  { Base abstract high level class wrapper to low level Imaging structures and
+    functions.}
+  TBaseImage = class(TPersistent)
+  private
+    function GetEmpty: Boolean;
+  protected
+    FPData: PImageData;
+    FOnDataSizeChanged: TNotifyEvent;
+    FOnPixelsChanged: TNotifyEvent;
+    function GetFormat: TImageFormat; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetHeight: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetSize: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetWidth: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetBits: Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetPalette: PPalette32; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetPaletteEntries: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetScanline(Index: Integer): Pointer;
+    function GetPixelPointer(X, Y: Integer): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetScanlineSize: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetFormatInfo: TImageFormatInfo; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetBoundsRect: TRect;
+    procedure SetFormat(const Value: TImageFormat); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetHeight(const Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetWidth(const Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetPointer; virtual; abstract;
+    procedure DoDataSizeChanged; virtual;
+    procedure DoPixelsChanged; virtual;
+  public
+    constructor Create; virtual;
+    constructor CreateFromImage(AImage: TBaseImage);
+    destructor Destroy; override;
+    { Returns info about current image.}
+    function ToString: string; {$IF Defined(DCC) and (CompilerVersion >= 20.0)}override;{$IFEND}
+
+    { Creates a new image data with the given size and format. Old image
+      data is lost. Works only for the current image of TMultiImage.}
+    procedure RecreateImageData(AWidth, AHeight: Integer; AFormat: TImageFormat);
+    { Maps underlying image data to given TImageData record. Both TBaseImage and
+      TImageData now share some image memory (bits). So don't call FreeImage
+      on TImageData afterwards since this TBaseImage would get really broken.}
+    procedure MapImageData(const ImageData: TImageData);
+    { Deletes current image.}
+    procedure Clear;
+
+    { Resizes current image with optional resampling.}
+    procedure Resize(NewWidth, NewHeight: Integer; Filter: TResizeFilter);
+
+    procedure ResizeToFit(FitWidth, FitHeight: Integer; Filter: TResizeFilter; DstImage: TBaseImage);
+    { Flips current image. Reverses the image along its horizontal axis the top
+      becomes the bottom and vice versa.}
+    procedure Flip;
+    { Mirrors current image. Reverses the image along its vertical axis the left
+      side becomes the right and vice versa.}
+    procedure Mirror;
+    { Rotates image by Angle degrees counterclockwise.}
+    procedure Rotate(Angle: Single);
+    { Copies rectangular part of SrcImage to DstImage. No blending is performed -
+      alpha is simply copied to destination image. Operates also with
+      negative X and Y coordinates.
+      Note that copying is fastest for images in the same data format
+      (and slowest for images in special formats).}
+    procedure CopyTo(SrcX, SrcY, Width, Height: Integer; DstImage: TBaseImage; DstX, DstY: Integer);
+    { Stretches the contents of the source rectangle to the destination rectangle
+      with optional resampling. No blending is performed - alpha is
+      simply copied/resampled to destination image. Note that stretching is
+      fastest for images in the same data format (and slowest for
+      images in special formats).}
+    procedure StretchTo(SrcX, SrcY, SrcWidth, SrcHeight: Integer; DstImage: TBaseImage; DstX, DstY, DstWidth, DstHeight: Integer; Filter: TResizeFilter);
+    { Replaces pixels with OldPixel in the given rectangle by NewPixel.
+      OldPixel and NewPixel should point to the pixels in the same format
+      as the given image is in.}
+    procedure ReplaceColor(X, Y, Width, Height: Integer; OldColor, NewColor: Pointer);
+    { Swaps SrcChannel and DstChannel color or alpha channels of image.
+      Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to
+      identify channels.}
+    procedure SwapChannels(SrcChannel, DstChannel: Integer);
+
+    { Loads current image data from file.}
+    procedure LoadFromFile(const FileName: string); virtual;
+    { Loads current image data from stream.}
+    procedure LoadFromStream(Stream: TStream); virtual;
+
+    { Saves current image data to file.}
+    procedure SaveToFile(const FileName: string);
+    { Saves current image data to stream. Ext identifies desired image file
+      format (jpg, png, dds, ...)}
+    procedure SaveToStream(const Ext: string; Stream: TStream);
+
+    { Width of current image in pixels.}
+    property Width: Integer read GetWidth write SetWidth;
+    { Height of current image in pixels.}
+    property Height: Integer read GetHeight write SetHeight;
+    { Image data format of current image.}
+    property Format: TImageFormat read GetFormat write SetFormat;
+    { Size in bytes of current image's data.}
+    property Size: Integer read GetSize;
+    { Pointer to memory containing image bits.}
+    property Bits: Pointer read GetBits;
+    { Pointer to palette for indexed format images. It is nil for others.
+      Max palette entry is at index [PaletteEntries - 1].}
+    property Palette: PPalette32 read GetPalette;
+    { Number of entries in image's palette}
+    property PaletteEntries: Integer read GetPaletteEntries;
+    { Provides indexed access to each line of pixels. Does not work with special
+      format images (like DXT).}
+    property Scanline[Index: Integer]: Pointer read GetScanline;
+    { Returns pointer to image pixel at [X, Y] coordinates.}
+    property PixelPointer[X, Y: Integer]: Pointer read GetPixelPointer;
+    { Size/length of one image scanline in bytes.}
+    property ScanlineSize: Integer read GetScanlineSize;
+    { Extended image format information.}
+    property FormatInfo: TImageFormatInfo read GetFormatInfo;
+    { This gives complete access to underlying TImageData record.
+      It can be used in functions that take TImageData as parameter
+      (for example: ReduceColors(SingleImageInstance.ImageData^, 64)).}
+    property ImageDataPointer: PImageData read FPData;
+    { Indicates whether the current image is valid (proper format,
+      allowed dimensions, right size, ...).}
+    property Valid: Boolean read GetValid;
+    { Indicates whether image containst any data (size in bytes > 0).}
+    property Empty: Boolean read GetEmpty;
+    { Specifies the bounding rectangle of the image.}
+    property BoundsRect: TRect read GetBoundsRect;
+    { This event occurs when the image data size has just changed. That means
+      image width, height, or format has been changed.}
+    property OnDataSizeChanged: TNotifyEvent read FOnDataSizeChanged write FOnDataSizeChanged;
+    { This event occurs when some pixels of the image have just changed.}
+    property OnPixelsChanged: TNotifyEvent read FOnPixelsChanged write FOnPixelsChanged;
+  end;
+
+  { Extension of TBaseImage which uses single TImageData record to
+    store image. All methods inherited from TBaseImage work with this record.}
+  TSingleImage = class(TBaseImage)
+  protected
+    FImageData: TImageData;
+    procedure SetPointer; override;
+  public
+    constructor Create; override;
+    constructor CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault);
+    constructor CreateFromData(const AData: TImageData);
+    constructor CreateFromFile(const FileName: string);
+    constructor CreateFromStream(Stream: TStream);
+    destructor Destroy; override;
+    { Assigns single image from another single image or multi image.}
+    procedure Assign(Source: TPersistent); override;
+    { Assigns single image from image data record.}
+    procedure AssignFromImageData(const AImageData: TImageData);
+  end;
+
+  { Extension of TBaseImage which uses array of TImageData records to
+    store multiple images. Images are independent on each other and they don't
+    share any common characteristic. Each can have different size, format, and
+    palette. All methods inherited from TBaseImage work only with
+    active image (it could represent mipmap level, animation frame, or whatever).
+    Methods whose names contain word 'Multi' work with all images in array
+    (as well as other methods with obvious names).}
+  TMultiImage = class(TBaseImage)
+  protected
+    FDataArray: TDynImageDataArray;
+    FActiveImage: Integer;
+    procedure SetActiveImage(Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetImageCount: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetImageCount(Value: Integer);
+    function GetAllImagesValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    function GetImage(Index: Integer): TImageData; {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetImage(Index: Integer; Value: TImageData); {$IFDEF USE_INLINE}inline;{$ENDIF}
+    procedure SetPointer; override;
+    function PrepareInsert(Index, Count: Integer): Boolean;
+    procedure DoInsertImages(Index: Integer; const Images: TDynImageDataArray);
+    procedure DoInsertNew(Index: Integer; AWidth, AHeight: Integer; AFormat: TImageFormat);
+  public
+    constructor Create; override;
+    constructor CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat; ImageCount: Integer);
+    constructor CreateFromArray(const ADataArray: TDynImageDataArray);
+    constructor CreateFromFile(const FileName: string);
+    constructor CreateFromStream(Stream: TStream);
+    destructor Destroy; override;
+    { Assigns multi image from another multi image or single image.}
+    procedure Assign(Source: TPersistent); override;
+    { Assigns multi image from array of image data records.}
+    procedure AssignFromArray(const ADataArray: TDynImageDataArray);
+
+    { Adds new image at the end of the image array. }
+    function AddImage(AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault): Integer; overload;
+    { Adds existing image at the end of the image array. }
+    function AddImage(const Image: TImageData): Integer; overload;
+    { Adds existing image (Active image of a TmultiImage)
+      at the end of the image array. }
+    function AddImage(Image: TBaseImage): Integer; overload;
+    { Adds existing image array ((all images of a multi image))
+      at the end of the image array. }
+    procedure AddImages(const Images: TDynImageDataArray); overload;
+    { Adds existing MultiImage images at the end of the image array. }
+    procedure AddImages(Images: TMultiImage); overload;
+
+    { Inserts new image image at the given position in the image array. }
+    procedure InsertImage(Index, AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault); overload;
+    { Inserts existing image at the given position in the image array. }
+    procedure InsertImage(Index: Integer; const Image: TImageData); overload;
+    { Inserts existing image (Active image of a TmultiImage)
+      at the given position in the image array. }
+    procedure InsertImage(Index: Integer; Image: TBaseImage); overload;
+    { Inserts existing image at the given position in the image array. }
+    procedure InsertImages(Index: Integer; const Images: TDynImageDataArray); overload;
+    { Inserts existing images (all images of a TmultiImage) at
+      the given position in the image array. }
+    procedure InsertImages(Index: Integer; Images: TMultiImage); overload;
+
+    { Exchanges two images at the given positions in the image array. }
+    procedure ExchangeImages(Index1, Index2: Integer);
+    { Deletes image at the given position in the image array.}
+    procedure DeleteImage(Index: Integer);
+    { Rearranges images so that the first image will become last and vice versa.}
+    procedure ReverseImages;
+    { Deletes all images.}
+    procedure ClearAll;
+
+    { Converts all images to another image data format.}
+    procedure ConvertImages(Format: TImageFormat);
+    { Resizes all images.}
+    procedure ResizeImages(NewWidth, NewHeight: Integer; Filter: TResizeFilter);
+
+    { Overloaded loading method that will add new image to multiimage if
+      image array is empty bero loading. }
+    procedure LoadFromFile(const FileName: string); override;
+    { Overloaded loading method that will add new image to multiimage if
+      image array is empty bero loading. }
+    procedure LoadFromStream(Stream: TStream); override;
+
+    { Loads whole multi image from file.}
+    procedure LoadMultiFromFile(const FileName: string);
+    { Loads whole multi image from stream.}
+    procedure LoadMultiFromStream(Stream: TStream);
+    { Saves whole multi image to file.}
+    procedure SaveMultiToFile(const FileName: string);
+    { Saves whole multi image to stream. Ext identifies desired
+      image file format (jpg, png, dds, ...).}
+    procedure SaveMultiToStream(const Ext: string; Stream: TStream);
+
+    { Indicates active image of this multi image. All methods inherited
+      from TBaseImage operate on this image only.}
+    property ActiveImage: Integer read FActiveImage write SetActiveImage;
+    { Number of images of this multi image.}
+    property ImageCount: Integer read GetImageCount write SetImageCount;
+    { This value is True if all images of this TMultiImage are valid.}
+    property AllImagesValid: Boolean read GetAllImagesValid;
+    { This gives complete access to underlying TDynImageDataArray.
+      It can be used in functions that take TDynImageDataArray
+      as parameter.}
+    property DataArray: TDynImageDataArray read FDataArray;
+    { Array property for accessing individual images of TMultiImage. When you
+      set image at given index the old image is freed and the source is cloned.}
+    property Images[Index: Integer]: TImageData read GetImage write SetImage; default;
+  end;
+
+implementation
+
+const
+  DefaultWidth = 16;
+  Defaultheight = 16;
+
+function GetArrayFromImageData(const ImageData: TImageData): TDynImageDataArray;
+begin
+  SetLength(Result, 1);
+  Result[0] := ImageData;
+end;
+
+{ TBaseImage class implementation }
+
+constructor TBaseImage.Create;
+begin
+  SetPointer;
+end;
+
+constructor TBaseImage.CreateFromImage(AImage: TBaseImage);
+begin
+  Create;
+  Assign(AImage);
+end;
+
+destructor TBaseImage.Destroy;
+begin
+  inherited Destroy;
+end;
+
+function TBaseImage.GetWidth: Integer;
+begin
+  if Valid then
+    Result := FPData.Width
+  else
+    Result := 0;
+end;
+
+function TBaseImage.GetHeight: Integer;
+begin
+  if Valid then
+    Result := FPData.Height
+  else
+    Result := 0;
+end;
+
+function TBaseImage.GetFormat: TImageFormat;
+begin
+  if Valid then
+    Result := FPData.Format
+  else
+    Result := ifUnknown;
+end;
+
+function TBaseImage.GetScanline(Index: Integer): Pointer;
+var
+  Info: TImageFormatInfo;
+begin
+  if Valid then
+  begin
+    Info := GetFormatInfo;
+    if not Info.IsSpecial then
+      Result := ImagingFormats.GetScanLine(FPData.Bits, Info, FPData.Width, Index)
+    else
+      Result := FPData.Bits;
+  end
+  else
+    Result := nil;
+end;
+
+function TBaseImage.GetScanlineSize: Integer;
+begin
+  if Valid then
+    Result := FormatInfo.GetPixelsSize(Format, Width, 1)
+  else
+    Result := 0;
+end;
+
+function TBaseImage.GetPixelPointer(X, Y: Integer): Pointer;
+begin
+  if Valid then
+    Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * GetFormatInfo.BytesPerPixel]
+  else
+    Result := nil;
+end;
+
+function TBaseImage.GetSize: Integer;
+begin
+  if Valid then
+    Result := FPData.Size
+  else
+    Result := 0;
+end;
+
+function TBaseImage.GetBits: Pointer;
+begin
+  if Valid then
+    Result := FPData.Bits
+  else
+    Result := nil;
+end;
+
+function TBaseImage.GetPalette: PPalette32;
+begin
+  if Valid then
+    Result := FPData.Palette
+  else
+    Result := nil;
+end;
+
+function TBaseImage.GetPaletteEntries: Integer;
+begin
+  Result := GetFormatInfo.PaletteEntries;
+end;
+
+function TBaseImage.GetFormatInfo: TImageFormatInfo;
+begin
+  if Valid then
+    Imaging.GetImageFormatInfo(FPData.Format, Result)
+  else
+    FillChar(Result, SizeOf(Result), 0);
+end;
+
+function TBaseImage.GetValid: Boolean;
+begin
+  Result := Assigned(FPData) and Imaging.TestImage(FPData^);
+end;
+
+function TBaseImage.GetBoundsRect: TRect;
+begin
+  Result := Rect(0, 0, GetWidth, GetHeight);
+end;
+
+function TBaseImage.GetEmpty: Boolean;
+begin
+  Result := FPData.Size = 0;
+end;
+
+procedure TBaseImage.SetWidth(const Value: Integer);
+begin
+  Resize(Value, GetHeight, rfNearest);
+end;
+
+procedure TBaseImage.SetHeight(const Value: Integer);
+begin
+  Resize(GetWidth, Value, rfNearest);
+end;
+
+procedure TBaseImage.SetFormat(const Value: TImageFormat);
+begin
+  if Valid and Imaging.ConvertImage(FPData^, Value) then
+    DoDataSizeChanged;
+end;
+
+procedure TBaseImage.DoDataSizeChanged;
+begin
+  if Assigned(FOnDataSizeChanged) then
+    FOnDataSizeChanged(Self);
+  DoPixelsChanged;
+end;
+
+procedure TBaseImage.DoPixelsChanged;
+begin
+  if Assigned(FOnPixelsChanged) then
+    FOnPixelsChanged(Self);
+end;
+
+procedure TBaseImage.RecreateImageData(AWidth, AHeight: Integer; AFormat: TImageFormat);
+begin
+  if Assigned(FPData) and Imaging.NewImage(AWidth, AHeight, AFormat, FPData^) then
+    DoDataSizeChanged;
+end;
+
+procedure TBaseImage.MapImageData(const ImageData: TImageData);
+begin
+  Clear;
+  FPData.Width := ImageData.Width;
+  FPData.Height := ImageData.Height;
+  FPData.Format := ImageData.Format;
+  FPData.Size := ImageData.Size;
+  FPData.Bits := ImageData.Bits;
+  FPData.Palette := ImageData.Palette;
+end;
+
+procedure TBaseImage.Clear;
+begin
+  FreeImage(FPData^);
+end;
+
+procedure TBaseImage.Resize(NewWidth, NewHeight: Integer; Filter: TResizeFilter);
+begin
+  if Valid and Imaging.ResizeImage(FPData^, NewWidth, NewHeight, Filter) then
+    DoDataSizeChanged;
+end;
+
+procedure TBaseImage.ResizeToFit(FitWidth, FitHeight: Integer;
+  Filter: TResizeFilter; DstImage: TBaseImage);
+begin
+  if Valid and Assigned(DstImage) then
+  begin
+    Imaging.ResizeImageToFit(FPData^, FitWidth, FitHeight, Filter,
+      DstImage.FPData^);
+    DstImage.DoDataSizeChanged;
+  end;
+end;
+
+procedure TBaseImage.Flip;
+begin
+  if Valid and Imaging.FlipImage(FPData^) then
+    DoPixelsChanged;
+end;
+
+procedure TBaseImage.Mirror;
+begin
+  if Valid and Imaging.MirrorImage(FPData^) then
+    DoPixelsChanged;
+end;
+
+procedure TBaseImage.Rotate(Angle: Single);
+begin
+  if Valid then
+  begin
+    Imaging.RotateImage(FPData^, Angle);
+    DoPixelsChanged;
+  end;
+end;
+
+procedure TBaseImage.CopyTo(SrcX, SrcY, Width, Height: Integer;
+  DstImage: TBaseImage; DstX, DstY: Integer);
+begin
+  if Valid and Assigned(DstImage) and DstImage.Valid then
+  begin
+    Imaging.CopyRect(FPData^, SrcX, SrcY, Width, Height, DstImage.FPData^, DstX, DstY);
+    DstImage.DoPixelsChanged;
+  end;
+end;
+
+procedure TBaseImage.StretchTo(SrcX, SrcY, SrcWidth, SrcHeight: Integer;
+  DstImage: TBaseImage; DstX, DstY, DstWidth, DstHeight: Integer; Filter: TResizeFilter);
+begin
+  if Valid and Assigned(DstImage) and DstImage.Valid then
+  begin
+    Imaging.StretchRect(FPData^, SrcX, SrcY, SrcWidth, SrcHeight,
+      DstImage.FPData^, DstX, DstY, DstWidth, DstHeight, Filter);
+    DstImage.DoPixelsChanged;
+  end;
+end;
+
+procedure TBaseImage.ReplaceColor(X, Y, Width, Height: Integer; OldColor,
+  NewColor: Pointer);
+begin
+  if Valid then
+  begin
+    Imaging.ReplaceColor(FPData^, X, Y, Width, Height, OldColor, NewColor);
+    DoPixelsChanged;
+  end;
+end;
+
+procedure TBaseImage.SwapChannels(SrcChannel, DstChannel: Integer);
+begin
+  if Valid then
+  begin
+    Imaging.SwapChannels(FPData^, SrcChannel, DstChannel);
+    DoPixelsChanged;
+  end;
+end;
+
+function TBaseImage.ToString: string;
+begin
+  Result := Iff(Valid, Imaging.ImageToStr(FPData^), 'empty image');
+end;
+
+procedure TBaseImage.LoadFromFile(const FileName: string);
+begin
+  if Assigned(FPData) and Imaging.LoadImageFromFile(FileName, FPData^) then
+    DoDataSizeChanged;
+end;
+
+procedure TBaseImage.LoadFromStream(Stream: TStream);
+begin
+  if Assigned(FPData) and Imaging.LoadImageFromStream(Stream, FPData^) then
+    DoDataSizeChanged;
+end;
+
+procedure TBaseImage.SaveToFile(const FileName: string);
+begin
+  if Valid then
+    Imaging.SaveImageToFile(FileName, FPData^);
+end;
+
+procedure TBaseImage.SaveToStream(const Ext: string; Stream: TStream);
+begin
+  if Valid then
+    Imaging.SaveImageToStream(Ext, Stream, FPData^);
+end;
+
+
+{ TSingleImage class implementation }
+
+constructor TSingleImage.Create;
+begin
+  inherited Create;
+  Clear;
+end;
+
+constructor TSingleImage.CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat);
+begin
+  inherited Create;
+  RecreateImageData(AWidth, AHeight, AFormat);
+end;
+
+constructor TSingleImage.CreateFromData(const AData: TImageData);
+begin
+  inherited Create;
+  AssignFromImageData(AData);
+end;
+
+constructor TSingleImage.CreateFromFile(const FileName: string);
+begin
+  inherited Create;
+  LoadFromFile(FileName);
+end;
+
+constructor TSingleImage.CreateFromStream(Stream: TStream);
+begin
+  inherited Create;
+  LoadFromStream(Stream);
+end;
+
+destructor TSingleImage.Destroy;
+begin
+  Imaging.FreeImage(FImageData);
+  inherited Destroy;
+end;
+
+procedure TSingleImage.SetPointer;
+begin
+  FPData := @FImageData;
+end;
+
+procedure TSingleImage.Assign(Source: TPersistent);
+begin
+  if Source = nil then
+  begin
+    Clear;
+  end
+  else if Source is TSingleImage then
+  begin
+    AssignFromImageData(TSingleImage(Source).FImageData);
+  end
+  else if Source is TMultiImage then
+  begin
+    if TMultiImage(Source).Valid then
+      AssignFromImageData(TMultiImage(Source).FPData^)
+    else
+      Clear;
+  end
+  else
+    inherited Assign(Source);
+end;
+
+procedure TSingleImage.AssignFromImageData(const AImageData: TImageData);
+begin
+  if Imaging.TestImage(AImageData) then
+  begin
+    Imaging.CloneImage(AImageData, FImageData);
+    DoDataSizeChanged;
+  end
+  else
+    Clear;
+end;
+
+{ TMultiImage class implementation }
+
+constructor TMultiImage.Create;
+begin
+  inherited Create;
+end;
+
+constructor TMultiImage.CreateFromParams(AWidth, AHeight: Integer;
+  AFormat: TImageFormat; ImageCount: Integer);
+var
+  I: Integer;
+begin
+  Imaging.FreeImagesInArray(FDataArray);
+  SetLength(FDataArray, ImageCount);
+  for I := 0 to GetImageCount - 1 do
+    Imaging.NewImage(AWidth, AHeight, AFormat, FDataArray[I]);
+  if GetImageCount > 0 then
+    SetActiveImage(0);
+end;
+
+constructor TMultiImage.CreateFromArray(const ADataArray: TDynImageDataArray);
+begin
+  AssignFromArray(ADataArray);
+end;
+
+constructor TMultiImage.CreateFromFile(const FileName: string);
+begin
+  LoadMultiFromFile(FileName);
+end;
+
+constructor TMultiImage.CreateFromStream(Stream: TStream);
+begin
+  LoadMultiFromStream(Stream);
+end;
+
+destructor TMultiImage.Destroy;
+begin
+  Imaging.FreeImagesInArray(FDataArray);
+  inherited Destroy;
+end;
+
+procedure TMultiImage.SetActiveImage(Value: Integer);
+begin
+  FActiveImage := Value;
+  SetPointer;
+end;
+
+function TMultiImage.GetImageCount: Integer;
+begin
+  Result := Length(FDataArray);
+end;
+
+procedure TMultiImage.SetImageCount(Value: Integer);
+var
+  I, OldCount: Integer;
+begin
+  if Value > GetImageCount then
+  begin
+    // Create new empty images if array will be enlarged
+    OldCount := GetImageCount;
+    SetLength(FDataArray, Value);
+    for I := OldCount to Value - 1 do
+      Imaging.NewImage(DefaultWidth, DefaultHeight, ifDefault, FDataArray[I]);
+  end
+  else
+  begin
+    // Free images that exceed desired count and shrink array
+    for I := Value to GetImageCount - 1 do
+      Imaging.FreeImage(FDataArray[I]);
+    SetLength(FDataArray, Value);
+  end;
+  SetPointer;
+end;
+
+function TMultiImage.GetAllImagesValid: Boolean;
+begin
+  Result := (GetImageCount > 0) and TestImagesInArray(FDataArray);
+end;
+
+function TMultiImage.GetImage(Index: Integer): TImageData;
+begin
+  if (Index >= 0) and (Index < GetImageCount) then
+    Result := FDataArray[Index];
+end;
+
+procedure TMultiImage.SetImage(Index: Integer; Value: TImageData);
+begin
+  if (Index >= 0) and (Index < GetImageCount) then
+    Imaging.CloneImage(Value, FDataArray[Index]);
+end;
+
+procedure TMultiImage.SetPointer;
+begin
+  if GetImageCount > 0 then
+  begin
+    FActiveImage := ClampInt(FActiveImage, 0, GetImageCount - 1);
+    FPData := @FDataArray[FActiveImage];
+  end
+  else
+  begin
+    FActiveImage := -1;
+    FPData := nil
+  end;
+end;
+
+function TMultiImage.PrepareInsert(Index, Count: Integer): Boolean;
+var
+  I: Integer;
+begin
+  // Inserting to empty image will add image at index 0
+  if GetImageCount = 0 then
+    Index := 0;
+
+  if (Index >= 0) and (Index <= GetImageCount) and (Count > 0) then
+  begin
+    SetLength(FDataArray, GetImageCount + Count);
+    if Index < GetImageCount - 1 then
+    begin
+      // Move imges to new position
+      System.Move(FDataArray[Index], FDataArray[Index + Count],
+        (GetImageCount - Count - Index) * SizeOf(TImageData));
+      // Null old images, not free them!
+      for I := Index to Index + Count - 1 do
+        InitImage(FDataArray[I]);
+    end;
+    Result := True;
+  end
+  else
+    Result := False;
+end;
+
+procedure TMultiImage.DoInsertImages(Index: Integer; const Images: TDynImageDataArray);
+var
+  I, Len: Integer;
+begin
+  Len := Length(Images);
+  if PrepareInsert(Index, Len) then
+  begin
+    for I := 0 to Len - 1 do
+      Imaging.CloneImage(Images[I], FDataArray[Index + I]);
+  end;
+end;
+
+procedure TMultiImage.DoInsertNew(Index, AWidth, AHeight: Integer;
+  AFormat: TImageFormat);
+begin
+  if PrepareInsert(Index, 1) then
+    Imaging.NewImage(AWidth, AHeight, AFormat, FDataArray[Index]);
+end;
+
+procedure TMultiImage.Assign(Source: TPersistent);
+var
+  Arr: TDynImageDataArray;
+begin
+  if Source = nil then
+  begin
+    ClearAll;
+  end
+  else if Source is TMultiImage then
+  begin
+    AssignFromArray(TMultiImage(Source).FDataArray);
+    SetActiveImage(TMultiImage(Source).ActiveImage);
+  end
+  else if Source is TSingleImage then
+  begin
+    SetLength(Arr, 1);
+    Arr[0] := TSingleImage(Source).FImageData;
+    AssignFromArray(Arr);
+  end
+  else
+    inherited Assign(Source);
+end;
+
+procedure TMultiImage.AssignFromArray(const ADataArray: TDynImageDataArray);
+var
+  I: Integer;
+begin
+  Imaging.FreeImagesInArray(FDataArray);
+  SetLength(FDataArray, Length(ADataArray));
+  for I := 0 to GetImageCount - 1 do
+  begin
+    // Clone only valid images
+    if Imaging.TestImage(ADataArray[I]) then
+      Imaging.CloneImage(ADataArray[I], FDataArray[I])
+    else
+      Imaging.NewImage(DefaultWidth, DefaultHeight, ifDefault, FDataArray[I]);
+  end;
+  if GetImageCount > 0 then
+    SetActiveImage(0);
+end;
+
+function TMultiImage.AddImage(AWidth, AHeight: Integer; AFormat: TImageFormat): Integer;
+begin
+  Result := GetImageCount;
+  DoInsertNew(Result, AWidth, AHeight, AFormat);
+end;
+
+function TMultiImage.AddImage(const Image: TImageData): Integer;
+begin
+  Result := GetImageCount;
+  DoInsertImages(Result, GetArrayFromImageData(Image));
+end;
+
+function TMultiImage.AddImage(Image: TBaseImage): Integer;
+begin
+  if Assigned(Image) and Image.Valid then
+  begin
+    Result := GetImageCount;
+    DoInsertImages(Result, GetArrayFromImageData(Image.FPData^));
+  end
+  else
+    Result := -1;
+end;
+
+procedure TMultiImage.AddImages(const Images: TDynImageDataArray);
+begin
+  DoInsertImages(GetImageCount, Images);
+end;
+
+procedure TMultiImage.AddImages(Images: TMultiImage);
+begin
+  DoInsertImages(GetImageCount, Images.FDataArray);
+end;
+
+procedure TMultiImage.InsertImage(Index, AWidth, AHeight: Integer;
+  AFormat: TImageFormat);
+begin
+  DoInsertNew(Index, AWidth, AHeight, AFormat);
+end;
+
+procedure TMultiImage.InsertImage(Index: Integer; const Image: TImageData);
+begin
+  DoInsertImages(Index, GetArrayFromImageData(Image));
+end;
+
+procedure TMultiImage.InsertImage(Index: Integer; Image: TBaseImage);
+begin
+  if Assigned(Image) and Image.Valid then
+    DoInsertImages(Index, GetArrayFromImageData(Image.FPData^));
+end;
+
+procedure TMultiImage.InsertImages(Index: Integer;
+  const Images: TDynImageDataArray);
+begin
+  DoInsertImages(Index, FDataArray);
+end;
+
+procedure TMultiImage.InsertImages(Index: Integer; Images: TMultiImage);
+begin
+  DoInsertImages(Index, Images.FDataArray);
+end;
+
+procedure TMultiImage.ExchangeImages(Index1, Index2: Integer);
+var
+  TempData: TImageData;
+begin
+  if (Index1 >= 0) and (Index1 < GetImageCount) and
+     (Index2 >= 0) and (Index2 < GetImageCount) then
+  begin
+    TempData := FDataArray[Index1];
+    FDataArray[Index1] := FDataArray[Index2];
+    FDataArray[Index2] := TempData;
+  end;
+end;
+
+procedure TMultiImage.DeleteImage(Index: Integer);
+var
+  I: Integer;
+begin
+  if (Index >= 0) and (Index < GetImageCount) then
+  begin
+    // Free image at index to be deleted
+    Imaging.FreeImage(FDataArray[Index]);
+    if Index < GetImageCount - 1 then
+    begin
+      // Move images to new indices if necessary
+      for I := Index to GetImageCount - 2 do
+        FDataArray[I] := FDataArray[I + 1];
+    end;
+    // Set new array length and update pointer to active image
+    SetLength(FDataArray, GetImageCount - 1);
+    SetPointer;
+  end;
+end;
+
+procedure TMultiImage.ClearAll;
+begin
+  ImageCount := 0;
+end;
+
+procedure TMultiImage.ConvertImages(Format: TImageFormat);
+var
+  I: Integer;
+begin
+  for I := 0 to GetImageCount - 1 do
+    Imaging.ConvertImage(FDataArray[I], Format);
+end;
+
+procedure TMultiImage.ResizeImages(NewWidth, NewHeight: Integer;
+  Filter: TResizeFilter);
+var
+  I: Integer;
+begin
+  for I := 0 to GetImageCount - 1 do
+    Imaging.ResizeImage(FDataArray[I], NewWidth, NewHeight, Filter);
+end;
+
+procedure TMultiImage.ReverseImages;
+var
+  I: Integer;
+begin
+  for I := 0 to GetImageCount div 2 do
+    ExchangeImages(I, GetImageCount - 1 - I);
+end;
+
+procedure TMultiImage.LoadFromFile(const FileName: string);
+begin
+  if GetImageCount = 0 then
+    ImageCount := 1;
+  inherited LoadFromFile(FileName);
+end;
+
+procedure TMultiImage.LoadFromStream(Stream: TStream);
+begin
+  if GetImageCount = 0 then
+    ImageCount := 1;
+  inherited LoadFromStream(Stream);
+end;
+
+procedure TMultiImage.LoadMultiFromFile(const FileName: string);
+begin
+  Imaging.LoadMultiImageFromFile(FileName, FDataArray);
+  SetActiveImage(0);
+end;
+
+procedure TMultiImage.LoadMultiFromStream(Stream: TStream);
+begin
+  Imaging.LoadMultiImageFromStream(Stream, FDataArray);
+  SetActiveImage(0);
+end;
+
+procedure TMultiImage.SaveMultiToFile(const FileName: string);
+begin
+  Imaging.SaveMultiImageToFile(FileName, FDataArray);
+end;
+
+procedure TMultiImage.SaveMultiToStream(const Ext: string; Stream: TStream);
+begin
+  Imaging.SaveMultiImageToStream(Ext, Stream, FDataArray);
+end;
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 ---------------------------------------------------
+    - Added TSingleImage.AssignFromData and TMultiImage.AssigntFromArray
+      as a replacement for constructors used as methods (that is
+      compiler error in Delphi XE3).
+    - Added TBaseImage.ResizeToFit method.
+    - Changed TMultiImage to have default state with no images.
+    - TMultiImage.AddImage now returns index of newly added image.
+    - Fixed img index bug in TMultiImage.ResizeImages
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Added MapImageData method to TBaseImage
+    - Added Empty property to TBaseImage.
+    - Added Clear method to TBaseImage.
+    - Added ScanlineSize property to TBaseImage.
+
+  -- 0.24.3 Changes/Bug Fixes ---------------------------------
+    - Added TMultiImage.ReverseImages method.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added SwapChannels method to TBaseImage.
+    - Added ReplaceColor method to TBaseImage.
+    - Added ToString method to TBaseImage.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Inserting images to empty MultiImage will act as Add method.
+    - MultiImages with empty arrays will now create one image when
+      LoadFromFile or LoadFromStream is called.
+    - Fixed bug that caused AVs when getting props like Width, Height, asn Size
+      and when inlining was off. There was call to Iff but with inlining disabled
+      params like FPData.Size were evaluated and when FPData was nil => AV.
+    - Added many FPData validity checks to many methods. There were AVs
+      when calling most methods on empty TMultiImage.
+    - Added AllImagesValid property to TMultiImage.
+    - Fixed memory leak in TMultiImage.CreateFromParams.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - added ResizeImages method to TMultiImage
+    - removed Ext parameter from various LoadFromStream methods, no
+      longer needed
+    - fixed various issues concerning ActiveImage of TMultiImage
+      (it pointed to invalid location after some operations)
+    - most of property set/get methods are now inline
+    - added PixelPointers property to TBaseImage
+    - added Images default array property to TMultiImage
+    - renamed methods in TMultiImage to contain 'Image' instead of 'Level'
+    - added canvas support
+    - added OnDataSizeChanged and OnPixelsChanged event to TBaseImage
+    - renamed TSingleImage.NewImage to RecreateImageData, made public, and
+      moved to TBaseImage
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - added props PaletteEntries and ScanLine to TBaseImage
+    - aded new constructor to TBaseImage that take TBaseImage source
+    - TMultiImage levels adding and inserting rewritten internally
+    - added some new functions to TMultiImage: AddLevels, InsertLevels
+    - added some new functions to TBaseImage: Flip, Mirror, Rotate,
+      CopyRect, StretchRect
+    - TBasicImage.Resize has now filter parameter
+    - new stuff added to TMultiImage (DataArray prop, ConvertLevels)
+
+  -- 0.13 Changes/Bug Fixes -----------------------------------
+    - added AddLevel, InsertLevel, ExchangeLevels and DeleteLevel
+      methods to TMultiImage
+    - added TBaseImage, TSingleImage and TMultiImage with initial
+      members
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingColors.pas b/src/lib/vampimg/ImagingColors.pas
new file mode 100644 (file)
index 0000000..c7fd428
--- /dev/null
@@ -0,0 +1,246 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains functions for manipulating and converting color values.}
+unit ImagingColors;
+
+interface
+
+{$I ImagingOptions.inc}
+
+uses
+  SysUtils, ImagingTypes, ImagingUtility;
+
+{ Converts RGB color to YUV.}
+procedure RGBToYUV(R, G, B: Byte; var Y, U, V: Byte);
+{ Converts YIV to RGB color.}
+procedure YUVToRGB(Y, U, V: Byte; var R, G, B: Byte);
+
+{ Converts RGB color to YCbCr as used in JPEG.}
+procedure RGBToYCbCr(R, G, B: Byte; var Y, Cb, Cr: Byte);
+{ Converts YCbCr as used in JPEG to RGB color.}
+procedure YCbCrToRGB(Y, Cb, Cr: Byte; var R, G, B: Byte);
+{ Converts RGB color to YCbCr as used in JPEG.}
+procedure RGBToYCbCr16(R, G, B: Word; var Y, Cb, Cr: Word);
+{ Converts YCbCr as used in JPEG to RGB color.}
+procedure YCbCrToRGB16(Y, Cb, Cr: Word; var R, G, B: Word);
+
+{ Converts RGB color to CMY.}
+procedure RGBToCMY(R, G, B: Byte; var C, M, Y: Byte);
+{ Converts CMY to RGB color.}
+procedure CMYToRGB(C, M, Y: Byte; var R, G, B: Byte);
+{ Converts RGB color to CMY.}
+procedure RGBToCMY16(R, G, B: Word; var C, M, Y: Word);
+{ Converts CMY to RGB color.}
+procedure CMYToRGB16(C, M, Y: Word; var R, G, B: Word);
+
+{ Converts RGB color to CMYK.}
+procedure RGBToCMYK(R, G, B: Byte; var C, M, Y, K: Byte);
+{ Converts CMYK to RGB color.}
+procedure CMYKToRGB(C, M, Y, K: Byte; var R, G, B: Byte);
+{ Converts RGB color to CMYK.}
+procedure RGBToCMYK16(R, G, B: Word; var C, M, Y, K: Word);
+{ Converts CMYK to RGB color.}
+procedure CMYKToRGB16(C, M, Y, K: Word; var R, G, B: Word);
+
+{ Converts RGB color to YCoCg.}
+procedure RGBToYCoCg(R, G, B: Byte; var Y, Co, Cg: Byte);
+{ Converts YCoCg to RGB color.}
+procedure YCoCgToRGB(Y, Co, Cg: Byte; var R, G, B: Byte);
+
+//procedure RGBToHSL(R, G, B: Byte; var H, S, L: Byte);
+//procedure HSLToRGB(H, S, L: Byte; var R, G, B: Byte);
+
+implementation
+
+procedure RGBToYUV(R, G, B: Byte; var Y, U, V: Byte);
+begin
+  Y := ClampToByte(Round( 0.257 * R + 0.504 * G + 0.098 * B) + 16);
+  V := ClampToByte(Round( 0.439 * R - 0.368 * G - 0.071 * B) + 128);
+  U := ClampToByte(Round(-0.148 * R - 0.291 * G + 0.439 * B) + 128);
+end;
+
+procedure YUVToRGB(Y, U, V: Byte; var R, G, B: Byte);
+var
+  CY, CU, CV: LongInt;
+begin
+  CY := Y - 16;
+  CU := U - 128;
+  CV := V - 128;
+  R := ClampToByte(Round(1.164 * CY - 0.002 * CU + 1.596 * CV));
+  G := ClampToByte(Round(1.164 * CY - 0.391 * CU - 0.813 * CV));
+  B := ClampToByte(Round(1.164 * CY + 2.018 * CU - 0.001 * CV));
+end;
+
+procedure RGBToYCbCr(R, G, B: Byte; var Y, Cb, Cr: Byte);
+begin
+  Y  := ClampToByte(Round( 0.29900 * R + 0.58700 * G + 0.11400 * B));
+  Cb := ClampToByte(Round(-0.16874 * R - 0.33126 * G + 0.50000 * B  + 128));
+  Cr := ClampToByte(Round( 0.50000 * R - 0.41869 * G - 0.08131 * B  + 128));
+end;
+
+procedure YCbCrToRGB(Y, Cb, Cr: Byte; var R, G, B: Byte);
+begin
+  R := ClampToByte(Round(Y                        + 1.40200 * (Cr - 128)));
+  G := ClampToByte(Round(Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128)));
+  B := ClampToByte(Round(Y + 1.77200 * (Cb - 128)));
+end;
+
+procedure RGBToYCbCr16(R, G, B: Word; var Y, Cb, Cr: Word);
+begin
+  Y  := ClampToWord(Round( 0.29900 * R + 0.58700 * G + 0.11400 * B));
+  Cb := ClampToWord(Round(-0.16874 * R - 0.33126 * G + 0.50000 * B  + 32768));
+  Cr := ClampToWord(Round( 0.50000 * R - 0.41869 * G - 0.08131 * B  + 32768));
+end;
+
+procedure YCbCrToRGB16(Y, Cb, Cr: Word; var R, G, B: Word);
+begin
+  R := ClampToWord(Round(Y                          + 1.40200 * (Cr - 32768)));
+  G := ClampToWord(Round(Y - 0.34414 * (Cb - 32768) - 0.71414 * (Cr - 32768)));
+  B := ClampToWord(Round(Y + 1.77200 * (Cb - 32768)));
+end;
+
+procedure RGBToCMY(R, G, B: Byte; var C, M, Y: Byte);
+begin
+  C := 255 - R;
+  M := 255 - G;
+  Y := 255 - B;
+end;
+
+procedure CMYToRGB(C, M, Y: Byte; var R, G, B: Byte);
+begin
+  R := 255 - C;
+  G := 255 - M;
+  B := 255 - Y;
+end;
+
+procedure RGBToCMY16(R, G, B: Word; var C, M, Y: Word);
+begin
+  C := 65535 - R;
+  M := 65535 - G;
+  Y := 65535 - B;
+end;
+
+procedure CMYToRGB16(C, M, Y: Word; var R, G, B: Word);
+begin
+  R := 65535 - C;
+  G := 65535 - M;
+  B := 65535 - Y;
+end;
+
+procedure RGBToCMYK(R, G, B: Byte; var C, M, Y, K: Byte);
+begin
+  RGBToCMY(R, G, B, C, M, Y);
+  K := Min(C, Min(M, Y));
+  if K = 255 then
+  begin
+    C := 0;
+    M := 0;
+    Y := 0;
+  end
+  else
+  begin
+    C := ClampToByte(Round((C - K) / (255 - K) * 255));
+    M := ClampToByte(Round((M - K) / (255 - K) * 255));
+    Y := ClampToByte(Round((Y - K) / (255 - K) * 255));
+  end;
+end;
+
+procedure CMYKToRGB(C, M, Y, K: Byte; var R, G, B: Byte);
+begin
+   R := (255 - (C - MulDiv(C, K, 255) + K));
+   G := (255 - (M - MulDiv(M, K, 255) + K));
+   B := (255 - (Y - MulDiv(Y, K, 255) + K));
+end;
+
+procedure RGBToCMYK16(R, G, B: Word; var C, M, Y, K: Word);
+begin
+  RGBToCMY16(R, G, B, C, M, Y);
+  K := Min(C, Min(M, Y));
+  if K = 65535 then
+  begin
+    C := 0;
+    M := 0;
+    Y := 0;
+  end
+  else
+  begin
+    C := ClampToWord(Round((C - K) / (65535 - K) * 65535));
+    M := ClampToWord(Round((M - K) / (65535 - K) * 65535));
+    Y := ClampToWord(Round((Y - K) / (65535 - K) * 65535));
+  end;
+end;
+
+procedure CMYKToRGB16(C, M, Y, K: Word; var R, G, B: Word);
+begin
+  R := 65535 - (C - MulDiv(C, K, 65535) + K);
+  G := 65535 - (M - MulDiv(M, K, 65535) + K);
+  B := 65535 - (Y - MulDiv(Y, K, 65535) + K);
+end;
+
+procedure RGBToYCoCg(R, G, B: Byte; var Y, Co, Cg: Byte);
+begin
+  // C and Delphi's SHR behaviour differs for negative numbers, use div instead.
+  Y  := ClampToByte(( R +     G shl 1 + B       + 2) div 4);
+  Co := ClampToByte(( R shl 1         - B shl 1 + 2) div 4 + 128);
+  Cg := ClampToByte((-R +     G shl 1 - B       + 2) div 4 + 128);
+end;
+
+procedure YCoCgToRGB(Y, Co, Cg: Byte; var R, G, B: Byte);
+var
+  CoInt, CgInt: Integer;
+begin
+  CoInt := Co - 128;
+  CgInt := Cg - 128;
+  R := ClampToByte(Y + CoInt - CgInt);
+  G := ClampToByte(Y + CgInt);
+  B := ClampToByte(Y - CoInt - CgInt);
+end;
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Added RGB<>YCoCg conversion functions.
+    - Fixed RGB>>CMYK conversions.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added RGB<>CMY(K) converion functions for 16 bit channels
+      (needed by PSD loading code).
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Added some color space conversion functions and LUTs
+      (RGB/YUV/YCrCb/CMY/CMYK).
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - unit created (empty!)
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingComponents.pas b/src/lib/vampimg/ImagingComponents.pas
new file mode 100644 (file)
index 0000000..61451fe
--- /dev/null
@@ -0,0 +1,1296 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains VCL/LCL TGraphic descendant which uses Imaging library
+  for saving and loading.}
+unit ImagingComponents;
+
+{$I ImagingOptions.inc}
+
+interface
+
+{$IFDEF LCL}
+  {$DEFINE COMPONENT_SET_LCL}
+  {$UNDEF COMPONENT_SET_VCL}
+{$ENDIF}
+
+{$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)}
+// If no component sets should be used just include empty unit.
+//DOC-IGNORE-BEGIN
+implementation
+//DOC-IGNORE-END
+{$ELSE}
+
+uses
+  SysUtils, Types, Classes,
+{$IFDEF MSWINDOWS}
+  Windows,
+{$ENDIF}
+{$IFDEF COMPONENT_SET_VCL}
+  Graphics,
+{$ENDIF}
+{$IFDEF COMPONENT_SET_LCL}
+  InterfaceBase,
+  GraphType,
+  Graphics,
+  LCLType,
+  LCLIntf,
+{$ENDIF}
+  ImagingTypes, Imaging, ImagingClasses;
+
+type
+  { Graphic class which uses Imaging to load images.
+    It has standard TBitmap class as ancestor and it can
+    Assign also to/from TImageData structres and TBaseImage
+    classes. For saving is uses inherited TBitmap methods.
+    This class is automatically registered to TPicture for all
+    file extensions supported by Imaging (useful only for loading).
+    If you just want to load images in various formats you can use this
+    class or simply use  TPicture.LoadFromXXX which will create this class
+    automatically. For TGraphic class that saves with Imaging look
+    at TImagingGraphicForSave class.}
+  TImagingGraphic = class(TBitmap)
+  protected
+    procedure ReadDataFromStream(Stream: TStream); virtual;
+    procedure AssignTo(Dest: TPersistent); override;
+  public
+    constructor Create; override;
+
+    { Loads new image from the stream. It can load all image
+      file formats supported by Imaging (and enabled of course)
+      even though it is called by descendant class capable of
+      saving only one file format.}
+    procedure LoadFromStream(Stream: TStream); override;
+    { Copies the image contained in Source to this graphic object.
+      Supports also TBaseImage descendants from ImagingClasses unit. }
+    procedure Assign(Source: TPersistent); override;
+    { Copies the image contained in TBaseImage to this graphic object.}
+    procedure AssignFromImage(Image: TBaseImage);
+    { Copies the current image to TBaseImage object.}
+    procedure AssignToImage(Image: TBaseImage);
+    { Copies the image contained in TImageData structure to this graphic object.}
+    procedure AssignFromImageData(const ImageData: TImageData);
+    { Copies the current image to TImageData structure.}
+    procedure AssignToImageData(var ImageData: TImageData);
+  end;
+
+  TImagingGraphicClass = class of TImagingGraphic;
+
+  { Base class for file format specific TGraphic classes that use
+    Imaging for saving. Each descendant class can load all file formats
+    supported by Imaging but save only one format (TImagingBitmap
+    for *.bmp, TImagingJpeg for *.jpg). Format specific classes also
+    allow easy access to Imaging options that affect saving of files
+    (they are properties here).}
+  TImagingGraphicForSave = class(TImagingGraphic)
+  protected
+    FDefaultFileExt: string;
+    FSavingFormat: TImageFormat;
+    procedure WriteDataToStream(Stream: TStream); virtual;
+  public
+    constructor Create; override;
+    { Saves the current image to the stream. It is saved in the
+      file format according to the DefaultFileExt property.
+      So each descendant class can save some other file format.}
+    procedure SaveToStream(Stream: TStream); override;
+    { Returns TImageFileFormat descendant for this graphic class.}
+    class function GetFileFormat: TImageFileFormat; virtual; abstract;
+  {$IFDEF COMPONENT_SET_LCL}
+    { Returns file extensions of this graphic class.}
+    class function GetFileExtensions: string; override;
+    { Returns default MIME type of this graphic class.}
+    function GetMimeType: string; override;
+  {$ENDIF}
+    { Default (the most common) file extension of this graphic class.}
+    property DefaultFileExt: string read FDefaultFileExt;
+  end;
+
+  TImagingGraphicForSaveClass = class of TImagingGraphicForSave;
+
+{$IFNDEF DONT_LINK_BITMAP}
+  { TImagingGraphic descendant for loading/saving Windows bitmaps.
+    VCL/CLX/LCL all have native support for bitmaps so you might
+    want to disable this class (although you can save bitmaps with
+    RLE compression with this class).}
+  TImagingBitmap = class(TImagingGraphicForSave)
+  protected
+    FUseRLE: Boolean;
+  public
+    constructor Create; override;
+    procedure SaveToStream(Stream: TStream); override;
+    class function GetFileFormat: TImageFileFormat; override;
+    { See ImagingBitmapRLE option for details.}
+    property UseRLE: Boolean read FUseRLE write FUseRLE;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_JPEG}
+  { TImagingGraphic descendant for loading/saving JPEG images.}
+  TImagingJpeg = class(TImagingGraphicForSave)
+  protected
+    FQuality: LongInt;
+    FProgressive: Boolean;
+  public
+    constructor Create; override;
+    procedure SaveToStream(Stream: TStream); override;
+    class function GetFileFormat: TImageFileFormat; override;
+  {$IFDEF COMPONENT_SET_LCL}
+    function GetMimeType: string; override;
+  {$ENDIF}
+    { See ImagingJpegQuality option for details.}
+    property Quality: LongInt read FQuality write FQuality;
+    { See ImagingJpegProgressive option for details.}
+    property Progressive: Boolean read FProgressive write FProgressive;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_PNG}
+  { TImagingGraphic descendant for loading/saving PNG images.}
+  TImagingPNG = class(TImagingGraphicForSave)
+  protected
+    FPreFilter: LongInt;
+    FCompressLevel: LongInt;
+  public
+    constructor Create; override;
+    procedure SaveToStream(Stream: TStream); override;
+    class function GetFileFormat: TImageFileFormat; override;
+    { See ImagingPNGPreFilter option for details.}
+    property PreFilter: LongInt read FPreFilter write FPreFilter;
+    { See ImagingPNGCompressLevel option for details.}
+    property CompressLevel: LongInt read FCompressLevel write FCompressLevel;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_GIF}
+  { TImagingGraphic descendant for loading/saving GIF images.}
+  TImagingGIF = class(TImagingGraphicForSave)
+  public
+    class function GetFileFormat: TImageFileFormat; override;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_TARGA}
+  { TImagingGraphic descendant for loading/saving Targa images.}
+  TImagingTarga = class(TImagingGraphicForSave)
+  protected
+    FUseRLE: Boolean;
+  public
+    constructor Create; override;
+    procedure SaveToStream(Stream: TStream); override;
+    class function GetFileFormat: TImageFileFormat; override;
+    { See ImagingTargaRLE option for details.}
+    property UseRLE: Boolean read FUseRLE write FUseRLE;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_DDS}
+  { Compresssion type used when saving DDS files by TImagingDds.}
+  TDDSCompresion = (dcNone, dcDXT1, dcDXT3, dcDXT5);
+
+  { TImagingGraphic descendant for loading/saving DDS images.}
+  TImagingDDS = class(TImagingGraphicForSave)
+  protected
+    FCompression: TDDSCompresion;
+  public
+    constructor Create; override;
+    procedure SaveToStream(Stream: TStream); override;
+    class function GetFileFormat: TImageFileFormat; override;
+    { You can choose compression type used when saving DDS file.
+      dcNone means that file will be saved in the current bitmaps pixel format.}
+    property Compression: TDDSCompresion read FCompression write FCompression;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_MNG}
+  { TImagingGraphic descendant for loading/saving MNG images.}
+  TImagingMNG = class(TImagingGraphicForSave)
+  protected
+    FLossyCompression: Boolean;
+    FLossyAlpha: Boolean;
+    FPreFilter: LongInt;
+    FCompressLevel: LongInt;
+    FQuality: LongInt;
+    FProgressive: Boolean;
+  public
+    constructor Create; override;
+    procedure SaveToStream(Stream: TStream); override;
+    class function GetFileFormat: TImageFileFormat; override;
+  {$IFDEF COMPONENT_SET_LCL}
+    function GetMimeType: string; override;
+  {$ENDIF}
+    { See ImagingMNGLossyCompression option for details.}
+    property LossyCompression: Boolean read FLossyCompression write FLossyCompression;
+    { See ImagingMNGLossyAlpha option for details.}
+    property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha;
+    { See ImagingMNGPreFilter option for details.}
+    property PreFilter: LongInt read FPreFilter write FPreFilter;
+    { See ImagingMNGCompressLevel option for details.}
+    property CompressLevel: LongInt read FCompressLevel write FCompressLevel;
+    { See ImagingMNGQuality option for details.}
+    property Quality: LongInt read FQuality write FQuality;
+    { See ImagingMNGProgressive option for details.}
+    property Progressive: Boolean read FProgressive write FProgressive;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_JNG}
+  { TImagingGraphic descendant for loading/saving JNG images.}
+  TImagingJNG = class(TImagingGraphicForSave)
+  protected
+    FLossyAlpha: Boolean;
+    FAlphaPreFilter: LongInt;
+    FAlphaCompressLevel: LongInt;
+    FQuality: LongInt;
+    FProgressive: Boolean;
+  public
+    constructor Create; override;
+    procedure SaveToStream(Stream: TStream); override;
+    class function GetFileFormat: TImageFileFormat; override;
+    { See ImagingJNGLossyAlpha option for details.}
+    property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha;
+    { See ImagingJNGPreFilter option for details.}
+    property AlphaPreFilter: LongInt read FAlphaPreFilter write FAlphaPreFilter;
+    { See ImagingJNGCompressLevel option for details.}
+    property AlphaCompressLevel: LongInt read FAlphaCompressLevel write FAlphaCompressLevel;
+    { See ImagingJNGQuality option for details.}
+    property Quality: LongInt read FQuality write FQuality;
+    { See ImagingJNGProgressive option for details.}
+    property Progressive: Boolean read FProgressive write FProgressive;
+  end;
+{$ENDIF}
+
+{ Returns bitmap pixel format with the closest match with given data format.}
+function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat;
+{ Returns data format with closest match with given bitmap pixel format.}
+function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat;
+
+{ Converts TImageData structure to VCL/CLX/LCL bitmap.}
+procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap);
+{ Converts VCL/CLX/LCL bitmap to TImageData structure.}
+procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData);
+{ Converts TBaseImage instance to VCL/CLX/LCL bitmap.}
+procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap);
+{ Converts VCL/CLX/LCL bitmap to TBaseImage. Image must exist before
+  procedure is called. It overwrites its current image data.
+  When Image is TMultiImage only the current image level is overwritten.}
+procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage);
+
+{ Displays image stored in TImageData structure onto TCanvas. This procedure
+  draws image without converting from Imaging format to TBitmap.
+  Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
+  when you want displaying images that change frequently (because converting to
+  TBitmap by ConvertImageDataToBitmap is generally slow). Dest and Src
+  rectangles represent coordinates in the form (X1, Y1, X2, Y2).}
+procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
+{ Displays image onto TCanvas at position [DstX, DstY]. This procedure
+  draws image without converting from Imaging format to TBitmap.
+  Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
+  when you want displaying images that change frequently (because converting to
+  TBitmap by ConvertImageDataToBitmap is generally slow).}
+procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage); overload;
+{ Displays image onto TCanvas to rectangle DstRect. This procedure
+  draws image without converting from Imaging format to TBitmap.
+  Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
+  when you want displaying images that change frequently (because converting to
+  TBitmap by ConvertImageDataToBitmap is generally slow).}
+procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage); overload;
+{ Displays part of the image specified by SrcRect onto TCanvas to rectangle DstRect.
+  This procedure draws image without converting from Imaging format to TBitmap.
+  Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this
+  when you want displaying images that change frequently (because converting to
+  TBitmap by ConvertImageDataToBitmap is generally slow).}
+procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect); overload;
+
+{$IFDEF MSWINDOWS}
+{ Displays image stored in TImageData structure onto Windows device context.
+  Behaviour is the same as of DisplayImageData.}
+procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
+{$ENDIF}
+
+implementation
+
+uses
+{$IF Defined(LCL)}
+  {$IF Defined(LCLGTK2)}
+    GLib2, GDK2, GTK2, GTK2Def, GTK2Proc,
+  {$IFEND}
+{$IFEND}
+{$IFNDEF DONT_LINK_BITMAP}
+  ImagingBitmap,
+{$ENDIF}
+{$IFNDEF DONT_LINK_JPEG}
+  ImagingJpeg,
+{$ENDIF}
+{$IFNDEF DONT_LINK_GIF}
+  ImagingGif,
+{$ENDIF}
+{$IFNDEF DONT_LINK_TARGA}
+  ImagingTarga,
+{$ENDIF}
+{$IFNDEF DONT_LINK_DDS}
+  ImagingDds,
+{$ENDIF}
+{$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)}
+  ImagingNetworkGraphics,
+{$IFEND}
+  ImagingFormats, ImagingUtility;
+
+resourcestring
+  SBadFormatDataToBitmap = 'Cannot find compatible bitmap format for image %s';
+  SBadFormatBitmapToData = 'Cannot find compatible data format for bitmap %p';
+  SBadFormatDisplay = 'Unsupported image format passed';
+  SUnsupportedLCLWidgetSet = 'This function is not implemented for current LCL widget set';
+  SImagingGraphicName = 'Imaging Graphic AllInOne';
+
+{ Registers types to VCL/LCL.}
+procedure RegisterTypes;
+var
+  I: LongInt;
+
+  procedure RegisterFileFormatAllInOne(Format: TImageFileFormat);
+  var
+    I: LongInt;
+  begin
+    for I := 0 to Format.Extensions.Count - 1 do
+      TPicture.RegisterFileFormat(Format.Extensions[I], SImagingGraphicName,
+        TImagingGraphic);
+  end;
+
+  procedure RegisterFileFormat(AClass: TImagingGraphicForSaveClass);
+  var
+    I: LongInt;
+  begin
+    for I := 0 to AClass.GetFileFormat.Extensions.Count - 1 do
+      TPicture.RegisterFileFormat(AClass.GetFileFormat.Extensions[I],
+        AClass.GetFileFormat.Name, AClass);
+  end;
+
+begin
+  for I := Imaging.GetFileFormatCount - 1 downto 0 do
+    RegisterFileFormatAllInOne(Imaging.GetFileFormatAtIndex(I));
+  Classes.RegisterClass(TImagingGraphic);
+
+{$IFNDEF DONT_LINK_TARGA}
+  RegisterFileFormat(TImagingTarga);
+  Classes.RegisterClass(TImagingTarga);
+{$ENDIF}
+{$IFNDEF DONT_LINK_DDS}
+  RegisterFileFormat(TImagingDDS);
+  Classes.RegisterClass(TImagingDDS);
+{$ENDIF}
+{$IFNDEF DONT_LINK_JNG}
+  RegisterFileFormat(TImagingJNG);
+  Classes.RegisterClass(TImagingJNG);
+{$ENDIF}
+{$IFNDEF DONT_LINK_MNG}
+  RegisterFileFormat(TImagingMNG);
+  Classes.RegisterClass(TImagingMNG);
+{$ENDIF}
+{$IFNDEF DONT_LINK_GIF}
+  RegisterFileFormat(TImagingGIF);
+  Classes.RegisterClass(TImagingGIF);
+{$ENDIF}
+{$IFNDEF DONT_LINK_PNG}
+  {$IFDEF COMPONENT_SET_LCL}
+    // Unregister Lazarus´ default PNG loader which crashes on some PNG files
+    TPicture.UnregisterGraphicClass(TPortableNetworkGraphic);
+  {$ENDIF}
+  RegisterFileFormat(TImagingPNG);
+  Classes.RegisterClass(TImagingPNG);
+{$ENDIF}
+{$IFNDEF DONT_LINK_JPEG}
+  RegisterFileFormat(TImagingJpeg);
+  Classes.RegisterClass(TImagingJpeg);
+{$ENDIF}
+{$IFNDEF DONT_LINK_BITMAP}
+  RegisterFileFormat(TImagingBitmap);
+  Classes.RegisterClass(TImagingBitmap);
+{$ENDIF}
+end;
+
+{ Unregisters types from VCL/LCL.}
+procedure UnRegisterTypes;
+begin
+{$IFNDEF DONT_LINK_BITMAP}
+  TPicture.UnregisterGraphicClass(TImagingBitmap);
+  Classes.UnRegisterClass(TImagingBitmap);
+{$ENDIF}
+{$IFNDEF DONT_LINK_JPEG}
+  TPicture.UnregisterGraphicClass(TImagingJpeg);
+  Classes.UnRegisterClass(TImagingJpeg);
+{$ENDIF}
+{$IFNDEF DONT_LINK_PNG}
+  TPicture.UnregisterGraphicClass(TImagingPNG);
+  Classes.UnRegisterClass(TImagingPNG);
+{$ENDIF}
+{$IFNDEF DONT_LINK_GIF}
+  TPicture.UnregisterGraphicClass(TImagingGIF);
+  Classes.UnRegisterClass(TImagingGIF);
+{$ENDIF}
+{$IFNDEF DONT_LINK_TARGA}
+  TPicture.UnregisterGraphicClass(TImagingTarga);
+  Classes.UnRegisterClass(TImagingTarga);
+{$ENDIF}
+{$IFNDEF DONT_LINK_DDS}
+  TPicture.UnregisterGraphicClass(TImagingDDS);
+  Classes.UnRegisterClass(TImagingDDS);
+{$ENDIF}
+  TPicture.UnregisterGraphicClass(TImagingGraphic);
+  Classes.UnRegisterClass(TImagingGraphic);
+end;
+
+function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat;
+begin
+  case Format of
+{$IFDEF COMPONENT_SET_VCL}
+    ifIndex8: Result := pf8bit;
+    ifR5G6B5: Result := pf16bit;
+    ifR8G8B8: Result := pf24bit;
+{$ENDIF}
+    ifA8R8G8B8,
+    ifX8R8G8B8: Result := pf32bit;
+  else
+    Result := pfCustom;
+  end;
+end;
+
+function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat;
+begin
+  case Format of
+    pf8bit: Result := ifIndex8;
+    pf15bit: Result := ifA1R5G5B5;
+    pf16bit: Result := ifR5G6B5;
+    pf24bit: Result := ifR8G8B8;
+    pf32bit: Result := ifA8R8G8B8;
+  else
+    Result := ifUnknown;
+  end;
+end;
+
+procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap);
+var
+  I, LineBytes: LongInt;
+  PF: TPixelFormat;
+  Info: TImageFormatInfo;
+  WorkData: TImageData;
+{$IFDEF COMPONENT_SET_VCL}
+  LogPalette: TMaxLogPalette;
+{$ENDIF}
+{$IFDEF COMPONENT_SET_LCL}
+  RawImage: TRawImage;
+  ImgHandle, ImgMaskHandle: HBitmap;
+{$ENDIF}
+begin
+  PF := DataFormatToPixelFormat(Data.Format);
+  GetImageFormatInfo(Data.Format, Info);
+
+  if (PF = pf8bit) and PaletteHasAlpha(Data.Palette, Info.PaletteEntries) then
+  begin
+    // Some indexed images may have valid alpha data, dont lose it!
+    // (e.g. transparent 8bit PNG or GIF images)
+    PF := pfCustom;
+  end;
+
+  if PF = pfCustom then
+  begin
+    // Convert from formats not supported by Graphics unit
+    Imaging.InitImage(WorkData);
+    Imaging.CloneImage(Data, WorkData);
+    if Info.IsFloatingPoint or Info.HasAlphaChannel or Info.IsSpecial then
+      Imaging.ConvertImage(WorkData, ifA8R8G8B8)
+    else
+    begin
+{$IFDEF COMPONENT_SET_VCL}
+      if Info.IsIndexed or Info.HasGrayChannel then
+        Imaging.ConvertImage(WorkData, ifIndex8)
+      else if Info.UsePixelFormat then
+        Imaging.ConvertImage(WorkData, ifR5G6B5)
+      else
+        Imaging.ConvertImage(WorkData, ifR8G8B8);
+{$ELSE}
+        Imaging.ConvertImage(WorkData, ifA8R8G8B8);
+{$ENDIF}
+    end;
+
+    PF := DataFormatToPixelFormat(WorkData.Format);
+    GetImageFormatInfo(WorkData.Format, Info);
+  end
+  else
+    WorkData := Data;
+
+  if PF = pfCustom then
+    RaiseImaging(SBadFormatDataToBitmap, [ImageToStr(WorkData)]);
+
+  LineBytes := WorkData.Width * Info.BytesPerPixel;
+
+{$IFDEF COMPONENT_SET_VCL}
+  Bitmap.Width := WorkData.Width;
+  Bitmap.Height := WorkData.Height;
+  Bitmap.PixelFormat := PF;
+
+  if (PF = pf8bit) and (WorkData.Palette <> nil) then
+  begin
+    // Copy palette, this must be done before copying bits
+    FillChar(LogPalette, SizeOf(LogPalette), 0);
+    LogPalette.palVersion := $300;
+    LogPalette.palNumEntries := Info.PaletteEntries;
+    for I := 0 to Info.PaletteEntries - 1 do
+    with LogPalette do
+    begin
+      palPalEntry[I].peRed := WorkData.Palette[I].R;
+      palPalEntry[I].peGreen := WorkData.Palette[I].G;
+      palPalEntry[I].peBlue := WorkData.Palette[I].B;
+    end;
+    Bitmap.Palette := CreatePalette(PLogPalette(@LogPalette)^);
+  end;
+  // Copy scanlines
+  for I := 0 to WorkData.Height - 1 do
+    Move(PByteArray(WorkData.Bits)[I * LineBytes], Bitmap.Scanline[I]^, LineBytes);
+
+  // Delphi 2009 and newer support alpha transparency fro TBitmap
+{$IF Defined(DELPHI) and (CompilerVersion >= 20.0)}
+  if Bitmap.PixelFormat = pf32bit then
+    Bitmap.AlphaFormat := afDefined;
+{$IFEND}
+
+{$ENDIF}
+{$IFDEF COMPONENT_SET_LCL}
+  // Create 32bit raw image from image data
+  FillChar(RawImage, SizeOf(RawImage), 0);
+  with RawImage.Description do
+  begin
+    Width := WorkData.Width;
+    Height := WorkData.Height;
+    BitsPerPixel := 32;
+    Format := ricfRGBA;
+    LineEnd := rileDWordBoundary;
+    BitOrder := riboBitsInOrder;
+    ByteOrder := riboLSBFirst;
+    LineOrder := riloTopToBottom;
+    AlphaPrec := 8;
+    RedPrec := 8;
+    GreenPrec := 8;
+    BluePrec := 8;
+    AlphaShift := 24;
+    RedShift := 16;
+    GreenShift := 8;
+    BlueShift := 0;
+    Depth := 32; // Must be 32 for alpha blending (and for working in MacOSX Carbon)
+  end;
+  RawImage.Data := WorkData.Bits;
+  RawImage.DataSize := WorkData.Size;
+
+  // Create bitmap from raw image
+  if RawImage_CreateBitmaps(RawImage, ImgHandle, ImgMaskHandle) then
+  begin
+    Bitmap.Handle := ImgHandle;
+    Bitmap.MaskHandle := ImgMaskHandle;
+  end;
+{$ENDIF}
+  if WorkData.Bits <> Data.Bits then
+    Imaging.FreeImage(WorkData);
+end;
+
+procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData);
+var
+  I, LineBytes: LongInt;
+  Format: TImageFormat;
+  Info: TImageFormatInfo;
+{$IFDEF COMPONENT_SET_VCL}
+  Colors: Word;
+  LogPalette: TMaxLogPalette;
+{$ENDIF}
+{$IFDEF COMPONENT_SET_LCL}
+  RawImage: TRawImage;
+  LineLazBytes: LongInt;
+{$ENDIF}
+begin
+{$IFDEF COMPONENT_SET_LCL}
+  // In the current Lazarus 0.9.10 Bitmap.PixelFormat property is useless.
+  // We cannot change bitmap's format by changing it (it will just release
+  // old image but not convert it to new format) nor we can determine bitmaps's
+  // current format (it is usually set to pfDevice). So bitmap's format is obtained
+  // trough RawImage api and cannot be changed to mirror some Imaging format
+  // (so formats with no coresponding Imaging format cannot be saved now).
+
+  if RawImage_DescriptionFromBitmap(Bitmap.Handle, RawImage.Description) then
+    case RawImage.Description.BitsPerPixel of
+      8: Format := ifIndex8;
+      16:
+        if RawImage.Description.Depth = 15 then
+          Format := ifA1R5G5B5
+        else
+          Format := ifR5G6B5;
+      24: Format := ifR8G8B8;
+      32: Format := ifA8R8G8B8;
+      48: Format := ifR16G16B16;
+      64: Format := ifA16R16G16B16;
+    else
+      Format := ifUnknown;
+    end;
+{$ELSE}
+  Format := PixelFormatToDataFormat(Bitmap.PixelFormat);
+  if Format = ifUnknown then
+  begin
+    // Convert from formats not supported by Imaging (1/4 bit)
+    if Bitmap.PixelFormat < pf8bit then
+       Bitmap.PixelFormat := pf8bit
+    else
+      Bitmap.PixelFormat := pf32bit;
+    Format := PixelFormatToDataFormat(Bitmap.PixelFormat);
+  end;
+{$ENDIF}
+
+  if Format = ifUnknown then
+    RaiseImaging(SBadFormatBitmapToData, []);
+
+  Imaging.NewImage(Bitmap.Width, Bitmap.Height, Format, Data);
+  GetImageFormatInfo(Data.Format, Info);
+  LineBytes := Data.Width * Info.BytesPerPixel;
+
+{$IFDEF COMPONENT_SET_VCL}
+  if (Format = ifIndex8) and (GetObject(Bitmap.Palette, SizeOf(Colors),
+    @Colors) <> 0) then
+  begin
+    // Copy palette
+    GetPaletteEntries(Bitmap.Palette, 0, Colors, LogPalette.palPalEntry);
+    if Colors > Info.PaletteEntries  then
+      Colors := Info.PaletteEntries;
+    for I := 0 to Colors - 1 do
+    with LogPalette do
+    begin
+      Data.Palette[I].A := $FF;
+      Data.Palette[I].R := palPalEntry[I].peRed;
+      Data.Palette[I].G := palPalEntry[I].peGreen;
+      Data.Palette[I].B := palPalEntry[I].peBlue;
+    end;
+  end;
+  // Copy scanlines
+  for I := 0 to Data.Height - 1 do
+    Move(Bitmap.ScanLine[I]^, PByteArray(Data.Bits)[I * LineBytes], LineBytes);
+{$ENDIF}
+{$IFDEF COMPONENT_SET_LCL}
+  // Get raw image from bitmap (mask handle must be 0 or expect violations)
+  if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, nil) then
+  begin
+    LineLazBytes := GetBytesPerLine(Data.Width, RawImage.Description.BitsPerPixel,
+      RawImage.Description.LineEnd);
+    // Copy scanlines
+    for I := 0 to Data.Height - 1 do
+    begin
+      Move(PByteArray(RawImage.Data)[I * LineLazBytes],
+        PByteArray(Data.Bits)[I * LineBytes], LineBytes);
+    end;
+    // May need to swap RB order, depends on wifget set
+    if RawImage.Description.BlueShift > RawImage.Description.RedShift then
+      SwapChannels(Data, ChannelRed, ChannelBlue);
+
+    RawImage.FreeData;
+  end;
+{$ENDIF}
+end;
+
+procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap);
+begin
+  ConvertDataToBitmap(Image.ImageDataPointer^, Bitmap);
+end;
+
+procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage);
+begin
+  ConvertBitmapToData(Bitmap, Image.ImageDataPointer^);
+end;
+
+{$IFDEF MSWINDOWS}
+procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
+var
+  OldMode: Integer;
+  BitmapInfo: Windows.TBitmapInfo;
+  Bmp: TBitmap;
+begin
+  if TestImage(ImageData) then
+  begin
+    Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay);
+    OldMode := Windows.SetStretchBltMode(DC, COLORONCOLOR);
+
+    FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
+    with BitmapInfo.bmiHeader do
+    begin
+      biSize := SizeOf(TBitmapInfoHeader);
+      biPlanes := 1;
+      biBitCount := 32;
+      biCompression := BI_RGB;
+      biWidth := ImageData.Width;
+      biHeight := -ImageData.Height;
+      biSizeImage := ImageData.Size;
+      biXPelsPerMeter := 0;
+      biYPelsPerMeter := 0;
+      biClrUsed := 0;
+      biClrImportant := 0;
+    end;
+
+    try
+       with SrcRect, ImageData do
+        if Windows.StretchDIBits(DC, DstRect.Left, DstRect.Top,
+          DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Left,
+          Top, Right - Left, Bottom - Top, Bits, BitmapInfo, DIB_RGB_COLORS, SRCCOPY) <> Height then
+        begin
+          // StretchDIBits may fail on some ocassions (error 487, http://support.microsoft.com/kb/269585).
+          // This fallback is slow but works every time. Thanks to Sergey Galezdinov for the fix.
+          Bmp := TBitmap.Create;
+          try
+            ConvertDataToBitmap(ImageData, Bmp);
+            StretchBlt(DC, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top,
+              Bmp.Canvas.Handle, 0, 0, Width, Height, SRCCOPY);
+          finally
+            Bmp.Free;
+          end;
+        end;
+    finally
+      Windows.SetStretchBltMode(DC, OldMode);
+    end;
+  end;
+end;
+{$ENDIF}
+
+procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect);
+{$IF Defined(DCC) or Defined(LCLWIN32)} // Delphi or LCL Win32
+begin
+  DisplayImageDataOnDC(DstCanvas.Handle, DstRect, ImageData, SrcRect);
+end;
+{$ELSEIF Defined(LCLGTK2)}
+  type
+    TDeviceContext = TGtk2DeviceContext;
+
+  procedure GDKDrawBitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY,
+    SrcWidth, SrcHeight: Integer; ImageData: TImageData);
+  var
+    P: TPoint;
+  begin
+    P := TDeviceContext(Dest).Offset;
+    Inc(DstX, P.X);
+    Inc(DstY, P.Y);
+    gdk_draw_rgb_32_image(TDeviceContext(Dest).Drawable, TDeviceContext(Dest).GC,
+      DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE,
+      @PLongWordArray(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 4);
+  end;
+
+var
+  DisplayImage: TImageData;
+  NewWidth, NewHeight: Integer;
+  SrcBounds, DstBounds, DstClip: TRect;
+begin
+  if TestImage(ImageData) then
+  begin
+    Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay);
+    InitImage(DisplayImage);
+
+    SrcBounds := RectToBounds(SrcRect);
+    DstBounds := RectToBounds(DstRect);
+    WidgetSet.GetClipBox(DstCanvas.Handle, @DstClip);
+
+    ClipStretchBounds(SrcBounds.Left, SrcBounds.Top, SrcBounds.Right, SrcBounds.Bottom,
+      DstBounds.Left, DstBounds.Top, DstBounds.Right, DstBounds.Bottom, ImageData.Width,
+      ImageData.Height, DstClip);
+
+    NewWidth := DstBounds.Right;
+    NewHeight := DstBounds.Bottom;
+
+    if (NewWidth > 0) and (NewHeight > 0) then
+    begin
+      if (SrcBounds.Right = NewWidth) and (SrcBounds.Bottom = NewHeight) then
+      try
+        CloneImage(ImageData, DisplayImage);
+        // Swap R-B channels for GTK display compatability!
+        SwapChannels(DisplayImage, ChannelRed, ChannelBlue);
+        GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top,
+          SrcBounds.Left, SrcBounds.Top, NewWidth, NewHeight, DisplayImage);
+      finally
+        FreeImage(DisplayImage);
+      end
+      else
+      try
+        // Create new image with desired dimensions
+        NewImage(NewWidth, NewHeight, ImageData.Format, DisplayImage);
+        // Stretch pixels from old image to new one  TResizeFilter = (rfNearest, rfBilinear, rfBicubic);
+        StretchRect(ImageData, SrcBounds.Left, SrcBounds.Top, SrcBounds.Right,
+          SrcBounds.Bottom, DisplayImage, 0, 0, NewWidth, NewHeight, rfNearest);
+        // Swap R-B channels for GTK display compatability!
+        SwapChannels(DisplayImage, ChannelRed, ChannelBlue);
+        GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top, 0, 0,
+          NewWidth, NewHeight, DisplayImage);
+       finally
+        FreeImage(DisplayImage);
+      end
+    end;
+  end;
+end;
+{$ELSE}
+begin
+  raise Exception.Create(SUnsupportedLCLWidgetSet);
+end;
+{$IFEND}
+
+procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage);
+begin
+  DisplayImageData(DstCanvas, BoundsToRect(DstX, DstY, Image.Width, Image.Height),
+    Image.ImageDataPointer^, Image.BoundsRect);
+end;
+
+procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage);
+begin
+  DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, Image.BoundsRect);
+end;
+
+procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect);
+begin
+  DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, SrcRect);
+end;
+
+
+{ TImagingGraphic class implementation }
+
+constructor TImagingGraphic.Create;
+begin
+  inherited Create;
+  PixelFormat := pf24Bit;
+end;
+
+procedure TImagingGraphic.LoadFromStream(Stream: TStream);
+begin
+  ReadDataFromStream(Stream);
+end;
+
+procedure TImagingGraphic.ReadDataFromStream(Stream: TStream);
+var
+  Image: TSingleImage;
+begin
+  Image := TSingleImage.Create;
+  try
+    Image.LoadFromStream(Stream);
+    Assign(Image);
+  finally
+    Image.Free;
+  end;
+end;
+
+procedure TImagingGraphic.AssignTo(Dest: TPersistent);
+var
+  Arr: TDynImageDataArray;
+begin
+  if Dest is TSingleImage then
+  begin
+    AssignToImage(TSingleImage(Dest))
+  end
+  else if Dest is TMultiImage then
+  begin
+    SetLength(Arr, 1);
+    AssignToImageData(Arr[0]);
+    TMultiImage(Dest).CreateFromArray(Arr);
+    Imaging.FreeImagesInArray(Arr);
+  end
+  else
+    inherited AssignTo(Dest);
+end;
+
+procedure TImagingGraphic.Assign(Source: TPersistent);
+begin
+  if Source is TBaseImage then
+    AssignFromImage(TBaseImage(Source))
+  else
+    inherited Assign(Source);
+end;
+
+procedure TImagingGraphic.AssignFromImage(Image: TBaseImage);
+begin
+  if (Image <> nil) and Image.Valid then
+    AssignFromImageData(Image.ImageDataPointer^);
+end;
+
+procedure TImagingGraphic.AssignToImage(Image: TBaseImage);
+begin
+  if (Image <> nil) and (Image.ImageDataPointer <> nil) then
+    AssignToImageData(Image.ImageDataPointer^);
+end;
+
+procedure TImagingGraphic.AssignFromImageData(const ImageData: TImageData);
+begin
+  if Imaging.TestImage(ImageData) then
+    ConvertDataToBitmap(ImageData, Self);
+end;
+
+procedure TImagingGraphic.AssignToImageData(var ImageData: TImageData);
+begin
+  Imaging.FreeImage(ImageData);
+  ConvertBitmapToData(Self, ImageData);
+end;
+
+
+{ TImagingGraphicForSave class implementation }
+
+constructor TImagingGraphicForSave.Create;
+begin
+  inherited Create;
+  FDefaultFileExt := GetFileFormat.Extensions[0];
+  FSavingFormat := ifUnknown;
+  GetFileFormat.CheckOptionsValidity;
+end;
+
+procedure TImagingGraphicForSave.WriteDataToStream(Stream: TStream);
+var
+  Image: TSingleImage;
+begin
+  if FDefaultFileExt <> '' then
+  begin
+    Image := TSingleImage.Create;
+    try
+      Image.Assign(Self);
+      if FSavingFormat <> ifUnknown then
+        Image.Format := FSavingFormat;
+      Image.SaveToStream(FDefaultFileExt, Stream);
+    finally
+      Image.Free;
+    end;
+  end;
+end;
+
+procedure TImagingGraphicForSave.SaveToStream(Stream: TStream);
+begin
+  WriteDataToStream(Stream);
+end;
+
+{$IFDEF COMPONENT_SET_LCL}
+class function TImagingGraphicForSave.GetFileExtensions: string;
+begin
+  Result := StringReplace(GetFileFormat.Extensions.CommaText, ',', ';', [rfReplaceAll]);
+end;
+
+function TImagingGraphicForSave.GetMimeType: string;
+begin
+  Result := 'image/' + FDefaultFileExt;
+end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_BITMAP}
+
+{ TImagingBitmap class implementation }
+
+constructor TImagingBitmap.Create;
+begin
+  inherited Create;
+  FUseRLE := (GetFileFormat as TBitmapFileFormat).UseRLE;
+end;
+
+class function TImagingBitmap.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TBitmapFileFormat);
+end;
+
+procedure TImagingBitmap.SaveToStream(Stream: TStream);
+begin
+  Imaging.PushOptions;
+  Imaging.SetOption(ImagingBitmapRLE, Ord(FUseRLE));
+  inherited SaveToStream(Stream);
+  Imaging.PopOptions;
+end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_JPEG}
+
+{ TImagingJpeg class implementation }
+
+constructor TImagingJpeg.Create;
+begin
+  inherited Create;
+  FQuality := (GetFileFormat as TJpegFileFormat).Quality;
+  FProgressive := (GetFileFormat as TJpegFileFormat).Progressive;
+end;
+
+class function TImagingJpeg.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TJpegFileFormat);
+end;
+
+{$IFDEF COMPONENT_SET_LCL}
+function TImagingJpeg.GetMimeType: string;
+begin
+  Result := 'image/jpeg';
+end;
+{$ENDIF}
+
+procedure TImagingJpeg.SaveToStream(Stream: TStream);
+begin
+  Imaging.PushOptions;
+  Imaging.SetOption(ImagingJpegQuality, FQuality);
+  Imaging.SetOption(ImagingJpegProgressive, Ord(FProgressive));
+  inherited SaveToStream(Stream);
+  Imaging.PopOptions;
+end;
+
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_PNG}
+
+{ TImagingPNG class implementation }
+
+constructor TImagingPNG.Create;
+begin
+  inherited Create;
+  FPreFilter := (GetFileFormat as TPNGFileFormat).PreFilter;
+  FCompressLevel := (GetFileFormat as TPNGFileFormat).CompressLevel;
+end;
+
+class function TImagingPNG.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TPNGFileFormat);
+end;
+
+procedure TImagingPNG.SaveToStream(Stream: TStream);
+begin
+  Imaging.PushOptions;
+  Imaging.SetOption(ImagingPNGPreFilter, FPreFilter);
+  Imaging.SetOption(ImagingPNGCompressLevel, FCompressLevel);
+  inherited SaveToStream(Stream);
+  Imaging.PopOptions;
+end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_GIF}
+
+{ TImagingGIF class implementation}
+
+class function TImagingGIF.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TGIFFileFormat);
+end;
+
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_TARGA}
+
+{ TImagingTarga class implementation }
+
+constructor TImagingTarga.Create;
+begin
+  inherited Create;
+  FUseRLE := (GetFileFormat as TTargaFileFormat).UseRLE;
+end;
+
+class function TImagingTarga.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TTargaFileFormat);
+end;
+
+procedure TImagingTarga.SaveToStream(Stream: TStream);
+begin
+  Imaging.PushOptions;
+  Imaging.SetOption(ImagingTargaRLE, Ord(FUseRLE));
+  inherited SaveToStream(Stream);
+  Imaging.PopOptions;
+end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_DDS}
+
+{ TImagingDDS class implementation }
+
+constructor TImagingDDS.Create;
+begin
+  inherited Create;
+  FCompression := dcNone;
+end;
+
+class function TImagingDDS.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TDDSFileFormat);
+end;
+
+procedure TImagingDDS.SaveToStream(Stream: TStream);
+begin
+  case FCompression of
+    dcNone: FSavingFormat := ifUnknown;
+    dcDXT1: FSavingFormat := ifDXT1;
+    dcDXT3: FSavingFormat := ifDXT3;
+    dcDXT5: FSavingFormat := ifDXT5;
+  end;
+  Imaging.PushOptions;
+  Imaging.SetOption(ImagingDDSSaveCubeMap, Ord(False));
+  Imaging.SetOption(ImagingDDSSaveVolume, Ord(False));
+  Imaging.SetOption(ImagingDDSSaveMipMapCount, 1);
+  Imaging.SetOption(ImagingDDSSaveDepth, 1);
+  inherited SaveToStream(Stream);
+  Imaging.PopOptions;
+end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_MNG}
+
+{ TImagingMNG class implementation }
+
+constructor TImagingMNG.Create;
+begin
+  inherited Create;
+  FLossyCompression := (GetFileFormat as TMNGFileFormat).LossyCompression;
+  FLossyAlpha := (GetFileFormat as TMNGFileFormat).LossyAlpha;
+  FPreFilter := (GetFileFormat as TMNGFileFormat).PreFilter;
+  FCompressLevel := (GetFileFormat as TMNGFileFormat).CompressLevel;
+  FQuality := (GetFileFormat as TMNGFileFormat).Quality;
+  FProgressive := (GetFileFormat as TMNGFileFormat).Progressive;
+end;
+
+class function TImagingMNG.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TMNGFileFormat);
+end;
+
+{$IFDEF COMPONENT_SET_LCL}
+function TImagingMNG.GetMimeType: string;
+begin
+  Result := 'video/mng';
+end;
+{$ENDIF}
+
+procedure TImagingMNG.SaveToStream(Stream: TStream);
+begin
+  Imaging.PushOptions;
+  Imaging.SetOption(ImagingMNGLossyCompression, Ord(FLossyCompression));
+  Imaging.SetOption(ImagingMNGLossyAlpha, Ord(FLossyAlpha));
+  Imaging.SetOption(ImagingMNGPreFilter, FPreFilter);
+  Imaging.SetOption(ImagingMNGCompressLevel, FCompressLevel);
+  Imaging.SetOption(ImagingMNGQuality, FQuality);
+  Imaging.SetOption(ImagingMNGProgressive, Ord(FProgressive));
+  inherited SaveToStream(Stream);
+  Imaging.PopOptions;
+end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_JNG}
+
+{ TImagingJNG class implementation }
+
+constructor TImagingJNG.Create;
+begin
+  inherited Create;
+  FLossyAlpha := (GetFileFormat as TJNGFileFormat).LossyAlpha;
+  FAlphaPreFilter := (GetFileFormat as TJNGFileFormat).PreFilter;
+  FAlphaCompressLevel := (GetFileFormat as TJNGFileFormat).CompressLevel;
+  FQuality := (GetFileFormat as TJNGFileFormat).Quality;
+  FProgressive := (GetFileFormat as TJNGFileFormat).Progressive;
+end;
+
+class function TImagingJNG.GetFileFormat: TImageFileFormat;
+begin
+  Result := FindImageFileFormatByClass(TJNGFileFormat);
+end;
+
+procedure TImagingJNG.SaveToStream(Stream: TStream);
+begin
+  Imaging.PushOptions;
+  Imaging.SetOption(ImagingJNGLossyALpha, Ord(FLossyAlpha));
+  Imaging.SetOption(ImagingJNGAlphaPreFilter, FAlphaPreFilter);
+  Imaging.SetOption(ImagingJNGAlphaCompressLevel, FAlphaCompressLevel);
+  Imaging.SetOption(ImagingJNGQuality, FQuality);
+  Imaging.SetOption(ImagingJNGProgressive, Ord(FProgressive));
+  inherited SaveToStream(Stream);
+  Imaging.PopOptions;
+end;
+{$ENDIF}
+
+initialization
+  RegisterTypes;
+finalization
+  UnRegisterTypes;
+
+{$IFEND} // {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)}
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 ---------------------------------------------------
+    - Fixed bug in ConvertBitmapToData causing images from GTK2 bitmaps
+      to have swapped RB channels.
+    - LCL: Removed GTK1 support (deprecated).
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Transparency of 8bit images (like loaded from 8bit PNG or GIF) is
+      kept intact during conversion to TBitmap in ConvertDataToBitmap
+      (32bit bitmap is created).
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Setting AlphaFormat property of TBitmap in ConvertDataToBitmap
+      when using Delphi 2009+.
+    - Fixed garbled LCL TBitmaps created by ConvertDataToBitmap
+      in Mac OS X (Carbon).
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - Added some more IFDEFs for Lazarus widget sets.
+    - Removed CLX code.
+    - GTK version of Unix DisplayImageData only used with LCL GTK so the
+      the rest of the unit can be used with Qt or other LCL interfaces.
+    - Fallback mechanism for DisplayImageDataOnDC, it may fail on occasions.
+    - Changed file format conditional compilation to reflect changes
+      in LINK symbols.
+    - Lazarus 0.9.26 compatibility changes.
+
+  -- 0.24.1 Changes/Bug Fixes ---------------------------------
+    - Fixed wrong IFDEF causing that Imaging wouldn't compile in Lazarus
+      with GTK2 target.
+    - Added commnets with code for Lazarus rev. 11861+ regarding
+      RawImage interface. Replace current code with that in comments
+      if you use Lazarus from SVN. New RawImage interface will be used by
+      default after next Lazarus release.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added TImagingGIF.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Uses only high level interface now (except for saving options).
+    - Slightly changed class hierarchy. TImagingGraphic is now only for loading
+      and base class for savers is new TImagingGraphicForSave. Also
+      TImagingGraphic is now registered with all supported file formats
+      by TPicture's format support.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - added DisplayImage procedures (thanks to Paul Michell, modified)
+    - removed RegisterTypes and UnRegisterTypes from interface section,
+      they are called automatically
+    - added procedures: ConvertImageToBitmap and ConvertBitmapToImage
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - LCL data to bitmap conversion didn´t work in Linux, fixed
+    - added MNG file format
+    - added JNG file format
+
+  -- 0.15 Changes/Bug Fixes -----------------------------------
+    - made it LCL compatible
+    - made it CLX compatible
+    - added all initial stuff
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingDds.pas b/src/lib/vampimg/ImagingDds.pas
new file mode 100644 (file)
index 0000000..9410495
--- /dev/null
@@ -0,0 +1,1144 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader/saver for DirectDraw Surface images.}
+unit ImagingDds;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  ImagingTypes, Imaging, ImagingUtility, ImagingFormats;
+
+type
+  { Class for loading and saving Microsoft DirectDraw surfaces.
+    It can load/save all D3D formats which have coresponding
+    TImageFormat. It supports plain textures, cube textures and
+    volume textures, all of these can have mipmaps. It can also
+    load some formats which have no exact TImageFormat, but can be easily
+    converted to one (bump map formats, etc.).
+    You can get some information about last loaded DDS file by calling
+    GetOption with ImagingDDSLoadedXXX options and you can set some
+    saving options by calling SetOption with ImagingDDSSaveXXX or you can
+    simply use properties of this class.
+    Note that when saving cube maps and volumes input image array must contain
+    at least number of images to build cube/volume based on current
+    Depth and MipMapCount settings.}
+  TDDSFileFormat = class(TImageFileFormat)
+  private
+    FLoadedCubeMap: LongBool;
+    FLoadedVolume: LongBool;
+    FLoadedMipMapCount: LongInt;
+    FLoadedDepth: LongInt;
+    FSaveCubeMap: LongBool;
+    FSaveVolume: LongBool;
+    FSaveMipMapCount: LongInt;
+    FSaveDepth: LongInt;
+    procedure ComputeSubDimensions(Idx, Width, Height, MipMaps, Depth: LongInt;
+      IsCubeMap, IsVolume: Boolean; var CurWidth, CurHeight: LongInt);
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+    procedure CheckOptionsValidity; override;
+  published
+    { True if last loaded DDS file was cube map.}
+    property LoadedCubeMap: LongBool read FLoadedCubeMap write FLoadedCubeMap;
+    { True if last loaded DDS file was volume texture.}
+    property LoadedVolume: LongBool read FLoadedVolume write FLoadedVolume;
+    { Number of mipmap levels of last loaded DDS image.}
+    property LoadedMipMapCount: LongInt read FLoadedMipMapCount write FLoadedMipMapCount;
+    { Depth (slices of volume texture or faces of cube map) of last loaded DDS image.}
+    property LoadedDepth: LongInt read FLoadedDepth write FLoadedDepth;
+    { True if next DDS file to be saved should be stored as cube map.}
+    property SaveCubeMap: LongBool read FSaveCubeMap write FSaveCubeMap;
+    { True if next DDS file to be saved should be stored as volume texture.}
+    property SaveVolume: LongBool read FSaveVolume write FSaveVolume;
+    { Sets the number of mipmaps which should be stored in the next saved DDS file.
+      Only applies to cube maps and volumes, ordinary 2D textures save all
+      levels present in input.}
+    property SaveMipMapCount: LongInt read FSaveMipMapCount write FSaveMipMapCount;
+    { Sets the depth (slices of volume texture or faces of cube map)
+      of the next saved DDS file.}
+    property SaveDepth: LongInt read FSaveDepth write FSaveDepth;
+  end;
+
+const
+  { DDS related metadata Ids }
+
+  { DXGI format of textures stored in DDS files with DX10 extension. Type is
+    Enum (value corresponding to DXGI_FORMAT enum from DX SDK).}
+  SMetaDdsDxgiFormat = 'DdsDxgiFormat';
+  { Number of mipmaps for each main image in DDS file.}
+  SMetaDdsMipMapCount = 'DdsMipMapCount';
+  { Texture array size stored in DDS file (DX10 extension).}
+  SMetaDdsArraySize = 'DdsArraySize';
+
+implementation
+
+const
+  SDDSFormatName = 'DirectDraw Surface';
+  SDDSMasks      = '*.dds';
+  DDSSupportedFormats: TImageFormats = [ifR8G8B8, ifA8R8G8B8, ifX8R8G8B8,
+    ifA1R5G5B5, ifA4R4G4B4, ifX1R5G5B5, ifX4R4G4B4, ifR5G6B5, ifA16B16G16R16,
+    ifR32F, ifA32B32G32R32F, ifR16F, ifA16B16G16R16F, ifR3G3B2, ifGray8, ifA8Gray8,
+    ifGray16, ifDXT1, ifDXT3, ifDXT5, ifATI1N, ifATI2N];
+
+const
+  { Four character codes.}
+  DDSMagic    = LongWord(Byte('D') or (Byte('D') shl 8) or (Byte('S') shl 16) or
+    (Byte(' ') shl 24));
+  FOURCC_DXT1 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
+    (Byte('1') shl 24));
+  FOURCC_DXT3 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
+    (Byte('3') shl 24));
+  FOURCC_DXT5 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or
+    (Byte('5') shl 24));
+  FOURCC_ATI1 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or
+    (Byte('1') shl 24));
+  FOURCC_ATI2 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or
+    (Byte('2') shl 24));
+  FOURCC_DX10 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('1') shl 16) or
+    (Byte('0') shl 24));
+
+  { Some D3DFORMAT values used in DDS files as FourCC value.}
+  D3DFMT_A16B16G16R16  = 36;
+  D3DFMT_R32F          = 114;
+  D3DFMT_A32B32G32R32F = 116;
+  D3DFMT_R16F          = 111;
+  D3DFMT_A16B16G16R16F = 113;
+
+  { Constans used by TDDSurfaceDesc2.Flags.}
+  DDSD_CAPS            = $00000001;
+  DDSD_HEIGHT          = $00000002;
+  DDSD_WIDTH           = $00000004;
+  DDSD_PITCH           = $00000008;
+  DDSD_PIXELFORMAT     = $00001000;
+  DDSD_MIPMAPCOUNT     = $00020000;
+  DDSD_LINEARSIZE      = $00080000;
+  DDSD_DEPTH           = $00800000;
+
+  { Constans used by TDDSPixelFormat.Flags.}
+  DDPF_ALPHAPIXELS     = $00000001;    // used by formats which contain alpha
+  DDPF_FOURCC          = $00000004;    // used by DXT and large ARGB formats
+  DDPF_RGB             = $00000040;    // used by RGB formats
+  DDPF_LUMINANCE       = $00020000;    // used by formats like D3DFMT_L16
+  DDPF_BUMPLUMINANCE   = $00040000;    // used by mixed signed-unsigned formats
+  DDPF_BUMPDUDV        = $00080000;    // used by signed formats
+
+  { Constans used by TDDSCaps.Caps1.}
+  DDSCAPS_COMPLEX      = $00000008;
+  DDSCAPS_TEXTURE      = $00001000;
+  DDSCAPS_MIPMAP       = $00400000;
+
+  { Constans used by TDDSCaps.Caps2.}
+  DDSCAPS2_CUBEMAP     = $00000200;
+  DDSCAPS2_POSITIVEX   = $00000400;
+  DDSCAPS2_NEGATIVEX   = $00000800;
+  DDSCAPS2_POSITIVEY   = $00001000;
+  DDSCAPS2_NEGATIVEY   = $00002000;
+  DDSCAPS2_POSITIVEZ   = $00004000;
+  DDSCAPS2_NEGATIVEZ   = $00008000;
+  DDSCAPS2_VOLUME      = $00200000;
+
+  { Flags for TDDSurfaceDesc2.Flags used when saving DDS file.}
+  DDS_SAVE_FLAGS = DDSD_CAPS or DDSD_PIXELFORMAT or DDSD_WIDTH or
+    DDSD_HEIGHT or DDSD_LINEARSIZE;
+
+type
+  { Stores the pixel format information.}
+  TDDPixelFormat = packed record
+    Size: LongWord;       // Size of the structure = 32 bytes
+    Flags: LongWord;      // Flags to indicate valid fields
+    FourCC: LongWord;     // Four-char code for compressed textures (DXT)
+    BitCount: LongWord;   // Bits per pixel if uncomp. usually 16,24 or 32
+    RedMask: LongWord;    // Bit mask for the Red component
+    GreenMask: LongWord;  // Bit mask for the Green component
+    BlueMask: LongWord;   // Bit mask for the Blue component
+    AlphaMask: LongWord;  // Bit mask for the Alpha component
+  end;
+
+  { Specifies capabilities of surface.}
+  TDDSCaps = packed record
+    Caps1: LongWord;      // Should always include DDSCAPS_TEXTURE
+    Caps2: LongWord;      // For cubic environment maps
+    Reserved: array[0..1] of LongWord; // Reserved
+  end;
+
+  { Record describing DDS file contents.}
+  TDDSurfaceDesc2 = packed record
+    Size: LongWord;       // Size of the structure = 124 Bytes
+    Flags: LongWord;      // Flags to indicate valid fields
+    Height: LongWord;     // Height of the main image in pixels
+    Width: LongWord;      // Width of the main image in pixels
+    PitchOrLinearSize: LongWord; // For uncomp formats number of bytes per
+                          // scanline. For comp it is the size in
+                          // bytes of the main image
+    Depth: LongWord;      // Only for volume text depth of the volume
+    MipMaps: LongInt;     // Total number of levels in the mipmap chain
+    Reserved1: array[0..10] of LongWord; // Reserved
+    PixelFormat: TDDPixelFormat; // Format of the pixel data
+    Caps: TDDSCaps;       // Capabilities
+    Reserved2: LongWord;  // Reserved
+  end;
+
+  { DDS file header.}
+  TDDSFileHeader = packed record
+    Magic: LongWord;       // File format magic
+    Desc: TDDSurfaceDesc2; // Surface description
+  end;
+
+  { Resoirce types for D3D 10+ }
+  TD3D10ResourceDimension = (
+    D3D10_RESOURCE_DIMENSION_UNKNOWN   = 0,
+    D3D10_RESOURCE_DIMENSION_BUFFER    = 1,
+    D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2,
+    D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3,
+    D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4
+  );
+
+  { Texture formats for D3D 10+ }
+  TDXGIFormat = (
+    DXGI_FORMAT_UNKNOWN                      = 0,
+    DXGI_FORMAT_R32G32B32A32_TYPELESS        = 1,
+    DXGI_FORMAT_R32G32B32A32_FLOAT           = 2,
+    DXGI_FORMAT_R32G32B32A32_UINT            = 3,
+    DXGI_FORMAT_R32G32B32A32_SINT            = 4,
+    DXGI_FORMAT_R32G32B32_TYPELESS           = 5,
+    DXGI_FORMAT_R32G32B32_FLOAT              = 6,
+    DXGI_FORMAT_R32G32B32_UINT               = 7,
+    DXGI_FORMAT_R32G32B32_SINT               = 8,
+    DXGI_FORMAT_R16G16B16A16_TYPELESS        = 9,
+    DXGI_FORMAT_R16G16B16A16_FLOAT           = 10,
+    DXGI_FORMAT_R16G16B16A16_UNORM           = 11,
+    DXGI_FORMAT_R16G16B16A16_UINT            = 12,
+    DXGI_FORMAT_R16G16B16A16_SNORM           = 13,
+    DXGI_FORMAT_R16G16B16A16_SINT            = 14,
+    DXGI_FORMAT_R32G32_TYPELESS              = 15,
+    DXGI_FORMAT_R32G32_FLOAT                 = 16,
+    DXGI_FORMAT_R32G32_UINT                  = 17,
+    DXGI_FORMAT_R32G32_SINT                  = 18,
+    DXGI_FORMAT_R32G8X24_TYPELESS            = 19,
+    DXGI_FORMAT_D32_FLOAT_S8X24_UINT         = 20,
+    DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS     = 21,
+    DXGI_FORMAT_X32_TYPELESS_G8X24_UINT      = 22,
+    DXGI_FORMAT_R10G10B10A2_TYPELESS         = 23,
+    DXGI_FORMAT_R10G10B10A2_UNORM            = 24,
+    DXGI_FORMAT_R10G10B10A2_UINT             = 25,
+    DXGI_FORMAT_R11G11B10_FLOAT              = 26,
+    DXGI_FORMAT_R8G8B8A8_TYPELESS            = 27,
+    DXGI_FORMAT_R8G8B8A8_UNORM               = 28,
+    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB          = 29,
+    DXGI_FORMAT_R8G8B8A8_UINT                = 30,
+    DXGI_FORMAT_R8G8B8A8_SNORM               = 31,
+    DXGI_FORMAT_R8G8B8A8_SINT                = 32,
+    DXGI_FORMAT_R16G16_TYPELESS              = 33,
+    DXGI_FORMAT_R16G16_FLOAT                 = 34,
+    DXGI_FORMAT_R16G16_UNORM                 = 35,
+    DXGI_FORMAT_R16G16_UINT                  = 36,
+    DXGI_FORMAT_R16G16_SNORM                 = 37,
+    DXGI_FORMAT_R16G16_SINT                  = 38,
+    DXGI_FORMAT_R32_TYPELESS                 = 39,
+    DXGI_FORMAT_D32_FLOAT                    = 40,
+    DXGI_FORMAT_R32_FLOAT                    = 41,
+    DXGI_FORMAT_R32_UINT                     = 42,
+    DXGI_FORMAT_R32_SINT                     = 43,
+    DXGI_FORMAT_R24G8_TYPELESS               = 44,
+    DXGI_FORMAT_D24_UNORM_S8_UINT            = 45,
+    DXGI_FORMAT_R24_UNORM_X8_TYPELESS        = 46,
+    DXGI_FORMAT_X24_TYPELESS_G8_UINT         = 47,
+    DXGI_FORMAT_R8G8_TYPELESS                = 48,
+    DXGI_FORMAT_R8G8_UNORM                   = 49,
+    DXGI_FORMAT_R8G8_UINT                    = 50,
+    DXGI_FORMAT_R8G8_SNORM                   = 51,
+    DXGI_FORMAT_R8G8_SINT                    = 52,
+    DXGI_FORMAT_R16_TYPELESS                 = 53,
+    DXGI_FORMAT_R16_FLOAT                    = 54,
+    DXGI_FORMAT_D16_UNORM                    = 55,
+    DXGI_FORMAT_R16_UNORM                    = 56,
+    DXGI_FORMAT_R16_UINT                     = 57,
+    DXGI_FORMAT_R16_SNORM                    = 58,
+    DXGI_FORMAT_R16_SINT                     = 59,
+    DXGI_FORMAT_R8_TYPELESS                  = 60,
+    DXGI_FORMAT_R8_UNORM                     = 61,
+    DXGI_FORMAT_R8_UINT                      = 62,
+    DXGI_FORMAT_R8_SNORM                     = 63,
+    DXGI_FORMAT_R8_SINT                      = 64,
+    DXGI_FORMAT_A8_UNORM                     = 65,
+    DXGI_FORMAT_R1_UNORM                     = 66,
+    DXGI_FORMAT_R9G9B9E5_SHAREDEXP           = 67,
+    DXGI_FORMAT_R8G8_B8G8_UNORM              = 68,
+    DXGI_FORMAT_G8R8_G8B8_UNORM              = 69,
+    DXGI_FORMAT_BC1_TYPELESS                 = 70,
+    DXGI_FORMAT_BC1_UNORM                    = 71,
+    DXGI_FORMAT_BC1_UNORM_SRGB               = 72,
+    DXGI_FORMAT_BC2_TYPELESS                 = 73,
+    DXGI_FORMAT_BC2_UNORM                    = 74,
+    DXGI_FORMAT_BC2_UNORM_SRGB               = 75,
+    DXGI_FORMAT_BC3_TYPELESS                 = 76,
+    DXGI_FORMAT_BC3_UNORM                    = 77,
+    DXGI_FORMAT_BC3_UNORM_SRGB               = 78,
+    DXGI_FORMAT_BC4_TYPELESS                 = 79,
+    DXGI_FORMAT_BC4_UNORM                    = 80,
+    DXGI_FORMAT_BC4_SNORM                    = 81,
+    DXGI_FORMAT_BC5_TYPELESS                 = 82,
+    DXGI_FORMAT_BC5_UNORM                    = 83,
+    DXGI_FORMAT_BC5_SNORM                    = 84,
+    DXGI_FORMAT_B5G6R5_UNORM                 = 85,
+    DXGI_FORMAT_B5G5R5A1_UNORM               = 86,
+    DXGI_FORMAT_B8G8R8A8_UNORM               = 87,
+    DXGI_FORMAT_B8G8R8X8_UNORM               = 88,
+    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM   = 89,
+    DXGI_FORMAT_B8G8R8A8_TYPELESS            = 90,
+    DXGI_FORMAT_B8G8R8A8_UNORM_SRGB          = 91,
+    DXGI_FORMAT_B8G8R8X8_TYPELESS            = 92,
+    DXGI_FORMAT_B8G8R8X8_UNORM_SRGB          = 93,
+    DXGI_FORMAT_BC6H_TYPELESS                = 94,
+    DXGI_FORMAT_BC6H_UF16                    = 95,
+    DXGI_FORMAT_BC6H_SF16                    = 96,
+    DXGI_FORMAT_BC7_TYPELESS                 = 97,
+    DXGI_FORMAT_BC7_UNORM                    = 98,
+    DXGI_FORMAT_BC7_UNORM_SRGB               = 99,
+    DXGI_FORMAT_AYUV                         = 100,
+    DXGI_FORMAT_Y410                         = 101,
+    DXGI_FORMAT_Y416                         = 102,
+    DXGI_FORMAT_NV12                         = 103,
+    DXGI_FORMAT_P010                         = 104,
+    DXGI_FORMAT_P016                         = 105,
+    DXGI_FORMAT_420_OPAQUE                   = 106,
+    DXGI_FORMAT_YUY2                         = 107,
+    DXGI_FORMAT_Y210                         = 108,
+    DXGI_FORMAT_Y216                         = 109,
+    DXGI_FORMAT_NV11                         = 110,
+    DXGI_FORMAT_AI44                         = 111,
+    DXGI_FORMAT_IA44                         = 112,
+    DXGI_FORMAT_P8                           = 113,
+    DXGI_FORMAT_A8P8                         = 114,
+    DXGI_FORMAT_B4G4R4A4_UNORM               = 115
+  );
+
+  { DX10 extension header for DDS file format }
+  TDX10Header = packed record
+    DXGIFormat: TDXGIFormat;
+    ResourceDimension: TD3D10ResourceDimension;
+    MiscFlags: LongWord;
+    ArraySize: LongWord;
+    Reserved: LongWord;
+  end;
+
+{ TDDSFileFormat class implementation }
+
+procedure TDDSFileFormat.Define;
+begin
+  inherited;
+  FName := SDDSFormatName;
+  FFeatures := [ffLoad, ffSave, ffMultiImage];
+  FSupportedFormats := DDSSupportedFormats;
+
+  FSaveCubeMap := False;
+  FSaveVolume := False;
+  FSaveMipMapCount := 1;
+  FSaveDepth := 1;
+
+  AddMasks(SDDSMasks);
+
+  RegisterOption(ImagingDDSLoadedCubeMap, @FLoadedCubeMap);
+  RegisterOption(ImagingDDSLoadedVolume, @FLoadedVolume);
+  RegisterOption(ImagingDDSLoadedMipMapCount, @FLoadedMipMapCount);
+  RegisterOption(ImagingDDSLoadedDepth, @FLoadedDepth);
+  RegisterOption(ImagingDDSSaveCubeMap, @FSaveCubeMap);
+  RegisterOption(ImagingDDSSaveVolume, @FSaveVolume);
+  RegisterOption(ImagingDDSSaveMipMapCount, @FSaveMipMapCount);
+  RegisterOption(ImagingDDSSaveDepth, @FSaveDepth);
+end;
+
+procedure TDDSFileFormat.CheckOptionsValidity;
+begin
+  if FSaveCubeMap then
+    FSaveVolume := False;
+  if FSaveVolume then
+    FSaveCubeMap := False;
+  if FSaveDepth < 1 then
+    FSaveDepth := 1;
+  if FSaveMipMapCount < 1 then
+    FSaveMipMapCount := 1;
+end;
+
+procedure TDDSFileFormat.ComputeSubDimensions(Idx, Width, Height, MipMaps, Depth: LongInt;
+  IsCubeMap, IsVolume: Boolean; var CurWidth, CurHeight: LongInt);
+var
+  I, Last, Shift: LongInt;
+begin
+  CurWidth := Width;
+  CurHeight := Height;
+  if MipMaps > 1 then
+  begin
+    if not IsVolume then
+    begin
+      if IsCubeMap then
+      begin
+        // Cube maps are stored like this
+        // Face 0 mimap 0
+        // Face 0 mipmap 1
+        // ...
+        // Face 1 mipmap 0
+        // Face 1 mipmap 1
+        // ...
+
+        // Modify index so later in for loop we iterate less times
+        Idx := Idx - ((Idx div MipMaps) * MipMaps);
+      end;
+      for I := 0 to Idx - 1 do
+      begin
+        CurWidth := ClampInt(CurWidth shr 1, 1, CurWidth);
+        CurHeight := ClampInt(CurHeight shr 1, 1, CurHeight);
+      end;
+    end
+    else
+    begin
+      // Volume textures are stored in DDS files like this:
+      // Slice 0 mipmap 0
+      // Slice 1 mipmap 0
+      // Slice 2 mipmap 0
+      // Slice 3 mipmap 0
+      // Slice 0 mipmap 1
+      // Slice 1 mipmap 1
+      // Slice 0 mipmap 2
+      // Slice 0 mipmap 3 ...
+      Shift := 0;
+      Last := Depth;
+      while Idx > Last - 1 do
+      begin
+        CurWidth := ClampInt(CurWidth shr 1, 1, CurWidth);
+        CurHeight := ClampInt(CurHeight shr 1, 1, CurHeight);
+        if (CurWidth = 1) and (CurHeight = 1) then
+          Break;
+        Inc(Shift);
+        Inc(Last, ClampInt(Depth shr Shift, 1, Depth));
+      end;
+    end;
+  end;
+end;
+
+function TDDSFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Hdr: TDDSFileHeader;
+  HdrDX10: TDX10Header;
+  SrcFormat: TImageFormat;
+  FmtInfo: TImageFormatInfo;
+  NeedsSwapChannels: Boolean;
+  CurrentWidth, CurrentHeight, ImageCount, LoadSize, I,
+    PitchOrLinear, MainImageLinearSize: Integer;
+  Data: PByte;
+  UseAsPitch: Boolean;
+  UseAsLinear: Boolean;
+
+  function MasksEqual(const DDPF: TDDPixelFormat; PF: PPixelFormatInfo): Boolean;
+  begin
+    Result := (DDPF.AlphaMask = PF.ABitMask) and
+      (DDPF.RedMask = PF.RBitMask) and (DDPF.GreenMask = PF.GBitMask) and
+      (DDPF.BlueMask = PF.BBitMask);
+  end;
+
+  function FindFourCCFormat(FourCC: LongWord): TImageFormat;
+  begin
+    // Handle FourCC and large ARGB formats
+    case FourCC of
+      D3DFMT_A16B16G16R16: Result := ifA16B16G16R16;
+      D3DFMT_R32F: Result := ifR32F;
+      D3DFMT_A32B32G32R32F: Result := ifA32B32G32R32F;
+      D3DFMT_R16F: Result := ifR16F;
+      D3DFMT_A16B16G16R16F: Result := ifA16B16G16R16F;
+      FOURCC_DXT1: Result := ifDXT1;
+      FOURCC_DXT3: Result := ifDXT3;
+      FOURCC_DXT5: Result := ifDXT5;
+      FOURCC_ATI1: Result := ifATI1N;
+      FOURCC_ATI2: Result := ifATI2N;
+    else
+      Result := ifUnknown;
+    end;
+  end;
+
+  function FindDX10Format(DXGIFormat: TDXGIFormat; var NeedsSwapChannels: Boolean): TImageFormat;
+  begin
+    Result := ifUnknown;
+    NeedsSwapChannels := False;
+
+    case DXGIFormat of
+      DXGI_FORMAT_UNKNOWN: ;
+      DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_FLOAT:
+        Result := ifA32B32G32R32F;
+      DXGI_FORMAT_R32G32B32A32_UINT: ;
+      DXGI_FORMAT_R32G32B32A32_SINT: ;
+      DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_FLOAT:
+        Result := ifB32G32R32F;
+      DXGI_FORMAT_R32G32B32_UINT: ;
+      DXGI_FORMAT_R32G32B32_SINT: ;
+      DXGI_FORMAT_R16G16B16A16_FLOAT:
+        Result := ifA16B16G16R16F;
+      DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM,
+      DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SNORM,
+      DXGI_FORMAT_R16G16B16A16_SINT:
+        Result := ifA16B16G16R16;
+      DXGI_FORMAT_R32G32_TYPELESS: ;
+      DXGI_FORMAT_R32G32_FLOAT: ;
+      DXGI_FORMAT_R32G32_UINT: ;
+      DXGI_FORMAT_R32G32_SINT: ;
+      DXGI_FORMAT_R32G8X24_TYPELESS: ;
+      DXGI_FORMAT_D32_FLOAT_S8X24_UINT: ;
+      DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: ;
+      DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: ;
+      DXGI_FORMAT_R10G10B10A2_TYPELESS: ;
+      DXGI_FORMAT_R10G10B10A2_UNORM: ;
+      DXGI_FORMAT_R10G10B10A2_UINT: ;
+      DXGI_FORMAT_R11G11B10_FLOAT: ;
+      DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM,
+      DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_SNORM,DXGI_FORMAT_R8G8B8A8_SINT,
+      DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+        begin
+          Result := ifA8R8G8B8;
+          NeedsSwapChannels := True;
+        end;
+      DXGI_FORMAT_R16G16_TYPELESS: ;
+      DXGI_FORMAT_R16G16_FLOAT: ;
+      DXGI_FORMAT_R16G16_UNORM: ;
+      DXGI_FORMAT_R16G16_UINT: ;
+      DXGI_FORMAT_R16G16_SNORM: ;
+      DXGI_FORMAT_R16G16_SINT: ;
+      DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_SINT:
+        Result := ifGray32;
+      DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_R32_FLOAT:
+        Result := ifR32F;
+      DXGI_FORMAT_R24G8_TYPELESS: ;
+      DXGI_FORMAT_D24_UNORM_S8_UINT: ;
+      DXGI_FORMAT_R24_UNORM_X8_TYPELESS: ;
+      DXGI_FORMAT_X24_TYPELESS_G8_UINT: ;
+      DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UINT,
+      DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SINT:
+        Result := ifA8Gray8;
+      DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_R16_UNORM,
+      DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_SINT:
+        Result := ifGray16;
+      DXGI_FORMAT_R16_FLOAT:
+        Result := ifR16F;
+      DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UINT,
+      DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_A8_UNORM:
+        Result := ifGray8;
+      DXGI_FORMAT_R1_UNORM: ;
+      DXGI_FORMAT_R9G9B9E5_SHAREDEXP: ;
+      DXGI_FORMAT_R8G8_B8G8_UNORM: ;
+      DXGI_FORMAT_G8R8_G8B8_UNORM: ;
+      DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB:
+        Result := ifDXT1;
+      DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB:
+        Result := ifDXT3;
+      DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB:
+        Result := ifDXT5;
+      DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM:
+        Result := ifATI1N;
+      DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM:
+        Result := ifATI2N;
+      DXGI_FORMAT_B5G6R5_UNORM:
+        Result := ifR5G6B5;
+      DXGI_FORMAT_B5G5R5A1_UNORM:
+        Result := ifA1R5G5B5;
+      DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_TYPELESS:
+        Result := ifA8R8G8B8;
+      DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8X8_TYPELESS:
+        Result := ifX8R8G8B8;
+      DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: ;
+      DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: ;
+      DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: ;
+      DXGI_FORMAT_BC6H_TYPELESS: ;
+      DXGI_FORMAT_BC6H_UF16: ;
+      DXGI_FORMAT_BC6H_SF16: ;
+      DXGI_FORMAT_BC7_TYPELESS: ;
+      DXGI_FORMAT_BC7_UNORM: ;
+      DXGI_FORMAT_BC7_UNORM_SRGB: ;
+      DXGI_FORMAT_P8: ;
+      DXGI_FORMAT_A8P8: ;
+      DXGI_FORMAT_B4G4R4A4_UNORM:
+        Result := ifA4R4G4B4;
+    end;
+  end;
+
+begin
+  Result := False;
+  ImageCount := 1;
+  FLoadedMipMapCount := 1;
+  FLoadedDepth := 1;
+  FLoadedVolume := False;
+  FLoadedCubeMap := False;
+  ZeroMemory(@HdrDX10, SizeOf(HdrDX10));
+
+  with GetIO, Hdr, Hdr.Desc.PixelFormat do
+  begin
+    Read(Handle, @Hdr, SizeOf(Hdr));
+
+    SrcFormat := ifUnknown;
+    NeedsSwapChannels := False;
+
+    // Get image data format
+    if (Flags and DDPF_FOURCC) = DDPF_FOURCC then
+    begin
+      if FourCC = FOURCC_DX10 then
+      begin
+        Read(Handle, @HdrDX10, SizeOf(HdrDX10));
+        SrcFormat := FindDX10Format(HdrDX10.DXGIFormat, NeedsSwapChannels);
+        FMetadata.SetMetaItem(SMetaDdsDxgiFormat, HdrDX10.DXGIFormat);
+        FMetadata.SetMetaItem(SMetaDdsArraySize, HdrDX10.ArraySize);
+      end
+      else
+        SrcFormat := FindFourCCFormat(FourCC);
+    end
+    else if (Flags and DDPF_RGB) = DDPF_RGB then
+    begin
+      // Handle RGB formats
+      if (Flags and DDPF_ALPHAPIXELS) = DDPF_ALPHAPIXELS then
+      begin
+        // Handle RGB with alpha formats
+        case BitCount of
+          16:
+            begin
+              if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifA4R4G4B4).PixelFormat) then
+                SrcFormat := ifA4R4G4B4;
+              if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifA1R5G5B5).PixelFormat) then
+                SrcFormat := ifA1R5G5B5;
+            end;
+          32:
+            begin
+              SrcFormat := ifA8R8G8B8;
+              if BlueMask = $00FF0000 then
+                NeedsSwapChannels := True;
+            end;
+        end;
+      end
+      else
+      begin
+        // Handle RGB without alpha formats
+        case BitCount of
+          8:
+            if MasksEqual(Desc.PixelFormat,
+              GetFormatInfo(ifR3G3B2).PixelFormat) then
+              SrcFormat := ifR3G3B2;
+          16:
+            begin
+              if MasksEqual(Desc.PixelFormat,
+                GetFormatInfo(ifX4R4G4B4).PixelFormat) then
+                SrcFormat := ifX4R4G4B4;
+              if MasksEqual(Desc.PixelFormat,
+                GetFormatInfo(ifX1R5G5B5).PixelFormat) then
+                SrcFormat := ifX1R5G5B5;
+              if MasksEqual(Desc.PixelFormat,
+                GetFormatInfo(ifR5G6B5).PixelFormat) then
+                SrcFormat := ifR5G6B5;
+            end;
+          24: SrcFormat := ifR8G8B8;
+          32:
+            begin
+              SrcFormat := ifX8R8G8B8;
+              if BlueMask = $00FF0000 then
+                NeedsSwapChannels := True;
+            end;
+        end;
+      end;
+    end
+    else if (Flags and DDPF_LUMINANCE) = DDPF_LUMINANCE then
+    begin
+      // Handle luminance formats
+      if (Flags and DDPF_ALPHAPIXELS) = DDPF_ALPHAPIXELS then
+      begin
+        // Handle luminance with alpha formats
+        if BitCount = 16 then
+          SrcFormat := ifA8Gray8;
+      end
+      else
+      begin
+        // Handle luminance without alpha formats
+        case BitCount of
+          8: SrcFormat := ifGray8;
+          16: SrcFormat := ifGray16;
+        end;
+      end;
+    end
+    else if (Flags and DDPF_BUMPLUMINANCE) = DDPF_BUMPLUMINANCE then
+    begin
+      // Handle mixed bump-luminance formats like D3DFMT_X8L8V8U8
+      case BitCount of
+        32:
+          if BlueMask = $00FF0000 then
+          begin
+            SrcFormat := ifX8R8G8B8; // D3DFMT_X8L8V8U8
+            NeedsSwapChannels := True;
+          end;
+      end;
+    end
+    else if (Flags and DDPF_BUMPDUDV) = DDPF_BUMPDUDV then
+    begin
+      // Handle bumpmap formats like D3DFMT_Q8W8V8U8
+      case BitCount of
+        16: SrcFormat := ifA8Gray8; // D3DFMT_V8U8
+        32:
+          if AlphaMask = $FF000000 then
+          begin
+            SrcFormat := ifA8R8G8B8; // D3DFMT_Q8W8V8U8
+            NeedsSwapChannels := True;
+          end;
+        64: SrcFormat := ifA16B16G16R16; // D3DFMT_Q16W16V16U16
+      end;
+    end;
+
+    // If DDS format is not supported we will exit
+    if SrcFormat = ifUnknown then
+      Exit;
+
+    // File contains mipmaps for each subimage.
+    { Some DDS writers ignore setting proper Caps and Flags so
+      this check is not usable:
+    if ((Desc.Caps.Caps1 and DDSCAPS_MIPMAP) = DDSCAPS_MIPMAP) and
+      ((Desc.Flags and DDSD_MIPMAPCOUNT) = DDSD_MIPMAPCOUNT) then}
+    if Desc.MipMaps > 1 then
+    begin
+      FLoadedMipMapCount := Desc.MipMaps;
+      FMetadata.SetMetaItem(SMetaDdsMipMapCount, Desc.MipMaps);
+      ImageCount := Desc.MipMaps;
+    end;
+
+    // File stores volume texture
+    if ((Desc.Caps.Caps2 and DDSCAPS2_VOLUME) = DDSCAPS2_VOLUME) and
+      ((Desc.Flags and DDSD_DEPTH) = DDSD_DEPTH) then
+    begin
+      FLoadedVolume := True;
+      FLoadedDepth := Desc.Depth;
+      ImageCount := GetVolumeLevelCount(Desc.Depth, ImageCount);
+    end;
+
+    // File stores cube texture
+    if (Desc.Caps.Caps2 and DDSCAPS2_CUBEMAP) = DDSCAPS2_CUBEMAP then
+    begin
+      FLoadedCubeMap := True;
+      I := 0;
+      if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEX) = DDSCAPS2_POSITIVEX then Inc(I);
+      if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEY) = DDSCAPS2_POSITIVEY then Inc(I);
+      if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEZ) = DDSCAPS2_POSITIVEZ then Inc(I);
+      if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEX) = DDSCAPS2_NEGATIVEX then Inc(I);
+      if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEY) = DDSCAPS2_NEGATIVEY then Inc(I);
+      if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEZ) = DDSCAPS2_NEGATIVEZ then Inc(I);
+      FLoadedDepth := I;
+      ImageCount := ImageCount * I;
+    end;
+
+    // Allocate and load all images in file
+    FmtInfo := GetFormatInfo(SrcFormat);
+    SetLength(Images, ImageCount);
+
+    // Compute the pitch or get if from file if present
+    UseAsPitch := (Desc.Flags and DDSD_PITCH) = DDSD_PITCH;
+    UseAsLinear := (Desc.Flags and DDSD_LINEARSIZE) = DDSD_LINEARSIZE;
+    // Use linear as default if none is set
+    if not UseAsPitch and not UseAsLinear then
+      UseAsLinear := True;
+    // Main image pitch or linear size
+    PitchOrLinear := Desc.PitchOrLinearSize;
+
+    // Check: some writers just write garbage to pitch/linear size fields and flags
+    MainImageLinearSize := FmtInfo.GetPixelsSize(SrcFormat, Desc.Width, Desc.Height);
+    if UseAsLinear and ((PitchOrLinear < MainImageLinearSize) or
+      (PitchOrLinear * Integer(Desc.Height) = MainImageLinearSize)) then
+    begin
+      // Explicitly set linear size
+      PitchOrLinear := MainImageLinearSize;
+    end;
+
+    for I := 0 to ImageCount - 1 do
+    begin
+      // Compute dimensions of surrent subimage based on texture type and
+      // number of mipmaps
+      ComputeSubDimensions(I, Desc.Width, Desc.Height, Desc.MipMaps, Desc.Depth,
+        FLoadedCubeMap, FLoadedVolume, CurrentWidth, CurrentHeight);
+      NewImage(CurrentWidth, CurrentHeight, SrcFormat, Images[I]);
+
+      if (I > 0) or (PitchOrLinear = 0) then
+      begin
+        // Compute pitch or linear size for mipmap levels, or even for main image
+        // since some formats do not fill pitch nor size
+        if UseAsLinear then
+          PitchOrLinear := FmtInfo.GetPixelsSize(SrcFormat, CurrentWidth, CurrentHeight)
+        else
+          PitchOrLinear := (CurrentWidth * FmtInfo.BytesPerPixel + 3) div 4 * 4; // must be DWORD aligned
+      end;
+
+      if UseAsLinear then
+        LoadSize := PitchOrLinear
+      else
+        LoadSize := CurrentHeight * PitchOrLinear;
+
+      if UseAsLinear or (LoadSize = Images[I].Size) then
+      begin
+        // If DDS does not use Pitch we can simply copy data
+        Read(Handle, Images[I].Bits, LoadSize)
+      end
+      else
+      begin
+        // If DDS uses Pitch we must load aligned scanlines
+        // and then remove padding
+        GetMem(Data, LoadSize);
+        try
+          Read(Handle, Data, LoadSize);
+          RemovePadBytes(Data, Images[I].Bits, CurrentWidth, CurrentHeight,
+            FmtInfo.BytesPerPixel, PitchOrLinear);
+       finally
+          FreeMem(Data);
+        end;
+      end;
+
+      if NeedsSwapChannels then
+        SwapChannels(Images[I], ChannelRed, ChannelBlue);
+    end;
+    Result := True;
+  end;
+end;
+
+function TDDSFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+var
+  Hdr: TDDSFileHeader;
+  MainImage, ImageToSave: TImageData;
+  I, MainIdx, Len, ImageCount: LongInt;
+  J: LongWord;
+  FmtInfo: TImageFormatInfo;
+  MustBeFreed: Boolean;
+  Is2DTexture, IsCubeMap, IsVolume: Boolean;
+  MipMapCount, CurrentWidth, CurrentHeight: LongInt;
+  NeedsResize: Boolean;
+  NeedsConvert: Boolean;
+begin
+  Result := False;
+  FillChar(Hdr, Sizeof(Hdr), 0);
+
+  MainIdx := FFirstIdx;
+  Len := FLastIdx - MainIdx + 1;
+  // Some DDS saving rules:
+  //   2D textures: Len is used as mipmap count (FSaveMipMapCount not used!).
+  //   Cube maps:   FSaveDepth * FSaveMipMapCount images are used, if Len is
+  //                smaller than this file is saved as regular 2D texture.
+  //   Volume maps: GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount) images are
+  //                used, if Len is smaller than this file is
+  //                saved as regular 2D texture.
+
+  IsCubeMap := FSaveCubeMap;
+  IsVolume := FSaveVolume;
+  MipMapCount := FSaveMipMapCount;
+
+  if IsCubeMap then
+  begin
+    // Check if we have enough images on Input to save cube map
+    if Len < FSaveDepth * FSaveMipMapCount then
+      IsCubeMap := False;
+  end
+  else if IsVolume then
+  begin
+    // Check if we have enough images on Input to save volume texture
+    if Len < GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount) then
+      IsVolume := False;
+  end;
+
+  Is2DTexture := not IsCubeMap and not IsVolume;
+  if Is2DTexture then
+  begin
+    // Get number of mipmaps used with 2D texture
+    MipMapCount := Min(Len, GetNumMipMapLevels(Images[MainIdx].Width, Images[MainIdx].Height));
+  end;
+
+  // we create compatible main image and fill headers
+  if MakeCompatible(Images[MainIdx], MainImage, MustBeFreed) then
+  with GetIO, MainImage, Hdr do
+  try
+    FmtInfo := GetFormatInfo(Format);
+    Magic := DDSMagic;
+    Desc.Size := SizeOf(Desc);
+    Desc.Width := Width;
+    Desc.Height := Height;
+    Desc.Flags := DDS_SAVE_FLAGS;
+    Desc.Caps.Caps1 := DDSCAPS_TEXTURE;
+    Desc.PixelFormat.Size := SizeOf(Desc.PixelFormat);
+    Desc.PitchOrLinearSize := MainImage.Size;
+    ImageCount := MipMapCount;
+
+    if MipMapCount > 1 then
+    begin
+      // Set proper flags if we have some mipmaps to be saved
+      Desc.Flags := Desc.Flags or DDSD_MIPMAPCOUNT;
+      Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_MIPMAP or DDSCAPS_COMPLEX;
+      Desc.MipMaps := MipMapCount;
+    end;
+
+    if IsCubeMap then
+    begin
+      // Set proper cube map flags - number of stored faces is taken
+      // from FSaveDepth
+      Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_COMPLEX;
+      Desc.Caps.Caps2 := Desc.Caps.Caps2 or DDSCAPS2_CUBEMAP;
+      J := DDSCAPS2_POSITIVEX;
+      for I := 0 to FSaveDepth - 1 do
+      begin
+        Desc.Caps.Caps2 := Desc.Caps.Caps2 or J;
+        J := J shl 1;
+      end;
+      ImageCount := FSaveDepth * FSaveMipMapCount;
+    end
+    else if IsVolume then
+    begin
+      // Set proper flags for volume texture
+      Desc.Flags := Desc.Flags or DDSD_DEPTH;
+      Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_COMPLEX;
+      Desc.Caps.Caps2 := Desc.Caps.Caps2 or DDSCAPS2_VOLUME;
+      Desc.Depth := FSaveDepth;
+      ImageCount := GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount);
+    end;
+
+    // Now we set DDS pixel format for main image
+    if FmtInfo.IsSpecial or FmtInfo.IsFloatingPoint or
+      (FmtInfo.BytesPerPixel > 4) then
+    begin
+      Desc.PixelFormat.Flags := DDPF_FOURCC;
+      case Format of
+        ifA16B16G16R16:  Desc.PixelFormat.FourCC := D3DFMT_A16B16G16R16;
+        ifR32F:          Desc.PixelFormat.FourCC := D3DFMT_R32F;
+        ifA32B32G32R32F: Desc.PixelFormat.FourCC := D3DFMT_A32B32G32R32F;
+        ifR16F:          Desc.PixelFormat.FourCC := D3DFMT_R16F;
+        ifA16B16G16R16F: Desc.PixelFormat.FourCC := D3DFMT_A16B16G16R16F;
+        ifDXT1:          Desc.PixelFormat.FourCC := FOURCC_DXT1;
+        ifDXT3:          Desc.PixelFormat.FourCC := FOURCC_DXT3;
+        ifDXT5:          Desc.PixelFormat.FourCC := FOURCC_DXT5;
+        ifATI1N:         Desc.PixelFormat.FourCC := FOURCC_ATI1;
+        ifATI2N:         Desc.PixelFormat.FourCC := FOURCC_ATI2;
+      end;
+    end
+    else if FmtInfo.HasGrayChannel then
+    begin
+      Desc.PixelFormat.Flags := DDPF_LUMINANCE;
+      Desc.PixelFormat.BitCount := FmtInfo.BytesPerPixel * 8;
+      case Format of
+        ifGray8:  Desc.PixelFormat.RedMask := 255;
+        ifGray16: Desc.PixelFormat.RedMask := 65535;
+        ifA8Gray8:
+          begin
+            Desc.PixelFormat.Flags := Desc.PixelFormat.Flags or DDPF_ALPHAPIXELS;
+            Desc.PixelFormat.RedMask := 255;
+            Desc.PixelFormat.AlphaMask := 65280;
+          end;
+      end;
+    end
+    else
+    begin
+      Desc.PixelFormat.Flags := DDPF_RGB;
+      Desc.PixelFormat.BitCount := FmtInfo.BytesPerPixel * 8;
+      if FmtInfo.HasAlphaChannel then
+      begin
+        Desc.PixelFormat.Flags := Desc.PixelFormat.Flags or DDPF_ALPHAPIXELS;
+        Desc.PixelFormat.AlphaMask := $FF000000;
+      end;
+      if FmtInfo.BytesPerPixel > 2 then
+      begin
+        Desc.PixelFormat.RedMask :=   $00FF0000;
+        Desc.PixelFormat.GreenMask := $0000FF00;
+        Desc.PixelFormat.BlueMask :=  $000000FF;
+      end
+      else
+      begin
+        Desc.PixelFormat.AlphaMask := FmtInfo.PixelFormat.ABitMask;
+        Desc.PixelFormat.RedMask := FmtInfo.PixelFormat.RBitMask;
+        Desc.PixelFormat.GreenMask := FmtInfo.PixelFormat.GBitMask;
+        Desc.PixelFormat.BlueMask := FmtInfo.PixelFormat.BBitMask;
+      end;
+    end;
+
+    // Header and main image are written to output
+    Write(Handle, @Hdr, SizeOf(Hdr));
+    Write(Handle, MainImage.Bits, MainImage.Size);
+
+    // Write the rest of the images and convert them to
+    // the same format as main image if necessary and ensure proper mipmap
+    // simensions too.
+    for I := MainIdx + 1 to MainIdx + ImageCount - 1 do
+    begin
+      // Get proper dimensions for this level
+      ComputeSubDimensions(I, Desc.Width, Desc.Height, Desc.MipMaps, Desc.Depth,
+        IsCubeMap, IsVolume, CurrentWidth, CurrentHeight);
+
+      // Check if input image for this level has the right size and format
+      NeedsResize := not ((Images[I].Width = CurrentWidth) and (Images[I].Height = CurrentHeight));
+      NeedsConvert := not (Images[I].Format = Format);
+
+      if NeedsResize or NeedsConvert then
+      begin
+        // Input image must be resized or converted to different format
+        // to become valid mipmap level
+        InitImage(ImageToSave);
+        CloneImage(Images[I], ImageToSave);
+        if NeedsConvert then
+          ConvertImage(ImageToSave, Format);
+        if NeedsResize then
+          ResizeImage(ImageToSave, CurrentWidth, CurrentHeight, rfBilinear);
+      end
+      else
+        // Input image can be used without any changes
+        ImageToSave := Images[I];
+
+      // Write level data and release temp image if necessary
+      Write(Handle, ImageToSave.Bits, ImageToSave.Size);
+      if Images[I].Bits <> ImageToSave.Bits then
+        FreeImage(ImageToSave);
+    end;
+
+    Result := True;
+  finally
+    if MustBeFreed then
+      FreeImage(MainImage);
+  end;
+end;
+
+procedure TDDSFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if Info.IsIndexed or Info.IsSpecial then
+    // convert indexed and unsupported special formatd to A8R8G8B8
+    ConvFormat := ifA8R8G8B8
+  else if Info.IsFloatingPoint then
+  begin
+    if Info.Format = ifA16R16G16B16F then
+      // only swap channels here
+      ConvFormat := ifA16B16G16R16F
+    else
+      // convert other floating point formats to A32B32G32R32F
+      ConvFormat := ifA32B32G32R32F
+  end
+  else if Info.HasGrayChannel then
+  begin
+    if Info.HasAlphaChannel then
+      // convert grayscale with alpha to A8Gray8
+      ConvFormat := ifA8Gray8
+    else if Info.BytesPerPixel = 1 then
+      // convert 8bit grayscale to Gray8
+      ConvFormat := ifGray8
+    else
+      // convert 16-64bit grayscales to Gray16
+      ConvFormat := ifGray16;
+  end
+  else if Info.BytesPerPixel > 4 then
+    ConvFormat := ifA16B16G16R16
+  else if Info.HasAlphaChannel then
+    // convert the other images with alpha channel to A8R8G8B8
+    ConvFormat := ifA8R8G8B8
+  else
+    // convert the other formats to X8R8G8B8
+    ConvFormat := ifX8R8G8B8;
+
+  ConvertImage(Image, ConvFormat);
+end;
+
+function TDDSFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Hdr: TDDSFileHeader;
+  ReadCount: LongInt;
+begin
+  Result := False;
+  if Handle <> nil then
+    with GetIO do
+    begin
+      ReadCount := Read(Handle, @Hdr, SizeOf(Hdr));
+      Seek(Handle, -ReadCount, smFromCurrent);
+      Result := (Hdr.Magic = DDSMagic) and (ReadCount = SizeOf(Hdr)) and
+        ((Hdr.Desc.Caps.Caps1 and DDSCAPS_TEXTURE) = DDSCAPS_TEXTURE);
+    end;
+end;
+
+initialization
+  RegisterImageFileFormat(TDDSFileFormat);
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 ----------------------------------------------------
+    - Texture and D3D specific info stored in DDS is now available as metadata
+      (loading).
+    - Added support for loading DDS files with DX10 extension
+      (http://msdn.microsoft.com/en-us/library/windows/desktop/bb943991(v=vs.85).aspx)
+      and few compatibility fixes.
+
+  -- 0.25.0 Changes/Bug Fixes ---------------------------------
+    - Added support for 3Dc ATI1/2 formats.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Saved DDS with mipmaps now correctly defineds COMPLEX flag.
+    - Fixed loading of RGB DDS files that use pitch and have mipmaps -
+      mipmaps were loaded wrongly.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Changed saving behaviour a bit: mipmaps are inlcuded automatically for
+      2D textures if input image array has more than 1 image (no need to
+      set SaveMipMapCount manually).
+    - Mipmap levels are now saved with proper dimensions when saving DDS files.
+    - Made some changes to not be so strict when loading DDS files.
+      Many programs seem to save them in non-standard format
+      (by MS DDS File Reference).
+    - Added missing ifX8R8G8B8 to SupportedFormats, MakeCompatible failed
+      when image was converted to this format (inside).
+    - MakeCompatible method moved to base class, put ConvertToSupported here.
+      GetSupportedFormats removed, it is now set in constructor.
+    - Fixed bug that sometimes saved non-standard DDS files and another
+      one that caused crash when these files were loaded.
+    - Changed extensions to filename masks.
+    - Changed SaveData, LoadData, and MakeCompatible methods according
+      to changes in base class in Imaging unit.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - added support for half-float image formats
+    - change in LoadData to allow support for more images
+      in one stream loading
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - fixed bug in TestFormat which does not recognize many DDS files
+    - changed pitch/linearsize handling in DDS loading code to
+      load DDS files produced by NVidia's Photoshop plugin
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingExtras.pas b/src/lib/vampimg/ImagingExtras.pas
new file mode 100644 (file)
index 0000000..d32f0f9
--- /dev/null
@@ -0,0 +1,153 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This is helper unit that registers all image file formats in Extras package
+  to Imaging core loading and saving functions. Just put this unit in your uses
+  clause instead of adding every unit that provides new file format support.
+  Also new constants for SetOption/GetOption functions for new file formats
+  are located here.}
+unit ImagingExtras;
+
+{$I ImagingOptions.inc}
+
+{$DEFINE DONT_LINK_JPEG2000}    // link support for JPEG2000 images
+{$DEFINE DONT_LINK_TIFF}        // link support for TIFF images
+//{$DEFINE DONT_LINK_PSD}         // link support for PSD images
+//{$DEFINE DONT_LINK_PCX}         // link support for PCX images
+//{$DEFINE DONT_LINK_XPM}         // link support for XPM images
+//{$IFNDEF FULL_FEATURE_SET}
+  {$DEFINE DONT_LINK_ELDER}        // link support for Elder Imagery images
+//{$ENDIF}
+
+{$IF not (
+  (Defined(DCC) and Defined(CPUX86) and not Defined(MACOS)) or
+  (Defined(FPC) and not Defined(MSDOS) and
+    ((Defined(CPUX86) and (Defined(LINUX) or Defined(WIN32) or Defined(MACOS)) or
+     (Defined(CPUX64) and Defined(LINUX)))))
+  )}
+  // JPEG2000 only for 32bit Windows/Linux/OSX and for 64bit Unix with FPC
+  {$DEFINE DONT_LINK_JPEG2000}
+{$IFEND}
+
+{$IF not (Defined(DCC) and Defined(CPUX86) and not Defined(MACOS))}
+  {$DEFINE DONT_LINK_TIFF} // Only for Delphi now
+{$IFEND}
+
+interface
+
+const
+  { Those are new options for GetOption/SetOption interface. }
+
+  { Controls JPEG 2000 lossy compression quality. It is number in range 1..100.
+    1 means small/ugly file, 100 means large/nice file. Default is 80.}
+  ImagingJpeg2000Quality             = 55;
+  { Controls whether JPEG 2000 image is saved with full file headers or just
+    as code stream. Default value is False (0).}
+  ImagingJpeg2000CodeStreamOnly      = 56;
+  { Specifies JPEG 2000 image compression type. If True (1), saved JPEG 2000 files
+    will be losslessly compressed. Otherwise lossy compression is used.
+    Default value is False (0).}
+  ImagingJpeg2000LosslessCompression = 57;
+  { Specifies compression scheme used when saving TIFF images. Supported values
+    are 0 (Uncompressed), 1 (LZW), 2 (PackBits RLE), 3 (Deflate - ZLib), 4 (JPEG),
+    5 (CCITT Group 4 fax encoding - for binary images only).
+    Default is 1 (LZW). Note that not all images can be stored with
+    JPEG compression - these images will be saved with default compression if
+    JPEG is set.}
+  ImagingTiffCompression             = 65;
+  { Controls compression quality when selected TIFF compression is Jpeg.
+    It is number in range 1..100. 1 means small/ugly file,
+    100 means large/nice file. Accessible trough ImagingTiffJpegQuality option.}
+  ImagingTiffJpegQuality             = 66;
+  { When activated (True = 1) existing TIFF files are not overwritten when saving but
+    new images are instead appended thus producing multipage TIFFs.
+    Default value is False (0).}
+  ImagingTiffAppendMode              = 67;
+  { If enabled image data is saved as layer of PSD file. This is required
+    to get proper transparency when opened in Photoshop for images with
+    alpha data (will be opened with one layer, RGB color channels, and transparency).
+    If you don't need this Photoshop compatibility turn this option off as you'll get
+    smaller file (will be opened in PS as background raster with RGBA channels).
+    Default value is True (1). }
+  ImagingPSDSaveAsLayer              = 70;
+
+implementation
+
+uses
+{$IFNDEF DONT_LINK_JPEG2000}
+  ImagingJpeg2000,
+{$ENDIF}
+{$IFNDEF DONT_LINK_TIFF}
+  ImagingLibTiffDelphi,
+{$ENDIF}
+{$IFNDEF DONT_LINK_PSD}
+  ImagingPsd,
+{$ENDIF}
+{$IFNDEF DONT_LINK_PCX}
+  ImagingPcx,
+{$ENDIF}
+{$IFNDEF DONT_LINK_XPM}
+  ImagingXpm,
+{$ENDIF}
+{$IFNDEF DONT_LINK_ELDER}
+  ElderImagery,
+{$ENDIF}
+  Imaging;
+
+{
+  File Notes:
+
+ -- TODOS -----------------------------------------------------
+    - nothing now
+
+  -- 0.77 -----------------------------------------------------
+    - Added ImagingTiffAppendMode option.
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Added Group 4 Fax encoding as compression for TIFF files.
+    - Added ImagingTiffJpegQuality option.
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Allowed JPEG2000 for Mac OS X x86
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - ElderImagery formats are disabled by default, TIFF enabled.
+    - Changed _LINK_ symbols according to changes in ImagingOptions.inc.
+
+  -- 0.24.1 Changes/Bug Fixes ---------------------------------
+    - Allowed JPEG2000 for x86_64 CPUS in Linux
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Better IF conditional to disable JPEG2000 on unsupported platforms.
+    - Added PSD and TIFF related stuff.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Created with initial stuff.
+
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingFormats.pas b/src/lib/vampimg/ImagingFormats.pas
new file mode 100644 (file)
index 0000000..b42b4ac
--- /dev/null
@@ -0,0 +1,4516 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit manages information about all image data formats and contains
+  low level format conversion, manipulation, and other related functions.}
+unit ImagingFormats;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  ImagingTypes, Imaging, ImagingUtility;
+
+type
+  TImageFormatInfoArray = array[TImageFormat] of PImageFormatInfo;
+  PImageFormatInfoArray = ^TImageFormatInfoArray;
+
+
+{ Additional image manipulation functions (usually used internally by Imaging unit) }
+
+type
+  { Color reduction operations.}
+  TReduceColorsAction = (raCreateHistogram, raUpdateHistogram, raMakeColorMap,
+    raMapImage);
+  TReduceColorsActions = set of TReduceColorsAction;
+const
+  AllReduceColorsActions = [raCreateHistogram, raUpdateHistogram,
+    raMakeColorMap, raMapImage];
+{ Reduces the number of colors of source. Src is bits of source image
+  (ARGB or floating point) and Dst is in some indexed format. MaxColors
+  is the number of colors to which reduce and DstPal is palette to which
+  the resulting colors are written and it must be allocated to at least
+  MaxColors entries. ChannelMask is 'anded' with every pixel's channel value
+  when creating color histogram. If $FF is used all 8bits of color channels
+  are used which can be slow for large images with many colors so you can
+  use  lower masks to speed it up.}
+procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte;
+  DstPal: PPalette32; Actions: TReduceColorsActions = AllReduceColorsActions);
+{ Stretches rectangle in source image to rectangle in destination image
+  using nearest neighbor filtering. It is fast but results look blocky
+  because there is no interpolation used. SrcImage and DstImage must be
+  in the same data format. Works for all data formats except special formats.}
+procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt);
+type
+  { Built-in sampling filters.}
+  TSamplingFilter = (sfNearest, sfLinear, sfCosine, sfHermite, sfQuadratic,
+    sfGaussian, sfSpline, sfLanczos, sfMitchell, sfCatmullRom);
+  { Type of custom sampling function}
+  TFilterFunction = function(Value: Single): Single;
+const
+  { Default resampling filter used for bicubic resizing.}
+  DefaultCubicFilter = sfCatmullRom;
+var
+  { Built-in filter functions.}
+  SamplingFilterFunctions: array[TSamplingFilter] of TFilterFunction;
+  { Default radii of built-in filter functions.}
+  SamplingFilterRadii: array[TSamplingFilter] of Single;
+
+{ Stretches rectangle in source image to rectangle in destination image
+  with resampling. One of built-in resampling filters defined by
+  Filter is used. Set WrapEdges to True for seamlessly tileable images.
+  SrcImage and DstImage must be in the same data format.
+  Works for all data formats except special and indexed formats.}
+procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean = False); overload;
+{ Stretches rectangle in source image to rectangle in destination image
+  with resampling. You can use custom sampling function and filter radius.
+  Set WrapEdges to True for seamlessly tileable images. SrcImage and DstImage
+  must be in the same data format.
+  Works for all data formats except special and indexed formats.}
+procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt; Filter: TFilterFunction; Radius: Single;
+  WrapEdges: Boolean = False); overload;
+{ Helper for functions that create mipmap levels. BiggerLevel is
+  valid image and SmallerLevel is empty zeroed image. SmallerLevel is created
+  with Width and Height dimensions and it is filled with pixels of BiggerLevel
+  using resampling filter specified by ImagingMipMapFilter option.
+  Uses StretchNearest and StretchResample internally so the same image data format
+  limitations apply.}
+procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt;
+  var SmallerLevel: TImageData);
+
+
+{ Various helper & support functions }
+
+{ Copies Src pixel to Dest pixel. It is faster than System.Move procedure.}
+procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Compares Src pixel and Dest pixel. It is faster than SysUtils.CompareMem function.}
+function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Translates pixel color in SrcFormat to DstFormat.}
+procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat,
+  DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32);
+{ Clamps floating point pixel channel values to [0.0, 1.0] range.}
+procedure ClampFloatPixel(var PixF: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Helper function that converts pixel in any format to 32bit ARGB pixel.
+  For common formats it's faster than calling GetPixel32 etc.}
+procedure ConvertToPixel32(SrcPix: PByte; DestPix: PColor32Rec;
+  const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32 = nil); {$IFDEF USE_INLINE}inline;{$ENDIF}
+
+{ Adds padding bytes at the ends of scanlines. Bpp is the number of bytes per
+  pixel of source and WidthBytes is the number of bytes per scanlines of dest.}
+procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
+  Bpp, WidthBytes: LongInt);
+{ Removes padding from image with scanlines that have aligned sizes. Bpp is
+  the number of bytes per pixel of dest and WidthBytes is the number of bytes
+  per scanlines of source.}
+procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
+  Bpp, WidthBytes: LongInt);
+
+{ Converts 1bit image data to 8bit. Used mostly by file loaders for formats
+  supporting 1bit images. Scaling of pixel values to 8bits is optional
+  (indexed formats don't need this).}
+procedure Convert1To8(DataIn, DataOut: PByte; Width, Height,
+  WidthBytes: LongInt; ScaleTo8Bits: Boolean);
+{ Converts 2bit image data to 8bit. Used mostly by file loaders for formats
+  supporting 2bit images. Scaling of pixel values to 8bits is optional
+  (indexed formats don't need this).}
+procedure Convert2To8(DataIn, DataOut: PByte; Width, Height,
+  WidthBytes: LongInt; ScaleTo8Bits: Boolean);
+{ Converts 4bit image data to 8bit. Used mostly by file loaders for formats
+  supporting 4bit images. Scaling of pixel values to 8bits is optional
+  (indexed formats don't need this).}
+procedure Convert4To8(DataIn, DataOut: PByte; Width, Height,
+  WidthBytes: LongInt; ScaleTo8Bits: Boolean);
+
+{ Helper function for image file loaders. Some 15 bit images (targas, bitmaps)
+  may contain 1 bit alpha but there is no indication of it. This function checks
+  all 16 bit(should be X1R5G5B5 or A1R5G5B5 format) pixels and some of them have
+  alpha bit set it returns True, otherwise False.}
+function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean;
+{ Helper function for image file loaders. This function checks is similar
+  to Has16BitImageAlpha but works with A8R8G8B8/X8R8G8B8 format.}
+function Has32BitImageAlpha(NumPixels: LongInt; Data: PLongWord): Boolean;
+{ Checks if there is any relevant alpha data (any entry has alpha <> 255)
+  in the given palette.}
+function PaletteHasAlpha(Palette: PPalette32; PaletteEntries: Integer): Boolean;
+
+{ Provides indexed access to each line of pixels. Does not work with special
+  format images.}
+function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo;
+  LineWidth, Index: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns True if Format is valid image data format identifier.}
+function IsImageFormatValid(Format: TImageFormat): Boolean;
+
+{ Converts 16bit half floating point value to 32bit Single.}
+function HalfToFloat(Half: THalfFloat): Single;
+{ Converts 32bit Single to 16bit half floating point.}
+function FloatToHalf(Float: Single): THalfFloat;
+
+{ Converts half float color value to single-precision floating point color.}
+function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Converts single-precision floating point color to half float color.}
+function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+
+{ Makes image PalEntries x 1 big where each pixel has color of one pal entry.}
+procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData);
+
+type
+  TPointRec = record
+    Pos: LongInt;
+    Weight: Single;
+  end;
+  TCluster = array of TPointRec;
+  TMappingTable = array of TCluster;
+
+{ Helper function for resampling.}
+function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt;
+  Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable;
+{ Helper function for resampling.}
+procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt);
+
+
+{ Pixel readers/writers for different image formats }
+
+{ Returns pixel of image in any ARGB format. Channel values are scaled to 16 bits.}
+procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Pix: TColor64Rec);
+{ Sets pixel of image in any ARGB format. Channel values must be scaled to 16 bits.}
+procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  const Pix: TColor64Rec);
+
+{ Returns pixel of image in any grayscale format. Gray value is scaled to 64 bits
+  and alpha to 16 bits.}
+procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Gray: TColor64Rec; var Alpha: Word);
+{ Sets pixel of image in any grayscale format. Gray value must be scaled to 64 bits
+  and alpha to 16 bits.}
+procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  const Gray: TColor64Rec; Alpha: Word);
+
+{ Returns pixel of image in any floating point format. Channel values are
+  in range <0.0, 1.0>.}
+procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Pix: TColorFPRec);
+{ Sets pixel of image in any floating point format. Channel values must be
+  in range <0.0, 1.0>.}
+procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  const Pix: TColorFPRec);
+
+{ Returns pixel of image in any indexed format. Returned value is index to
+  the palette.}
+procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Index: LongWord);
+{ Sets pixel of image in any indexed format. Index is index to the palette.}
+procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  Index: LongWord);
+
+
+{ Pixel readers/writers for 32bit and FP colors}
+
+{ Function for getting pixel colors. Native pixel is read from Image and
+  then translated to 32 bit ARGB.}
+function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo;
+  Palette: PPalette32): TColor32Rec;
+{ Procedure for setting pixel colors. Input 32 bit ARGB color is translated to
+    native format and then written to Image.}
+procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo;
+  Palette: PPalette32; const Color: TColor32Rec);
+{ Function for getting pixel colors. Native pixel is read from Image and
+  then translated to FP ARGB.}
+function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo;
+  Palette: PPalette32): TColorFPRec;
+{ Procedure for setting pixel colors. Input FP ARGB color is translated to
+    native format and then written to Image.}
+procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo;
+  Palette: PPalette32; const Color: TColorFPRec);
+
+
+{ Image format conversion functions }
+
+{ Converts any ARGB format to any ARGB format.}
+procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any ARGB format to any grayscale format.}
+procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any ARGB format to any floating point format.}
+procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any ARGB format to any indexed format.}
+procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; DstPal: PPalette32);
+
+{ Converts any grayscale format to any grayscale format.}
+procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any grayscale format to any ARGB format.}
+procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any grayscale format to any floating point format.}
+procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any grayscale format to any indexed format.}
+procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; DstPal: PPalette32);
+
+{ Converts any floating point format to any floating point format.}
+procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any floating point format to any ARGB format.}
+procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any floating point format to any grayscale format.}
+procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+{ Converts any floating point format to any indexed format.}
+procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; DstPal: PPalette32);
+
+{ Converts any indexed format to any indexed format.}
+procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32);
+{ Converts any indexed format to any ARGB format.}
+procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal: PPalette32);
+{ Converts any indexed format to any grayscale format.}
+procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal: PPalette32);
+{ Converts any indexed format to any floating point  format.}
+procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal: PPalette32);
+
+
+{ Color constructor functions }
+
+{ Constructs TColor24Rec color.}
+function Color24(R, G, B: Byte): TColor24Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Constructs TColor32Rec color.}
+function Color32(A, R, G, B: Byte): TColor32Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Constructs TColor48Rec color.}
+function Color48(R, G, B: Word): TColor48Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Constructs TColor64Rec color.}
+function Color64(A, R, G, B: Word): TColor64Rec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Constructs TColorFPRec color.}
+function ColorFP(A, R, G, B: Single): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Constructs TColorHFRec color.}
+function ColorHF(A, R, G, B: THalfFloat): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF}
+
+
+{ Special formats conversion functions }
+
+{ Converts image to/from/between special image formats (dxtc, ...).}
+procedure ConvertSpecial(var Image: TImageData; SrcInfo,
+  DstInfo: PImageFormatInfo);
+
+
+{ Inits all image format information. Called internally on startup.}
+procedure InitImageFormats(var Infos: TImageFormatInfoArray);
+
+const
+  // Grayscale conversion channel weights
+  GrayConv: TColorFPRec = (B: 0.114; G: 0.587; R: 0.299; A: 0.0);
+
+  // Contants for converting integer colors to floating point
+  OneDiv8Bit: Single = 1.0 / 255.0;
+  OneDiv16Bit: Single = 1.0 / 65535.0;
+
+implementation
+
+{ TImageFormatInfo member functions }
+
+{ Returns size in bytes of image in given standard format where
+  Size = Width * Height * Bpp.}
+function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward;
+{ Checks if Width and Height are valid for given standard format.}
+procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt); forward;
+{ Returns size in bytes of image in given DXT format.}
+function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward;
+{ Checks if Width and Height are valid for given DXT format. If they are
+  not valid, they are changed to pass the check.}
+procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt); forward;
+{ Returns size in bytes of image in BTC format.}
+function GetBTCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward;
+{ Returns size in bytes of image in binary format (1bit image).}
+function GetBinaryPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward;
+
+function GetBCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward;
+procedure CheckBCDimensions(Format: TImageFormat; var Width, Height: LongInt); forward;
+
+
+{ Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo }
+
+function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward;
+procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward;
+function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
+procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
+
+function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward;
+procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward;
+function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
+procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
+
+function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward;
+procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward;
+
+var
+  PFR3G3B2: TPixelFormatInfo;
+  PFX5R1G1B1: TPixelFormatInfo;
+  PFR5G6B5: TPixelFormatInfo;
+  PFA1R5G5B5: TPixelFormatInfo;
+  PFA4R4G4B4: TPixelFormatInfo;
+  PFX1R5G5B5: TPixelFormatInfo;
+  PFX4R4G4B4: TPixelFormatInfo;
+  FInfos: PImageFormatInfoArray;
+
+var
+  // Free Pascal generates hundreds of warnings here
+{$WARNINGS OFF}
+
+  // indexed formats
+  Index8Info: TImageFormatInfo = (
+    Format: ifIndex8;
+    Name: 'Index8';
+    BytesPerPixel: 1;
+    ChannelCount: 1;
+    PaletteEntries: 256;
+    HasAlphaChannel: True;
+    IsIndexed: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  // grayscale formats
+  Gray8Info: TImageFormatInfo = (
+    Format: ifGray8;
+    Name: 'Gray8';
+    BytesPerPixel: 1;
+    ChannelCount: 1;
+    HasGrayChannel: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Channel8Bit;
+    GetPixelFP: GetPixelFPChannel8Bit;
+    SetPixel32: SetPixel32Channel8Bit;
+    SetPixelFP: SetPixelFPChannel8Bit);
+
+  A8Gray8Info: TImageFormatInfo = (
+    Format: ifA8Gray8;
+    Name: 'A8Gray8';
+    BytesPerPixel: 2;
+    ChannelCount: 2;
+    HasGrayChannel: True;
+    HasAlphaChannel: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Channel8Bit;
+    GetPixelFP: GetPixelFPChannel8Bit;
+    SetPixel32: SetPixel32Channel8Bit;
+    SetPixelFP: SetPixelFPChannel8Bit);
+
+  Gray16Info: TImageFormatInfo = (
+    Format: ifGray16;
+    Name: 'Gray16';
+    BytesPerPixel: 2;
+    ChannelCount: 1;
+    HasGrayChannel: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  Gray32Info: TImageFormatInfo = (
+    Format: ifGray32;
+    Name: 'Gray32';
+    BytesPerPixel: 4;
+    ChannelCount: 1;
+    HasGrayChannel: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  Gray64Info: TImageFormatInfo = (
+    Format: ifGray64;
+    Name: 'Gray64';
+    BytesPerPixel: 8;
+    ChannelCount: 1;
+    HasGrayChannel: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  A16Gray16Info: TImageFormatInfo = (
+    Format: ifA16Gray16;
+    Name: 'A16Gray16';
+    BytesPerPixel: 4;
+    ChannelCount: 2;
+    HasGrayChannel: True;
+    HasAlphaChannel: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  // ARGB formats
+  X5R1G1B1Info: TImageFormatInfo = (
+    Format: ifX5R1G1B1;
+    Name: 'X5R1G1B1';
+    BytesPerPixel: 1;
+    ChannelCount: 3;
+    UsePixelFormat: True;
+    PixelFormat: @PFX5R1G1B1;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  R3G3B2Info: TImageFormatInfo = (
+    Format: ifR3G3B2;
+    Name: 'R3G3B2';
+    BytesPerPixel: 1;
+    ChannelCount: 3;
+    UsePixelFormat: True;
+    PixelFormat: @PFR3G3B2;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  R5G6B5Info: TImageFormatInfo = (
+    Format: ifR5G6B5;
+    Name: 'R5G6B5';
+    BytesPerPixel: 2;
+    ChannelCount: 3;
+    UsePixelFormat: True;
+    PixelFormat: @PFR5G6B5;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  A1R5G5B5Info: TImageFormatInfo = (
+    Format: ifA1R5G5B5;
+    Name: 'A1R5G5B5';
+    BytesPerPixel: 2;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    UsePixelFormat: True;
+    PixelFormat: @PFA1R5G5B5;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  A4R4G4B4Info: TImageFormatInfo = (
+    Format: ifA4R4G4B4;
+    Name: 'A4R4G4B4';
+    BytesPerPixel: 2;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    UsePixelFormat: True;
+    PixelFormat: @PFA4R4G4B4;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  X1R5G5B5Info: TImageFormatInfo = (
+    Format: ifX1R5G5B5;
+    Name: 'X1R5G5B5';
+    BytesPerPixel: 2;
+    ChannelCount: 3;
+    UsePixelFormat: True;
+    PixelFormat: @PFX1R5G5B5;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  X4R4G4B4Info: TImageFormatInfo = (
+    Format: ifX4R4G4B4;
+    Name: 'X4R4G4B4';
+    BytesPerPixel: 2;
+    ChannelCount: 3;
+    UsePixelFormat: True;
+    PixelFormat: @PFX4R4G4B4;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  R8G8B8Info: TImageFormatInfo = (
+    Format: ifR8G8B8;
+    Name: 'R8G8B8';
+    BytesPerPixel: 3;
+    ChannelCount: 3;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Channel8Bit;
+    GetPixelFP: GetPixelFPChannel8Bit;
+    SetPixel32: SetPixel32Channel8Bit;
+    SetPixelFP: SetPixelFPChannel8Bit);
+
+  A8R8G8B8Info: TImageFormatInfo = (
+    Format: ifA8R8G8B8;
+    Name: 'A8R8G8B8';
+    BytesPerPixel: 4;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32ifA8R8G8B8;
+    GetPixelFP: GetPixelFPifA8R8G8B8;
+    SetPixel32: SetPixel32ifA8R8G8B8;
+    SetPixelFP: SetPixelFPifA8R8G8B8);
+
+  X8R8G8B8Info: TImageFormatInfo = (
+    Format: ifX8R8G8B8;
+    Name: 'X8R8G8B8';
+    BytesPerPixel: 4;
+    ChannelCount: 3;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Channel8Bit;
+    GetPixelFP: GetPixelFPChannel8Bit;
+    SetPixel32: SetPixel32Channel8Bit;
+    SetPixelFP: SetPixelFPChannel8Bit);
+
+  R16G16B16Info: TImageFormatInfo = (
+    Format: ifR16G16B16;
+    Name: 'R16G16B16';
+    BytesPerPixel: 6;
+    ChannelCount: 3;
+    RBSwapFormat: ifB16G16R16;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  A16R16G16B16Info: TImageFormatInfo = (
+    Format: ifA16R16G16B16;
+    Name: 'A16R16G16B16';
+    BytesPerPixel: 8;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    RBSwapFormat: ifA16B16G16R16;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  B16G16R16Info: TImageFormatInfo = (
+    Format: ifB16G16R16;
+    Name: 'B16G16R16';
+    BytesPerPixel: 6;
+    ChannelCount: 3;
+    IsRBSwapped: True;
+    RBSwapFormat: ifR16G16B16;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  A16B16G16R16Info: TImageFormatInfo = (
+    Format: ifA16B16G16R16;
+    Name: 'A16B16G16R16';
+    BytesPerPixel: 8;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsRBSwapped: True;
+    RBSwapFormat: ifA16R16G16B16;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  // floating point formats
+  R32FInfo: TImageFormatInfo = (
+    Format: ifR32F;
+    Name: 'R32F';
+    BytesPerPixel: 4;
+    ChannelCount: 1;
+    IsFloatingPoint: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPFloat32;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPFloat32);
+
+ A32R32G32B32FInfo: TImageFormatInfo = (
+    Format: ifA32R32G32B32F;
+    Name: 'A32R32G32B32F';
+    BytesPerPixel: 16;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsFloatingPoint: True;
+    RBSwapFormat: ifA32B32G32R32F;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPFloat32;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPFloat32);
+
+  A32B32G32R32FInfo: TImageFormatInfo = (
+    Format: ifA32B32G32R32F;
+    Name: 'A32B32G32R32F';
+    BytesPerPixel: 16;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsFloatingPoint: True;
+    IsRBSwapped: True;
+    RBSwapFormat: ifA32R32G32B32F;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPFloat32;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPFloat32);
+
+  R16FInfo: TImageFormatInfo = (
+    Format: ifR16F;
+    Name: 'R16F';
+    BytesPerPixel: 2;
+    ChannelCount: 1;
+    IsFloatingPoint: True;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+ A16R16G16B16FInfo: TImageFormatInfo = (
+    Format: ifA16R16G16B16F;
+    Name: 'A16R16G16B16F';
+    BytesPerPixel: 8;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsFloatingPoint: True;
+    RBSwapFormat: ifA16B16G16R16F;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  A16B16G16R16FInfo: TImageFormatInfo = (
+    Format: ifA16B16G16R16F;
+    Name: 'A16B16G16R16F';
+    BytesPerPixel: 8;
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsFloatingPoint: True;
+    IsRBSwapped: True;
+    RBSwapFormat: ifA16R16G16B16F;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPGeneric;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPGeneric);
+
+  R32G32B32FInfo: TImageFormatInfo = (
+    Format: ifR32G32B32F;
+    Name: 'R32G32B32F';
+    BytesPerPixel: 12;
+    ChannelCount: 3;
+    IsFloatingPoint: True;
+    RBSwapFormat: ifB32G32R32F;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPFloat32;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPFloat32);
+
+  B32G32R32FInfo: TImageFormatInfo = (
+    Format: ifB32G32R32F;
+    Name: 'B32G32R32F';
+    BytesPerPixel: 12;
+    ChannelCount: 3;
+    IsFloatingPoint: True;
+    IsRBSwapped: True;
+    RBSwapFormat: ifR32G32B32F;
+    GetPixelsSize: GetStdPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    GetPixel32: GetPixel32Generic;
+    GetPixelFP: GetPixelFPFloat32;
+    SetPixel32: SetPixel32Generic;
+    SetPixelFP: SetPixelFPFloat32);
+
+  // special formats
+  DXT1Info: TImageFormatInfo = (
+    Format: ifDXT1;
+    Name: 'DXT1';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    GetPixelsSize: GetDXTPixelsSize;
+    CheckDimensions: CheckDXTDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);
+
+  DXT3Info: TImageFormatInfo = (
+    Format: ifDXT3;
+    Name: 'DXT3';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    GetPixelsSize: GetDXTPixelsSize;
+    CheckDimensions: CheckDXTDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);
+
+  DXT5Info: TImageFormatInfo = (
+    Format: ifDXT5;
+    Name: 'DXT5';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    GetPixelsSize: GetDXTPixelsSize;
+    CheckDimensions: CheckDXTDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);
+
+  BTCInfo: TImageFormatInfo = (
+    Format: ifBTC;
+    Name: 'BTC';
+    ChannelCount: 1;
+    HasAlphaChannel: False;
+    IsSpecial: True;
+    GetPixelsSize: GetBTCPixelsSize;
+    CheckDimensions: CheckDXTDimensions;
+    SpecialNearestFormat: ifGray8);
+
+  ATI1NInfo: TImageFormatInfo = (
+    Format: ifATI1N;
+    Name: 'ATI1N';
+    ChannelCount: 1;
+    HasAlphaChannel: False;
+    IsSpecial: True;
+    GetPixelsSize: GetDXTPixelsSize;
+    CheckDimensions: CheckDXTDimensions;
+    SpecialNearestFormat: ifGray8);
+
+  ATI2NInfo: TImageFormatInfo = (
+    Format: ifATI2N;
+    Name: 'ATI2N';
+    ChannelCount: 2;
+    HasAlphaChannel: False;
+    IsSpecial: True;
+    GetPixelsSize: GetDXTPixelsSize;
+    CheckDimensions: CheckDXTDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);
+
+  BinaryInfo: TImageFormatInfo = (
+    Format: ifBinary;
+    Name: 'Binary';
+    ChannelCount: 1;
+    HasAlphaChannel: False;
+    IsSpecial: True;
+    GetPixelsSize: GetBinaryPixelsSize;
+    CheckDimensions: CheckStdDimensions;
+    SpecialNearestFormat: ifGray8);
+
+  {ETC1Info: TImageFormatInfo = (
+    Format: ifETC1;
+    Name: 'ETC1';
+    ChannelCount: 3;
+    HasAlphaChannel: False;
+    IsSpecial: True;
+    IsPasstrough: True;
+    GetPixelsSize: GetBCPixelsSize;
+    CheckDimensions: CheckBCDimensions;
+    SpecialNearestFormat: ifR8G8B8);
+
+  ETC2RGBInfo: TImageFormatInfo = (
+    Format: ifETC2RGB;
+    Name: 'ETC2RGB';
+    ChannelCount: 3;
+    HasAlphaChannel: False;
+    IsSpecial: True;
+    IsPasstrough: True;
+    GetPixelsSize: GetBCPixelsSize;
+    CheckDimensions: CheckBCDimensions;
+    SpecialNearestFormat: ifR8G8B8);
+
+  ETC2RGBAInfo: TImageFormatInfo = (
+    Format: ifETC2RGBA;
+    Name: 'ETC2RGBA';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    IsPasstrough: True;
+    GetPixelsSize: GetBCPixelsSize;
+    CheckDimensions: CheckBCDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);
+
+  ETC2PAInfo: TImageFormatInfo = (
+    Format: ifETC2PA;
+    Name: 'ETC2PA';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    IsPasstrough: True;
+    GetPixelsSize: GetBCPixelsSize;
+    CheckDimensions: CheckBCDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);
+
+  DXBC6Info: TImageFormatInfo = (
+    Format: ifDXBC6;
+    Name: 'DXBC6';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    IsPasstrough: True;
+    GetPixelsSize: GetBCPixelsSize;
+    CheckDimensions: CheckBCDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);
+
+  DXBC7Info: TImageFormatInfo = (
+    Format: ifDXBC6;
+    Name: 'DXBC7';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    IsPasstrough: True;
+    GetPixelsSize: GetBCPixelsSize;
+    CheckDimensions: CheckBCDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);   }
+
+  {PVRTCInfo: TImageFormatInfo = (
+    Format: ifPVRTC;
+    Name: 'PVRTC';
+    ChannelCount: 4;
+    HasAlphaChannel: True;
+    IsSpecial: True;
+    IsPasstrough: True;
+    GetPixelsSize: GetBCPixelsSize;
+    CheckDimensions: CheckBCDimensions;
+    SpecialNearestFormat: ifA8R8G8B8);}
+
+{$WARNINGS ON}
+
+function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; forward;
+
+procedure InitImageFormats(var Infos: TImageFormatInfoArray);
+begin
+  FInfos := @Infos;
+
+  Infos[ifDefault] := @A8R8G8B8Info;
+  // indexed formats
+  Infos[ifIndex8] := @Index8Info;
+  // grayscale formats
+  Infos[ifGray8] := @Gray8Info;
+  Infos[ifA8Gray8] := @A8Gray8Info;
+  Infos[ifGray16] := @Gray16Info;
+  Infos[ifGray32] := @Gray32Info;
+  Infos[ifGray64] := @Gray64Info;
+  Infos[ifA16Gray16] := @A16Gray16Info;
+  // ARGB formats
+  Infos[ifX5R1G1B1] := @X5R1G1B1Info;
+  Infos[ifR3G3B2] := @R3G3B2Info;
+  Infos[ifR5G6B5] := @R5G6B5Info;
+  Infos[ifA1R5G5B5] := @A1R5G5B5Info;
+  Infos[ifA4R4G4B4] := @A4R4G4B4Info;
+  Infos[ifX1R5G5B5] := @X1R5G5B5Info;
+  Infos[ifX4R4G4B4] := @X4R4G4B4Info;
+  Infos[ifR8G8B8] := @R8G8B8Info;
+  Infos[ifA8R8G8B8] := @A8R8G8B8Info;
+  Infos[ifX8R8G8B8] := @X8R8G8B8Info;
+  Infos[ifR16G16B16] := @R16G16B16Info;
+  Infos[ifA16R16G16B16] := @A16R16G16B16Info;
+  Infos[ifB16G16R16] := @B16G16R16Info;
+  Infos[ifA16B16G16R16] := @A16B16G16R16Info;
+  // floating point formats
+  Infos[ifR32F] := @R32FInfo;
+  Infos[ifA32R32G32B32F] := @A32R32G32B32FInfo;
+  Infos[ifA32B32G32R32F] := @A32B32G32R32FInfo;
+  Infos[ifR16F] := @R16FInfo;
+  Infos[ifA16R16G16B16F] := @A16R16G16B16FInfo;
+  Infos[ifA16B16G16R16F] := @A16B16G16R16FInfo;
+  Infos[ifR32G32B32F] := @R32G32B32FInfo;
+  Infos[ifB32G32R32F] := @B32G32R32FInfo;
+  // special formats
+  Infos[ifDXT1] := @DXT1Info;
+  Infos[ifDXT3] := @DXT3Info;
+  Infos[ifDXT5] := @DXT5Info;
+  Infos[ifBTC] :=  @BTCInfo;
+  Infos[ifATI1N] := @ATI1NInfo;
+  Infos[ifATI2N] := @ATI2NInfo;
+  Infos[ifBinary] := @BinaryInfo;
+
+  PFR3G3B2 := PixelFormat(0, 3, 3, 2);
+  PFX5R1G1B1 := PixelFormat(0, 1, 1, 1);
+  PFR5G6B5 := PixelFormat(0, 5, 6, 5);
+  PFA1R5G5B5 := PixelFormat(1, 5, 5, 5);
+  PFA4R4G4B4 := PixelFormat(4, 4, 4, 4);
+  PFX1R5G5B5 := PixelFormat(0, 5, 5, 5);
+  PFX4R4G4B4 := PixelFormat(0, 4, 4, 4);
+end;
+
+
+{ Internal unit helper functions }
+
+function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo;
+begin
+  Result.ABitMask := ((1 shl ABitCount) - 1) shl (RBitCount + GBitCount +
+    BBitCount);
+  Result.RBitMask := ((1 shl RBitCount) - 1) shl (GBitCount + BBitCount);
+  Result.GBitMask := ((1 shl GBitCount) - 1) shl (BBitCount);
+  Result.BBitMask := (1 shl BBitCount) - 1;
+  Result.ABitCount := ABitCount;
+  Result.RBitCount := RBitCount;
+  Result.GBitCount := GBitCount;
+  Result.BBitCount := BBitCount;
+  Result.AShift := RBitCount + GBitCount + BBitCount;
+  Result.RShift := GBitCount + BBitCount;
+  Result.GShift := BBitCount;
+  Result.BShift := 0;
+  Result.ARecDiv := Max(1, Pow2Int(Result.ABitCount) - 1);
+  Result.RRecDiv := Max(1, Pow2Int(Result.RBitCount) - 1);
+  Result.GRecDiv := Max(1, Pow2Int(Result.GBitCount) - 1);
+  Result.BRecDiv := Max(1, Pow2Int(Result.BBitCount) - 1);
+end;
+
+function PixelFormatMask(ABitMask, RBitMask, GBitMask, BBitMask: LongWord): TPixelFormatInfo;
+
+  function GetBitCount(B: LongWord): LongWord;
+  var
+    I: LongWord;
+  begin
+    I := 0;
+    while (I < 31) and (((1 shl I) and B) = 0) do
+      Inc(I);
+    Result := 0;
+    while ((1 shl I) and B) <> 0 do
+    begin
+      Inc(I);
+      Inc(Result);
+    end;
+  end;
+
+begin
+  Result := PixelFormat(GetBitCount(ABitMask), GetBitCount(RBitMask),
+    GetBitCount(GBitMask), GetBitCount(BBitMask));
+end;
+
+function PFSetARGB(const PF: TPixelFormatInfo; A, R, G, B: Byte): TColor32;
+{$IFDEF USE_INLINE}inline;{$ENDIF}
+begin
+  with PF do
+    Result :=
+      (A shl ABitCount shr 8 shl AShift) or
+      (R shl RBitCount shr 8 shl RShift) or
+      (G shl GBitCount shr 8 shl GShift) or
+      (B shl BBitCount shr 8 shl BShift);
+end;
+
+procedure PFGetARGB(const PF: TPixelFormatInfo; Color: LongWord;
+  var A, R, G, B: Byte); {$IFDEF USE_INLINE}inline;{$ENDIF}
+begin
+  with PF do
+  begin
+    A := (Color and ABitMask shr AShift) * 255 div ARecDiv;
+    R := (Color and RBitMask shr RShift) * 255 div RRecDiv;
+    G := (Color and GBitMask shr GShift) * 255 div GRecDiv;
+    B := (Color and BBitMask shl BShift) * 255 div BRecDiv;
+  end;
+end;
+
+function PFSetColor(const PF: TPixelFormatInfo; ARGB: TColor32): LongWord;
+{$IFDEF USE_INLINE}inline;{$ENDIF}
+begin
+  with PF do
+    Result :=
+      (Byte(ARGB shr 24) shl ABitCount shr 8 shl AShift) or
+      (Byte(ARGB shr 16) shl RBitCount shr 8 shl RShift) or
+      (Byte(ARGB shr 8) shl GBitCount shr 8 shl GShift) or
+      (Byte(ARGB) shl BBitCount shr 8 shl BShift);
+end;
+
+function PFGetColor(const PF: TPixelFormatInfo; Color: LongWord): TColor32;
+{$IFDEF USE_INLINE}inline;{$ENDIF}
+begin
+  //with PF, TColor32Rec(Result) do
+  begin
+    TColor32Rec(Result).A := (Color and PF.ABitMask shr PF.AShift) * 255 div PF.ARecDiv;
+    TColor32Rec(Result).R := (Color and PF.RBitMask shr PF.RShift) * 255 div PF.RRecDiv;
+    TColor32Rec(Result).G := (Color and PF.GBitMask shr PF.GShift) * 255 div PF.GRecDiv;
+    TColor32Rec(Result).B := (Color and PF.BBitMask shl PF.BShift) * 255 div PF.BRecDiv;
+  end;
+end;
+
+
+{ Color constructor functions }
+
+
+function Color24(R, G, B: Byte): TColor24Rec;
+begin
+  Result.R := R;
+  Result.G := G;
+  Result.B := B;
+end;
+
+function Color32(A, R, G, B: Byte): TColor32Rec;
+begin
+  Result.A := A;
+  Result.R := R;
+  Result.G := G;
+  Result.B := B;
+end;
+
+function Color48(R, G, B: Word): TColor48Rec;
+begin
+  Result.R := R;
+  Result.G := G;
+  Result.B := B;
+end;
+
+function Color64(A, R, G, B: Word): TColor64Rec;
+begin
+  Result.A := A;
+  Result.R := R;
+  Result.G := G;
+  Result.B := B;
+end;
+
+function ColorFP(A, R, G, B: Single): TColorFPRec;
+begin
+  Result.A := A;
+  Result.R := R;
+  Result.G := G;
+  Result.B := B;
+end;
+
+function ColorHF(A, R, G, B: THalfFloat): TColorHFRec;
+begin
+  Result.A := A;
+  Result.R := R;
+  Result.G := G;
+  Result.B := B;
+end;
+
+
+{ Additional image manipulation functions (usually used internally by Imaging unit) }
+
+const
+  MaxPossibleColors = 4096;
+  HashSize = 32768;
+  AlphaWeight = 1024;
+  RedWeight = 612;
+  GreenWeight = 1202;
+  BlueWeight = 234;
+
+type
+  PColorBin = ^TColorBin;
+  TColorBin = record
+    Color: TColor32Rec;
+    Number: LongInt;
+    Next: PColorBin;
+  end;
+
+  THashTable = array[0..HashSize - 1] of PColorBin;
+
+  TColorBox = record
+    AMin, AMax,
+    RMin, RMax,
+    GMin, GMax,
+    BMin, BMax: LongInt;
+    Total: LongInt;
+    Represented: TColor32Rec;
+    List: PColorBin;
+  end;
+
+var
+  Table: THashTable;
+  Box: array[0..MaxPossibleColors - 1] of TColorBox;
+  Boxes: LongInt;
+  BoxesCreated: Boolean = False;
+
+procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte;
+  DstPal: PPalette32; Actions: TReduceColorsActions);
+
+  procedure CreateHistogram (Src: PByte; SrcInfo: PImageFormatInfo;
+    ChannelMask: Byte);
+  var
+    A, R, G, B: Byte;
+    I, Addr: LongInt;
+    PC: PColorBin;
+    Col: TColor32Rec;
+  begin
+    for I := 0 to NumPixels - 1 do
+    begin
+      Col := GetPixel32Generic(Src, SrcInfo, nil);
+      A := Col.A and ChannelMask;
+      R := Col.R and ChannelMask;
+      G := Col.G and ChannelMask;
+      B := Col.B and ChannelMask;
+
+      Addr := (A + 11 * B + 59 * R + 119 * G) mod HashSize;
+      PC := Table[Addr];
+
+      while (PC <> nil) and ((PC.Color.R <> R) or (PC.Color.G <> G) or
+        (PC.Color.B <> B) or (PC.Color.A <> A)) do
+        PC := PC.Next;
+
+      if PC = nil then
+      begin
+        New(PC);
+        PC.Color.R := R;
+        PC.Color.G := G;
+        PC.Color.B := B;
+        PC.Color.A := A;
+        PC.Number := 1;
+        PC.Next := Table[Addr];
+        Table[Addr] := PC;
+      end
+      else
+        Inc(PC^.Number);
+      Inc(Src, SrcInfo.BytesPerPixel);
+    end;
+  end;
+
+  procedure InitBox (var Box : TColorBox);
+  begin
+    Box.AMin := 256;
+    Box.RMin := 256;
+    Box.GMin := 256;
+    Box.BMin := 256;
+    Box.AMax := -1;
+    Box.RMax := -1;
+    Box.GMax := -1;
+    Box.BMax := -1;
+    Box.Total := 0;
+    Box.List := nil;
+  end;
+
+  procedure ChangeBox (var Box: TColorBox; const C: TColorBin);
+  begin
+    with C.Color do
+    begin
+      if A < Box.AMin then Box.AMin := A;
+      if A > Box.AMax then Box.AMax := A;
+      if B < Box.BMin then Box.BMin := B;
+      if B > Box.BMax then Box.BMax := B;
+      if G < Box.GMin then Box.GMin := G;
+      if G > Box.GMax then Box.GMax := G;
+      if R < Box.RMin then Box.RMin := R;
+      if R > Box.RMax then Box.RMax := R;
+    end;
+    Inc(Box.Total, C.Number);
+  end;
+
+  procedure MakeColormap;
+  var
+    I, J: LongInt;
+    CP, Pom: PColorBin;
+    Cut, LargestIdx, Largest, Size, S: LongInt;
+    CutA, CutR, CutG, CutB: Boolean;
+    SumA, SumR, SumG, SumB: LongInt;
+    Temp: TColorBox;
+  begin
+    I := 0;
+    Boxes := 1;
+    LargestIdx := 0;
+    while (I < HashSize) and (Table[I] = nil) do
+      Inc(i);
+    if I < HashSize then
+    begin
+      // put all colors into Box[0]
+      InitBox(Box[0]);
+      repeat
+        CP := Table[I];
+        while CP.Next <> nil do
+        begin
+          ChangeBox(Box[0], CP^);
+          CP := CP.Next;
+        end;
+        ChangeBox(Box[0], CP^);
+        CP.Next := Box[0].List;
+        Box[0].List := Table[I];
+        Table[I] := nil;
+        repeat
+          Inc(I)
+        until (I = HashSize) or (Table[I] <> nil);
+      until I = HashSize;
+      // now all colors are in Box[0]
+      repeat
+        // cut one color box
+        Largest := 0;
+        for I := 0 to Boxes - 1 do
+          with Box[I] do
+          begin
+            Size := (AMax - AMin) * AlphaWeight;
+            S := (RMax - RMin) * RedWeight;
+            if S > Size then
+              Size := S;
+            S := (GMax - GMin) * GreenWeight;
+            if S > Size then
+              Size := S;
+            S := (BMax - BMin) * BlueWeight;
+            if S > Size then
+              Size := S;
+            if Size > Largest then
+            begin
+              Largest := Size;
+              LargestIdx := I;
+            end;
+          end;
+        if Largest > 0 then
+        begin
+          // cutting Box[LargestIdx] into Box[LargestIdx] and Box[Boxes]
+          CutR := False;
+          CutG := False;
+          CutB := False;
+          CutA := False;
+          with Box[LargestIdx] do
+          begin
+            if (AMax - AMin) * AlphaWeight = Largest then
+            begin
+              Cut := (AMax + AMin) shr 1;
+              CutA := True;
+            end
+            else
+              if (RMax - RMin) * RedWeight = Largest then
+              begin
+                Cut := (RMax + RMin) shr 1;
+                CutR := True;
+              end
+              else
+                if (GMax - GMin) * GreenWeight = Largest then
+                begin
+                  Cut := (GMax + GMin) shr 1;
+                  CutG := True;
+                end
+                else
+                begin
+                  Cut := (BMax + BMin) shr 1;
+                  CutB := True;
+                end;
+            CP := List;
+          end;
+          InitBox(Box[LargestIdx]);
+          InitBox(Box[Boxes]);
+          repeat
+            // distribute one color
+            Pom := CP.Next;
+            with CP.Color do
+            begin
+              if (CutA and (A <= Cut)) or (CutR and (R <= Cut)) or
+                (CutG and (G <= Cut)) or (CutB and (B <= Cut)) then
+                I := LargestIdx
+              else
+                I := Boxes;
+            end;
+            CP.Next := Box[i].List;
+            Box[i].List := CP;
+            ChangeBox(Box[i], CP^);
+            CP := Pom;
+          until CP = nil;
+          Inc(Boxes);
+        end;
+      until (Boxes = MaxColors) or (Largest = 0);
+      // compute box representation
+      for I := 0 to Boxes - 1 do
+      begin
+        SumR := 0;
+        SumG := 0;
+        SumB := 0;
+        SumA := 0;
+        repeat
+          CP := Box[I].List;
+          Inc(SumR, CP.Color.R * CP.Number);
+          Inc(SumG, CP.Color.G * CP.Number);
+          Inc(SumB, CP.Color.B * CP.Number);
+          Inc(SumA, CP.Color.A * CP.Number);
+          Box[I].List := CP.Next;
+          Dispose(CP);
+        until Box[I].List = nil;
+        with Box[I] do
+        begin
+          Represented.A := SumA div Total;
+          Represented.R := SumR div Total;
+          Represented.G := SumG div Total;
+          Represented.B := SumB div Total;
+          AMin := AMin and ChannelMask;
+          RMin := RMin and ChannelMask;
+          GMin := GMin and ChannelMask;
+          BMin := BMin and ChannelMask;
+          AMax := (AMax and ChannelMask) + (not ChannelMask);
+          RMax := (RMax and ChannelMask) + (not ChannelMask);
+          GMax := (GMax and ChannelMask) + (not ChannelMask);
+          BMax := (BMax and ChannelMask) + (not ChannelMask);
+        end;
+      end;
+      // sort color boxes
+      for I := 0 to Boxes - 2 do
+      begin
+        Largest := 0;
+        for J := I to Boxes - 1 do
+          if Box[J].Total > Largest then
+          begin
+            Largest := Box[J].Total;
+            LargestIdx := J;
+          end;
+        if LargestIdx <> I then
+        begin
+          Temp := Box[I];
+          Box[I] := Box[LargestIdx];
+          Box[LargestIdx] := Temp;
+        end;
+      end;
+    end;
+  end;
+
+  procedure FillOutputPalette;
+  var
+    I: LongInt;
+  begin
+    FillChar(DstPal^, SizeOf(TColor32Rec) * MaxColors, $FF);
+    for I := 0 to MaxColors - 1 do
+    begin
+      if I < Boxes then
+      with Box[I].Represented do
+      begin
+        DstPal[I].A := A;
+        DstPal[I].R := R;
+        DstPal[I].G := G;
+        DstPal[I].B := B;
+      end
+      else
+        DstPal[I].Color := $FF000000;
+    end;
+  end;
+
+  function MapColor(const Col: TColor32Rec) : LongInt;
+  var
+    I: LongInt;
+  begin
+    I := 0;
+    with Col do
+      while (I < Boxes) and ((Box[I].AMin > A) or (Box[I].AMax < A) or
+        (Box[I].RMin > R) or (Box[I].RMax < R) or (Box[I].GMin > G) or
+        (Box[I].GMax < G) or (Box[I].BMin > B) or (Box[I].BMax < B)) do
+        Inc(I);
+    if I = Boxes then
+      MapColor := 0
+    else
+      MapColor := I;
+  end;
+
+  procedure MapImage(Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo);
+  var
+    I: LongInt;
+    Col: TColor32Rec;
+  begin
+    for I := 0 to NumPixels - 1 do
+    begin
+      Col := GetPixel32Generic(Src, SrcInfo, nil);
+      IndexSetDstPixel(Dst, DstInfo, MapColor(Col));
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end;
+  end;
+
+begin
+  MaxColors := ClampInt(MaxColors, 2, MaxPossibleColors);
+
+  if (raUpdateHistogram in Actions) or (raMapImage in Actions) then
+  begin
+    Assert(not SrcInfo.IsSpecial);
+    Assert(not SrcInfo.IsIndexed);
+  end;
+
+  if raCreateHistogram in Actions then
+    FillChar(Table, SizeOf(Table), 0);
+
+  if raUpdateHistogram in Actions then
+    CreateHistogram(Src, SrcInfo, ChannelMask);
+
+  if raMakeColorMap in Actions then
+  begin
+    MakeColorMap;
+    FillOutputPalette;
+  end;
+
+  if raMapImage in Actions then
+    MapImage(Src, Dst, SrcInfo, DstInfo);
+end;
+
+procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt);
+var
+  Info: TImageFormatInfo;
+  ScaleX, ScaleY, X, Y, Xp, Yp: LongInt;
+  DstPixel, SrcLine: PByte;
+begin
+  GetImageFormatInfo(SrcImage.Format, Info);
+  Assert(SrcImage.Format = DstImage.Format);
+  Assert(not Info.IsSpecial);
+  // Use integers instead of floats for source image pixel coords
+  // Xp and Yp coords must be shifted right to get read source image coords
+  ScaleX := (SrcWidth shl 16) div DstWidth;
+  ScaleY := (SrcHeight shl 16) div DstHeight;
+  Yp := 0;
+  for Y := 0 to DstHeight - 1 do
+  begin
+    Xp := 0;
+    SrcLine := @PByteArray(SrcImage.Bits)[((SrcY + Yp shr 16) * SrcImage.Width + SrcX) * Info.BytesPerPixel];
+    DstPixel := @PByteArray(DstImage.Bits)[((DstY + Y) * DstImage.Width + DstX) * Info.BytesPerPixel];
+    for X := 0 to DstWidth - 1 do
+    begin
+      case Info.BytesPerPixel of
+        1: PByte(DstPixel)^ := PByteArray(SrcLine)[Xp shr 16];
+        2: PWord(DstPixel)^ := PWordArray(SrcLine)[Xp shr 16];
+        3: PColor24Rec(DstPixel)^ := PPalette24(SrcLine)[Xp shr 16];
+        4: PColor32(DstPixel)^ := PLongWordArray(SrcLine)[Xp shr 16];
+        6: PColor48Rec(DstPixel)^ := PColor48RecArray(SrcLine)[Xp shr 16];
+        8: PColor64(DstPixel)^ := PInt64Array(SrcLine)[Xp shr 16];
+        16: PColorFPRec(DstPixel)^ := PColorFPRecArray(SrcLine)[Xp shr 16];
+      end;
+      Inc(DstPixel, Info.BytesPerPixel);
+      Inc(Xp, ScaleX);
+    end;
+    Inc(Yp, ScaleY);
+  end;
+end;
+
+{ Filter function for nearest filtering. Also known as box filter.}
+function FilterNearest(Value: Single): Single;
+begin
+  if (Value > -0.5) and (Value <= 0.5) then
+    Result := 1
+  else
+    Result := 0;
+end;
+
+{ Filter function for linear filtering. Also known as triangle or Bartlett filter.}
+function FilterLinear(Value: Single): Single;
+begin
+  if Value < 0.0 then
+    Value := -Value;
+  if Value < 1.0 then
+    Result := 1.0 - Value
+  else
+    Result := 0.0;
+end;
+
+{ Cosine filter.}
+function FilterCosine(Value: Single): Single;
+begin
+  Result := 0;
+  if Abs(Value) < 1 then
+    Result := (Cos(Value * Pi) + 1) / 2;
+end;
+
+{ f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 }
+function FilterHermite(Value: Single): Single;
+begin
+  if Value < 0.0 then
+    Value := -Value;
+  if Value < 1 then
+    Result := (2 * Value - 3) * Sqr(Value) + 1
+  else
+    Result := 0;
+end;
+
+{ Quadratic filter. Also known as Bell.}
+function FilterQuadratic(Value: Single): Single;
+begin
+  if Value < 0.0 then
+    Value := -Value;
+  if Value < 0.5 then
+    Result := 0.75 - Sqr(Value)
+  else
+  if Value < 1.5 then
+  begin
+    Value := Value - 1.5;
+    Result := 0.5 * Sqr(Value);
+  end
+  else
+    Result := 0.0;
+end;
+
+{ Gaussian filter.}
+function FilterGaussian(Value: Single): Single;
+begin
+  Result := Exp(-2.0 * Sqr(Value)) * Sqrt(2.0 / Pi);
+end;
+
+{ 4th order (cubic) b-spline filter.}
+function FilterSpline(Value: Single): Single;
+var
+  Temp: Single;
+begin
+  if Value < 0.0 then
+    Value := -Value;
+  if Value < 1.0 then
+  begin
+    Temp := Sqr(Value);
+    Result := 0.5 * Temp * Value - Temp + 2.0 / 3.0;
+  end
+  else
+  if Value < 2.0 then
+  begin
+    Value := 2.0 - Value;
+    Result := Sqr(Value) * Value / 6.0;
+  end
+  else
+    Result := 0.0;
+end;
+
+{ Lanczos-windowed sinc filter.}
+function FilterLanczos(Value: Single): Single;
+
+  function SinC(Value: Single): Single;
+  begin
+    if Value <> 0.0 then
+    begin
+      Value := Value * Pi;
+      Result := Sin(Value) / Value;
+    end
+    else
+      Result := 1.0;
+  end;
+
+begin
+  if Value < 0.0 then
+    Value := -Value;
+  if Value < 3.0 then
+    Result := SinC(Value) * SinC(Value / 3.0)
+  else
+    Result := 0.0;
+end;
+
+{ Micthell cubic filter.}
+function FilterMitchell(Value: Single): Single;
+const
+  B = 1.0 / 3.0;
+  C = 1.0 / 3.0;
+var
+  Temp: Single;
+begin
+  if Value < 0.0 then
+    Value := -Value;
+  Temp := Sqr(Value);
+  if Value < 1.0 then
+  begin
+    Value := (((12.0 - 9.0 * B - 6.0 * C) * (Value * Temp)) +
+      ((-18.0 + 12.0 * B + 6.0 * C) * Temp) +
+      (6.0 - 2.0 * B));
+    Result := Value / 6.0;
+  end
+  else
+  if Value < 2.0 then
+  begin
+    Value := (((-B - 6.0 * C) * (Value * Temp)) +
+      ((6.0 * B + 30.0 * C) * Temp) +
+      ((-12.0 * B - 48.0 * C) * Value) +
+      (8.0 * B + 24.0 * C));
+    Result := Value / 6.0;
+  end
+  else
+    Result := 0.0;
+end;
+
+{ CatmullRom spline filter.}
+function FilterCatmullRom(Value: Single): Single;
+begin
+  if Value < 0.0 then
+    Value := -Value;
+  if Value < 1.0 then
+    Result := 0.5 * (2.0 + Sqr(Value) * (-5.0 + 3.0 * Value))
+  else
+  if Value < 2.0 then
+    Result := 0.5 * (4.0 + Value * (-8.0 + Value * (5.0 - Value)))
+  else
+    Result := 0.0;
+end;
+
+procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean);
+begin
+  // Calls the other function with filter function and radius defined by Filter
+  StretchResample(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY,
+    DstWidth, DstHeight, SamplingFilterFunctions[Filter], SamplingFilterRadii[Filter],
+    WrapEdges);
+end;
+
+var
+  FullEdge: Boolean = True;
+
+{ The following resampling code is modified and extended code from Graphics32
+  library by Alex A. Denisov.}
+function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt;
+  Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable;
+var
+  I, J, K, N: LongInt;
+  Left, Right, SrcWidth, DstWidth: LongInt;
+  Weight, Scale, Center, Count: Single;
+begin
+  Result := nil;
+  K := 0;
+  SrcWidth := SrcHigh - SrcLow;
+  DstWidth := DstHigh - DstLow;
+
+  // Check some special cases
+  if SrcWidth = 1 then
+  begin
+    SetLength(Result, DstWidth);
+    for I := 0 to DstWidth - 1 do
+    begin
+      SetLength(Result[I], 1);
+      Result[I][0].Pos := 0;
+      Result[I][0].Weight := 1.0;
+    end;
+    Exit;
+  end
+  else
+  if (SrcWidth = 0) or (DstWidth = 0) then
+    Exit;
+
+  if FullEdge then
+    Scale := DstWidth / SrcWidth
+  else
+    Scale := (DstWidth - 1) / (SrcWidth - 1);
+
+  SetLength(Result, DstWidth);
+
+  // Pre-calculate filter contributions for a row or column
+  if Scale = 0.0 then
+  begin
+    Assert(Length(Result) = 1);
+    SetLength(Result[0], 1);
+    Result[0][0].Pos := (SrcLow + SrcHigh) div 2;
+    Result[0][0].Weight := 1.0;
+  end
+  else if Scale < 1.0 then
+  begin
+    // Sub-sampling - scales from bigger to smaller
+    Radius := Radius / Scale;
+    for I := 0 to DstWidth - 1 do
+    begin
+      if FullEdge then
+        Center := SrcLow - 0.5 + (I + 0.5) / Scale
+      else
+        Center := SrcLow + I / Scale;
+      Left := Floor(Center - Radius);
+      Right := Ceil(Center + Radius);
+      Count := -1.0;
+      for J := Left to Right do
+      begin
+        Weight := Filter((Center - J) * Scale) * Scale;
+        if Weight <> 0.0 then
+        begin
+          Count := Count + Weight;
+          K := Length(Result[I]);
+          SetLength(Result[I], K + 1);
+          Result[I][K].Pos := ClampInt(J, SrcLow, SrcHigh - 1);
+          Result[I][K].Weight := Weight;
+        end;
+      end;
+      if Length(Result[I]) = 0 then
+      begin
+        SetLength(Result[I], 1);
+        Result[I][0].Pos := Floor(Center);
+        Result[I][0].Weight := 1.0;
+      end
+      else if Count <> 0.0 then
+        Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count;
+    end;
+  end
+  else // if Scale > 1.0 then
+  begin
+    // Super-sampling - scales from smaller to bigger
+    Scale := 1.0 / Scale;
+    for I := 0 to DstWidth - 1 do
+    begin
+      if FullEdge then
+        Center := SrcLow - 0.5 + (I + 0.5) * Scale
+      else
+        Center := SrcLow + I * Scale;
+      Left := Floor(Center - Radius);
+      Right := Ceil(Center + Radius);
+      Count := -1.0;
+      for J := Left to Right do
+      begin
+        Weight := Filter(Center - J);
+        if Weight <> 0.0 then
+        begin
+          Count := Count + Weight;
+          K := Length(Result[I]);
+          SetLength(Result[I], K + 1);
+
+          if WrapEdges then
+          begin
+            if J < 0 then
+              N := SrcImageWidth + J
+            else if J >= SrcImageWidth then
+              N := J - SrcImageWidth
+            else
+              N := ClampInt(J, SrcLow, SrcHigh - 1);
+          end
+          else
+            N := ClampInt(J, SrcLow, SrcHigh - 1);
+
+          Result[I][K].Pos := N;
+          Result[I][K].Weight := Weight;
+        end;
+      end;
+      if Count <> 0.0 then
+        Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count;
+    end;
+  end;
+end;
+
+procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt);
+var
+  I, J: LongInt;
+begin
+  if Length(Map) > 0 then
+  begin
+    MinPos := Map[0][0].Pos;
+    MaxPos := MinPos;
+    for I := 0 to Length(Map) - 1 do
+      for J := 0 to Length(Map[I]) - 1 do
+      begin
+        if MinPos > Map[I][J].Pos then
+          MinPos := Map[I][J].Pos;
+        if MaxPos < Map[I][J].Pos then
+          MaxPos := Map[I][J].Pos;
+      end;
+  end;
+end;
+
+procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth,
+  SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth,
+  DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean);
+const
+  Channel8BitMax: Single = 255.0;
+var
+  MapX, MapY: TMappingTable;
+  I, J, X, Y: LongInt;
+  XMinimum, XMaximum: LongInt;
+  LineBufferFP: array of TColorFPRec;
+  ClusterX, ClusterY: TCluster;
+  Weight, AccumA, AccumR, AccumG, AccumB: Single;
+  DstLine: PByte;
+  SrcFloat: TColorFPRec;
+  Info: TImageFormatInfo;
+  BytesPerChannel: LongInt;
+begin
+  GetImageFormatInfo(SrcImage.Format, Info);
+  Assert(SrcImage.Format = DstImage.Format);
+  Assert(not Info.IsSpecial and not Info.IsIndexed);
+  BytesPerChannel := Info.BytesPerPixel div Info.ChannelCount;
+
+  // Create horizontal and vertical mapping tables
+  MapX := BuildMappingTable(DstX, DstX + DstWidth, SrcX, SrcX + SrcWidth,
+    SrcImage.Width, Filter, Radius, WrapEdges);
+  MapY := BuildMappingTable(DstY, DstY + DstHeight, SrcY, SrcY + SrcHeight,
+    SrcImage.Height, Filter, Radius, WrapEdges);
+
+  if (MapX = nil) or (MapY = nil) then
+    Exit;
+
+  ClusterX := nil;
+  ClusterY := nil;
+
+  try
+    // Find min and max X coords of pixels that will contribute to target image
+    FindExtremes(MapX, XMinimum, XMaximum);
+
+    SetLength(LineBufferFP, XMaximum - XMinimum + 1);
+    // Following code works for the rest of data formats
+    for J := 0 to DstHeight - 1 do
+    begin
+      // First for each pixel in the current line sample vertically
+      // and store results in LineBuffer. Then sample horizontally
+      // using values in LineBuffer.
+      ClusterY := MapY[J];
+      for X := XMinimum to XMaximum do
+      begin
+        // Clear accumulators
+        AccumA := 0;
+        AccumR := 0;
+        AccumG := 0;
+        AccumB := 0;
+        // For each pixel in line compute weighted sum of pixels
+        // in source column that will contribute to this pixel
+        for Y := 0 to Length(ClusterY) - 1 do
+        begin
+          // Accumulate this pixel's weighted value
+          Weight := ClusterY[Y].Weight;
+          SrcFloat := Info.GetPixelFP(@PByteArray(SrcImage.Bits)[(ClusterY[Y].Pos * SrcImage.Width + X) * Info.BytesPerPixel], @Info, nil);
+          AccumB := AccumB + SrcFloat.B * Weight;
+          AccumG := AccumG + SrcFloat.G * Weight;
+          AccumR := AccumR + SrcFloat.R * Weight;
+          AccumA := AccumA + SrcFloat.A * Weight;
+        end;
+        // Store accumulated value for this pixel in buffer
+        with LineBufferFP[X - XMinimum] do
+        begin
+          A := AccumA;
+          R := AccumR;
+          G := AccumG;
+          B := AccumB;
+        end;
+      end;
+
+      DstLine := @PByteArray(DstImage.Bits)[((J + DstY) * DstImage.Width + DstX) * Info.BytesPerPixel];
+      // Now compute final colors for targte pixels in the current row
+      // by sampling horizontally
+      for I := 0 to DstWidth - 1 do
+      begin
+        ClusterX := MapX[I];
+        // Clear accumulator
+        AccumA := 0;
+        AccumR := 0;
+        AccumG := 0;
+        AccumB := 0;
+        // Compute weighted sum of values (which are already
+        // computed weighted sums of pixels in source columns stored in LineBuffer)
+        // that will contribute to the current target pixel
+        for X := 0 to Length(ClusterX) - 1 do
+        begin
+          Weight := ClusterX[X].Weight;
+          with LineBufferFP[ClusterX[X].Pos - XMinimum] do
+          begin
+            AccumB := AccumB + B * Weight;
+            AccumG := AccumG + G * Weight;
+            AccumR := AccumR + R * Weight;
+            AccumA := AccumA + A * Weight;
+          end;
+        end;
+
+        // Now compute final color to be written to dest image
+        SrcFloat.A := AccumA;
+        SrcFloat.R := AccumR;
+        SrcFloat.G := AccumG;
+        SrcFloat.B := AccumB;
+
+        Info.SetPixelFP(DstLine, @Info, nil, SrcFloat);
+        Inc(DstLine, Info.BytesPerPixel);
+      end;
+    end;
+
+  finally
+    MapX := nil;
+    MapY := nil;
+  end;
+end;
+
+procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt;
+  var SmallerLevel: TImageData);
+var
+  Filter: TSamplingFilter;
+  Info: TImageFormatInfo;
+  CompatibleCopy: TImageData;
+begin
+  Assert(TestImage(BiggerLevel));
+  Filter := TSamplingFilter(GetOption(ImagingMipMapFilter));
+
+  // If we have special format image we must create copy to allow pixel access
+  GetImageFormatInfo(BiggerLevel.Format, Info);
+  if Info.IsSpecial then
+  begin
+    InitImage(CompatibleCopy);
+    CloneImage(BiggerLevel, CompatibleCopy);
+    ConvertImage(CompatibleCopy, ifDefault);
+  end
+  else
+    CompatibleCopy := BiggerLevel;
+
+  // Create new smaller image
+  NewImage(Width, Height, CompatibleCopy.Format, SmallerLevel);
+  GetImageFormatInfo(CompatibleCopy.Format, Info);
+  // If input is indexed we must copy its palette
+  if Info.IsIndexed then
+    CopyPalette(CompatibleCopy.Palette, SmallerLevel.Palette, 0, 0, Info.PaletteEntries);
+
+  if (Filter = sfNearest) or Info.IsIndexed then
+  begin
+    StretchNearest(CompatibleCopy, 0, 0, CompatibleCopy.Width, CompatibleCopy.Height,
+      SmallerLevel, 0, 0, Width, Height);
+  end
+  else
+  begin
+    StretchResample(CompatibleCopy, 0, 0, CompatibleCopy.Width, CompatibleCopy.Height,
+      SmallerLevel, 0, 0, Width, Height, Filter);
+  end;
+
+  // Free copy and convert result to special format if necessary
+  if CompatibleCopy.Format <> BiggerLevel.Format then
+  begin
+    ConvertImage(SmallerLevel, BiggerLevel.Format);
+    FreeImage(CompatibleCopy);
+  end;
+end;
+
+
+{ Various format support functions }
+
+procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt);
+begin
+  case BytesPerPixel of
+    1: PByte(Dest)^ := PByte(Src)^;
+    2: PWord(Dest)^ := PWord(Src)^;
+    3: PColor24Rec(Dest)^ := PColor24Rec(Src)^;
+    4: PLongWord(Dest)^ := PLongWord(Src)^;
+    6: PColor48Rec(Dest)^ := PColor48Rec(Src)^;
+    8: PInt64(Dest)^ := PInt64(Src)^;
+    12: PColor96FPRec(Dest)^ := PColor96FPRec(Src)^;
+    16: PColorFPRec(Dest)^ := PColorFPRec(Src)^;
+  end;
+end;
+
+function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean;
+begin
+  case BytesPerPixel of
+    1: Result := PByte(PixelA)^ = PByte(PixelB)^;
+    2: Result := PWord(PixelA)^ = PWord(PixelB)^;
+    3: Result := (PWord(PixelA)^ = PWord(PixelB)^) and (PColor24Rec(PixelA).R = PColor24Rec(PixelB).R);
+    4: Result := PLongWord(PixelA)^ = PLongWord(PixelB)^;
+    6: Result := (PLongWord(PixelA)^ = PLongWord(PixelB)^) and (PColor48Rec(PixelA).R = PColor48Rec(PixelB).R);
+    8: Result := PInt64(PixelA)^ = PInt64(PixelB)^;
+    12: Result := (PFloatHelper(PixelA).Data = PFloatHelper(PixelB).Data) and
+          (PFloatHelper(PixelA).Data32 = PFloatHelper(PixelB).Data32);
+    16: Result := (PFloatHelper(PixelA).Data = PFloatHelper(PixelB).Data) and
+          (PFloatHelper(PixelA).Data64 = PFloatHelper(PixelB).Data64);
+  else
+    Result := False;
+  end;
+end;
+
+procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat,
+  DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32);
+var
+  SrcInfo, DstInfo: PImageFormatInfo;
+  PixFP: TColorFPRec;
+begin
+  SrcInfo := FInfos[SrcFormat];
+  DstInfo := FInfos[DstFormat];
+
+  PixFP := GetPixelFPGeneric(SrcPixel, SrcInfo, SrcPalette);
+  SetPixelFPGeneric(DstPixel, DstInfo, DstPalette, PixFP);
+end;
+
+procedure ClampFloatPixel(var PixF: TColorFPRec);
+begin
+  if PixF.A > 1.0 then
+    PixF.A := 1.0;
+  if PixF.R > 1.0 then
+    PixF.R := 1.0;
+  if PixF.G > 1.0 then
+    PixF.G := 1.0;
+  if PixF.B > 1.0 then
+    PixF.B := 1.0;
+
+  if PixF.A < 0.0 then
+    PixF.A := 0.0;
+  if PixF.R < 0.0 then
+    PixF.R := 0.0;
+  if PixF.G < 0.0 then
+    PixF.G := 0.0;
+  if PixF.B < 0.0 then
+    PixF.B := 0.0;
+end;
+
+procedure ConvertToPixel32(SrcPix: PByte; DestPix: PColor32Rec;
+  const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32);
+begin
+  case SrcInfo.Format of
+    ifIndex8:
+      begin
+        DestPix^ := SrcPalette[SrcPix^];
+      end;
+    ifGray8:
+      begin
+        DestPix.R := SrcPix^;
+        DestPix.G := SrcPix^;
+        DestPix.B := SrcPix^;
+        DestPix.A := 255;
+      end;
+    ifA8Gray8:
+      begin
+        DestPix.R := SrcPix^;
+        DestPix.G := SrcPix^;
+        DestPix.B := SrcPix^;
+        DestPix.A := PWordRec(SrcPix).High;
+      end;
+    ifGray16:
+      begin
+        DestPix.R := PWord(SrcPix)^ shr 8;
+        DestPix.G := DestPix.R;
+        DestPix.B := DestPix.R;
+        DestPix.A := 255;
+      end;
+    ifR8G8B8:
+      begin
+        DestPix.Color24Rec := PColor24Rec(SrcPix)^;
+        DestPix.A := 255;
+      end;
+    ifA8R8G8B8:
+      begin
+        DestPix^ := PColor32Rec(SrcPix)^;
+      end;
+    ifR16G16B16:
+      begin
+        DestPix.R := PColor48Rec(SrcPix).R shr 8;
+        DestPix.G := PColor48Rec(SrcPix).G shr 8;
+        DestPix.B := PColor48Rec(SrcPix).B shr 8;
+        DestPix.A := 255;
+      end;
+    ifA16R16G16B16:
+      begin
+        DestPix.R := PColor64Rec(SrcPix).R shr 8;
+        DestPix.G := PColor64Rec(SrcPix).G shr 8;
+        DestPix.B := PColor64Rec(SrcPix).B shr 8;
+        DestPix.A := PColor64Rec(SrcPix).A shr 8;
+      end;
+  else
+    DestPix^ := SrcInfo.GetPixel32(SrcPix, @SrcInfo, SrcPalette);
+  end;
+end;
+
+procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
+  Bpp, WidthBytes: LongInt);
+var
+  I, W: LongInt;
+begin
+  W := Width * Bpp;
+  for I := 0 to Height - 1 do
+    Move(PByteArray(DataIn)[I * W], PByteArray(DataOut)[I * WidthBytes], W);
+end;
+
+procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height,
+  Bpp, WidthBytes: LongInt);
+var
+  I, W: LongInt;
+begin
+  W := Width * Bpp;
+  for I := 0 to Height - 1 do
+    Move(PByteArray(DataIn)[I * WidthBytes], PByteArray(DataOut)[I * W], W);
+end;
+
+procedure Convert1To8(DataIn, DataOut: PByte; Width, Height,
+  WidthBytes: LongInt; ScaleTo8Bits: Boolean);
+const
+  Mask1: array[0..7] of Byte = ($80, $40, $20, $10, $08, $04, $02, $01);
+  Shift1: array[0..7] of Byte = (7, 6, 5, 4, 3, 2, 1, 0);
+  Scaling: Byte = 255;
+var
+  X, Y: LongInt;
+  InArray: PByteArray absolute DataIn;
+begin
+  for Y := 0 to Height - 1 do
+    for X := 0 to Width - 1 do
+    begin
+      DataOut^ := (InArray[Y * WidthBytes + X shr 3] and Mask1[X and 7]) shr Shift1[X and 7];
+      if ScaleTo8Bits then
+        DataOut^ := DataOut^ * Scaling;
+      Inc(DataOut);
+    end;
+end;
+
+procedure Convert2To8(DataIn, DataOut: PByte; Width, Height,
+  WidthBytes: LongInt; ScaleTo8Bits: Boolean);
+const
+  Mask2: array[0..3] of Byte = ($C0, $30, $0C, $03);
+  Shift2: array[0..3] of Byte = (6, 4, 2, 0);
+  Scaling: Byte = 85;
+var
+  X, Y: LongInt;
+  InArray: PByteArray absolute DataIn;
+begin
+  for Y := 0 to Height - 1 do
+    for X := 0 to Width - 1 do
+    begin
+      DataOut^ := (InArray[Y * WidthBytes + X shr 2] and Mask2[X and 3]) shr Shift2[X and 3];
+      if ScaleTo8Bits then
+        DataOut^ := DataOut^ * Scaling;
+      Inc(DataOut);
+    end;
+end;
+
+procedure Convert4To8(DataIn, DataOut: PByte; Width, Height,
+  WidthBytes: LongInt; ScaleTo8Bits: Boolean);
+const
+  Mask4: array[0..1] of Byte = ($F0, $0F);
+  Shift4: array[0..1] of Byte = (4, 0);
+  Scaling: Byte = 17;
+var
+  X, Y: LongInt;
+  InArray: PByteArray absolute DataIn;
+begin
+  for Y := 0 to Height - 1 do
+    for X := 0 to Width - 1 do
+    begin
+      DataOut^ := (InArray[Y * WidthBytes + X shr 1] and  Mask4[X and 1]) shr Shift4[X and 1];
+      if ScaleTo8Bits then
+        DataOut^ := DataOut^ * Scaling;
+      Inc(DataOut);
+    end;
+end;
+
+function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean;
+var
+  I: LongInt;
+begin
+  Result := False;
+  for I := 0 to NumPixels - 1 do
+  begin
+    if Data^ >= 1 shl 15 then
+    begin
+      Result := True;
+      Exit;
+    end;
+    Inc(Data);
+  end;
+end;
+
+function Has32BitImageAlpha(NumPixels: LongInt; Data: PLongWord): Boolean;
+var
+  I: LongInt;
+begin
+  Result := False;
+  for I := 0 to NumPixels - 1 do
+  begin
+    if Data^ >= 1 shl 24 then
+    begin
+      Result := True;
+      Exit;
+    end;
+    Inc(Data);
+  end;
+end;
+
+function PaletteHasAlpha(Palette: PPalette32; PaletteEntries: Integer): Boolean;
+var
+  I: Integer;
+begin
+  for I := 0 to PaletteEntries - 1 do
+  begin
+    if Palette[I].A <> 255 then
+    begin
+      Result := True;
+      Exit;
+    end;
+  end;
+  Result := False;
+end;
+
+function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo;
+  LineWidth, Index: LongInt): Pointer;
+var
+  LineBytes: LongInt;
+begin
+  Assert(not FormatInfo.IsSpecial);
+  LineBytes := FormatInfo.GetPixelsSize(FormatInfo.Format, LineWidth, 1);
+  Result := @PByteArray(ImageBits)[Index * LineBytes];
+end;
+
+function IsImageFormatValid(Format: TImageFormat): Boolean;
+begin
+  Result := FInfos[Format] <> nil;
+end;
+
+const
+  HalfMin:     Single = 5.96046448e-08; // Smallest positive half
+  HalfMinNorm: Single = 6.10351562e-05; // Smallest positive normalized half
+  HalfMax:     Single = 65504.0;        // Largest positive half
+  HalfEpsilon: Single = 0.00097656;     // Smallest positive e for which half (1.0 + e) != half (1.0)
+  HalfNaN:     THalfFloat = 65535;
+  HalfPosInf:  THalfFloat = 31744;
+  HalfNegInf:  THalfFloat = 64512;
+
+
+{
+  Half/Float conversions inspired by half class from OpenEXR library.
+
+  Float (Pascal Single type) is an IEEE 754 single-precision
+  floating point number.
+
+  Bit layout of Single:
+
+    31 (msb)
+    |
+    | 30     23
+    | |      |
+    | |      | 22                    0 (lsb)
+    | |      | |                     |
+    X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX
+    s e        m
+
+  Bit layout of half:
+
+    15 (msb)
+    |
+    | 14  10
+    | |   |
+    | |   | 9        0 (lsb)
+    | |   | |        |
+    X XXXXX XXXXXXXXXX
+    s e     m
+
+  S is the sign-bit, e is the exponent and m is the significand (mantissa).
+}
+
+function HalfToFloat(Half: THalfFloat): Single;
+var
+  Dst, Sign, Mantissa: LongWord;
+  Exp: LongInt;
+begin
+  // Extract sign, exponent, and mantissa from half number
+  Sign := Half shr 15;
+  Exp := (Half and $7C00) shr 10;
+  Mantissa := Half and 1023;
+
+  if (Exp > 0) and (Exp < 31) then
+  begin
+    // Common normalized number
+    Exp := Exp + (127 - 15);
+    Mantissa := Mantissa shl 13;
+    Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa;
+    // Result := Power(-1, Sign) * Power(2, Exp - 15) * (1 + Mantissa / 1024);
+  end
+  else if (Exp = 0) and (Mantissa = 0) then
+  begin
+    // Zero - preserve sign
+    Dst := Sign shl 31;
+  end
+  else if (Exp = 0) and (Mantissa <> 0) then
+  begin
+    // Denormalized number - renormalize it
+    while (Mantissa and $00000400) = 0 do
+    begin
+      Mantissa := Mantissa shl 1;
+      Dec(Exp);
+    end;
+    Inc(Exp);
+    Mantissa := Mantissa and not $00000400;
+    // Now assemble normalized number
+    Exp := Exp + (127 - 15);
+    Mantissa := Mantissa shl 13;
+    Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa;
+    // Result := Power(-1, Sign) * Power(2, -14) * (Mantissa / 1024);
+  end
+  else if (Exp = 31) and (Mantissa = 0) then
+  begin
+    // +/- infinity
+    Dst := (Sign shl 31) or $7F800000;
+  end
+  else //if (Exp = 31) and (Mantisa <> 0) then
+  begin
+    // Not a number - preserve sign and mantissa
+    Dst := (Sign shl 31) or $7F800000 or (Mantissa shl 13);
+  end;
+
+  // Reinterpret LongWord as Single
+  Result := PSingle(@Dst)^;
+end;
+
+function FloatToHalf(Float: Single): THalfFloat;
+var
+  Src: LongWord;
+  Sign, Exp, Mantissa: LongInt;
+begin
+  Src := PLongWord(@Float)^;
+  // Extract sign, exponent, and mantissa from Single number
+  Sign := Src shr 31;
+  Exp := LongInt((Src and $7F800000) shr 23) - 127 + 15;
+  Mantissa := Src and $007FFFFF;
+
+  if (Exp > 0) and (Exp < 30) then
+  begin
+    // Simple case - round the significand and combine it with the sign and exponent
+    Result := (Sign shl 15) or (Exp shl 10) or ((Mantissa + $00001000) shr 13);
+  end
+  else if Src = 0 then
+  begin
+    // Input float is zero - return zero
+    Result := 0;
+  end
+  else
+  begin
+    // Difficult case - lengthy conversion
+    if Exp <= 0 then
+    begin
+      if Exp < -10 then
+      begin
+        // Input float's value is less than HalfMin, return zero
+        Result := 0;
+      end
+      else
+      begin
+        // Float is a normalized Single whose magnitude is less than HalfNormMin.
+        // We convert it to denormalized half.
+        Mantissa := (Mantissa or $00800000) shr (1 - Exp);
+        // Round to nearest
+        if (Mantissa and $00001000) > 0 then
+          Mantissa := Mantissa + $00002000;
+        // Assemble Sign and Mantissa (Exp is zero to get denormalized number)
+        Result := (Sign shl 15) or (Mantissa shr 13);
+      end;
+    end
+    else if Exp = 255 - 127 + 15 then
+    begin
+      if Mantissa = 0 then
+      begin
+        // Input float is infinity, create infinity half with original sign
+        Result := (Sign shl 15) or $7C00;
+      end
+      else
+      begin
+        // Input float is NaN, create half NaN with original sign and mantissa
+        Result := (Sign shl 15) or $7C00 or (Mantissa shr 13);
+      end;
+    end
+    else
+    begin
+      // Exp is > 0 so input float is normalized Single
+
+      // Round to nearest
+      if (Mantissa and $00001000) > 0 then
+      begin
+        Mantissa := Mantissa + $00002000;
+        if (Mantissa and $00800000) > 0 then
+        begin
+          Mantissa := 0;
+          Exp := Exp + 1;
+        end;
+      end;
+
+      if Exp > 30 then
+      begin
+        // Exponent overflow - return infinity half
+        Result := (Sign shl 15) or $7C00;
+      end
+      else
+        // Assemble normalized half
+        Result := (Sign shl 15) or (Exp shl 10) or (Mantissa shr 13);
+    end;
+  end;
+end;
+
+function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec;
+begin
+  Result.A := HalfToFloat(ColorHF.A);
+  Result.R := HalfToFloat(ColorHF.R);
+  Result.G := HalfToFloat(ColorHF.G);
+  Result.B := HalfToFloat(ColorHF.B);
+end;
+
+function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec;
+begin
+  Result.A := FloatToHalf(ColorFP.A);
+  Result.R := FloatToHalf(ColorFP.R);
+  Result.G := FloatToHalf(ColorFP.G);
+  Result.B := FloatToHalf(ColorFP.B);
+end;
+
+procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData);
+var
+  I: Integer;
+  Pix: PColor32;
+begin
+  InitImage(PalImage);
+  NewImage(Entries, 1, ifA8R8G8B8, PalImage);
+  Pix := PalImage.Bits;
+  for I := 0 to Entries - 1 do
+  begin
+    Pix^ := Pal[I].Color;
+    Inc(Pix);
+  end;
+end;
+
+
+{ Pixel readers/writers for different image formats }
+
+procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Pix: TColor64Rec);
+var
+  A, R, G, B: Byte;
+begin
+  A := 0;
+  R := 0;
+  G := 0;
+  B := 0;
+  FillChar(Pix, SizeOf(Pix), 0);
+  // returns 64 bit color value with 16 bits for each channel
+  case SrcInfo.BytesPerPixel of
+    1:
+      begin
+        PFGetARGB(SrcInfo.PixelFormat^, Src^, A, R, G, B);
+        Pix.A := A shl 8;
+        Pix.R := R shl 8;
+        Pix.G := G shl 8;
+        Pix.B := B shl 8;
+      end;
+    2:
+      begin
+        PFGetARGB(SrcInfo.PixelFormat^, PWord(Src)^, A, R, G, B);
+        Pix.A := A shl 8;
+        Pix.R := R shl 8;
+        Pix.G := G shl 8;
+        Pix.B := B shl 8;
+      end;
+    3:
+      with Pix do
+      begin
+        R := MulDiv(PColor24Rec(Src).R, 65535, 255);
+        G := MulDiv(PColor24Rec(Src).G, 65535, 255);
+        B := MulDiv(PColor24Rec(Src).B, 65535, 255);
+      end;
+    4:
+      with Pix do
+      begin
+        A := MulDiv(PColor32Rec(Src).A, 65535, 255);
+        R := MulDiv(PColor32Rec(Src).R, 65535, 255);
+        G := MulDiv(PColor32Rec(Src).G, 65535, 255);
+        B := MulDiv(PColor32Rec(Src).B, 65535, 255);
+      end;
+    6:
+      with Pix do
+      begin
+        R := PColor48Rec(Src).R;
+        G := PColor48Rec(Src).G;
+        B := PColor48Rec(Src).B;
+      end;
+    8: Pix.Color := PColor64(Src)^;
+  end;
+  // if src has no alpha, we set it to max (otherwise we would have to
+  // test if dest has alpha or not in each ChannelToXXX function)
+  if not SrcInfo.HasAlphaChannel then
+    Pix.A := 65535;
+
+  if SrcInfo.IsRBSwapped then
+    SwapValues(Pix.R, Pix.B);
+end;
+
+procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  const Pix: TColor64Rec);
+var
+  PixW: TColor64Rec;
+begin
+  PixW := Pix;
+  if DstInfo.IsRBSwapped then
+    SwapValues(PixW.R, PixW.B);
+  // Pix contains 64 bit color value with 16 bit for each channel
+  case DstInfo.BytesPerPixel of
+    1: Dst^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8,
+        PixW.R shr 8, PixW.G shr 8, PixW.B shr 8);
+    2: PWord(Dst)^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8,
+        PixW.R shr 8, PixW.G shr 8, PixW.B shr 8);
+    3:
+      with PColor24Rec(Dst)^ do
+      begin
+        R := MulDiv(PixW.R, 255, 65535);
+        G := MulDiv(PixW.G, 255, 65535);
+        B := MulDiv(PixW.B, 255, 65535);
+      end;
+    4:
+      with PColor32Rec(Dst)^ do
+      begin
+        A := MulDiv(PixW.A, 255, 65535);
+        R := MulDiv(PixW.R, 255, 65535);
+        G := MulDiv(PixW.G, 255, 65535);
+        B := MulDiv(PixW.B, 255, 65535);
+      end;
+    6:
+      with PColor48Rec(Dst)^ do
+      begin
+        R := PixW.R;
+        G := PixW.G;
+        B := PixW.B;
+      end;
+    8: PColor64(Dst)^ := PixW.Color;
+  end;
+end;
+
+procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Gray: TColor64Rec; var Alpha: Word);
+begin
+  FillChar(Gray, SizeOf(Gray), 0);
+  // Source alpha is scaled to 16 bits and stored in Alpha,
+  // grayscale value is scaled to 64 bits and stored in Gray
+  case SrcInfo.BytesPerPixel of
+    1: Gray.A := MulDiv(Src^, 65535, 255);
+    2:
+      if SrcInfo.HasAlphaChannel then
+        with PWordRec(Src)^ do
+        begin
+          Alpha := MulDiv(High, 65535, 255);
+          Gray.A := MulDiv(Low, 65535, 255);
+        end
+      else
+        Gray.A := PWord(Src)^;
+    4:
+      if SrcInfo.HasAlphaChannel then
+        with PLongWordRec(Src)^ do
+        begin
+          Alpha := High;
+          Gray.A := Low;
+        end
+      else
+        with PLongWordRec(Src)^ do
+        begin
+          Gray.A := High;
+          Gray.R := Low;
+        end;
+    8: Gray.Color := PColor64(Src)^;
+  end;
+  // if src has no alpha, we set it to max (otherwise we would have to
+  // test if dest has alpha or not in each GrayToXXX function)
+  if not SrcInfo.HasAlphaChannel then
+    Alpha := 65535;
+end;
+
+procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  const Gray: TColor64Rec; Alpha: Word);
+begin
+  // Gray contains grayscale value scaled to 64 bits, Alpha contains
+  // alpha value scaled to 16 bits
+  case DstInfo.BytesPerPixel of
+    1: Dst^ := MulDiv(Gray.A, 255, 65535);
+    2:
+      if DstInfo.HasAlphaChannel then
+        with PWordRec(Dst)^ do
+        begin
+          High := MulDiv(Alpha, 255, 65535);
+          Low := MulDiv(Gray.A, 255, 65535);
+        end
+      else
+        PWord(Dst)^ := Gray.A;
+    4:
+      if DstInfo.HasAlphaChannel then
+        with PLongWordRec(Dst)^ do
+        begin
+          High := Alpha;
+          Low := Gray.A;
+        end
+      else
+        with PLongWordRec(Dst)^ do
+        begin
+          High := Gray.A;
+          Low := Gray.R;
+        end;
+    8: PColor64(Dst)^ := Gray.Color;
+  end;
+end;
+
+procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Pix: TColorFPRec);
+var
+  PixHF: TColorHFRec;
+begin
+  Assert(SrcInfo.BytesPerPixel in [2, 4, 8, 12, 16]);
+
+  if SrcInfo.BytesPerPixel in [4, 12, 16] then
+  begin
+    // IEEE 754 single-precision channels
+    FillChar(Pix, SizeOf(Pix), 0);
+    case SrcInfo.BytesPerPixel of
+      4: Pix.R := PSingle(Src)^;
+      12: Pix.Color96Rec := PColor96FPRec(Src)^;
+      16: Pix := PColorFPRec(Src)^;
+    end;
+  end
+  else
+  begin
+    // Half float channels
+    FillChar(PixHF, SizeOf(PixHF), 0);
+    case SrcInfo.BytesPerPixel of
+      2: PixHF.R := PHalfFloat(Src)^;
+      8: PixHF := PColorHFRec(Src)^;
+    end;
+    Pix := ColorHalfToFloat(PixHF);
+  end;
+
+  // If src has no alpha, we set it to max (otherwise we would have to
+  // test if dest has alpha or not in each FloatToXXX function)
+  if not SrcInfo.HasAlphaChannel then
+    Pix.A := 1.0;
+  if SrcInfo.IsRBSwapped then
+    SwapValues(Pix.R, Pix.B);
+end;
+
+procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  const Pix: TColorFPRec);
+var
+  PixW: TColorFPRec;
+  PixHF: TColorHFRec;
+begin
+  Assert(DstInfo.BytesPerPixel in [2, 4, 8, 12, 16]);
+
+  PixW := Pix;
+  if DstInfo.IsRBSwapped then
+    SwapValues(PixW.R, PixW.B);
+
+  if DstInfo.BytesPerPixel in [4, 12, 16] then
+  begin
+    case DstInfo.BytesPerPixel of
+      4:  PSingle(Dst)^ := PixW.R;
+      12: PColor96FPRec(Dst)^:= PixW.Color96Rec;
+      16: PColorFPRec(Dst)^ := PixW;
+    end;
+  end
+  else
+  begin
+    PixHF := ColorFloatToHalf(PixW);
+    case DstInfo.BytesPerPixel of
+      2: PHalfFloat(Dst)^ := PixHF.R;
+      8: PColorHFRec(Dst)^ := PixHF;
+    end;
+  end;
+end;
+
+procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo;
+  var Index: LongWord);
+begin
+  case SrcInfo.BytesPerPixel of
+    1: Index := Src^;
+  end;
+end;
+
+procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo;
+  Index: LongWord);
+begin
+  case DstInfo.BytesPerPixel of
+    1: Dst^ := Byte(Index);
+    2: PWord(Dst)^ := Word(Index);
+    4: PLongWord(Dst)^ := Index;
+  end;
+end;
+
+
+{ Pixel readers/writers for 32bit and FP colors}
+
+function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec;
+var
+  Pix64: TColor64Rec;
+  PixF: TColorFPRec;
+  Alpha: Word;
+  Index: LongWord;
+begin
+  if Info.Format = ifA8R8G8B8 then
+  begin
+    Result := PColor32Rec(Bits)^
+  end
+  else if Info.Format = ifR8G8B8 then
+  begin
+    PColor24Rec(@Result)^ := PColor24Rec(Bits)^;
+    Result.A := $FF;
+  end
+  else if Info.IsFloatingPoint then
+  begin
+    FloatGetSrcPixel(Bits, Info, PixF);
+    Result.A := ClampToByte(Round(PixF.A * 255.0));
+    Result.R := ClampToByte(Round(PixF.R * 255.0));
+    Result.G := ClampToByte(Round(PixF.G * 255.0));
+    Result.B := ClampToByte(Round(PixF.B * 255.0));
+  end
+  else if Info.HasGrayChannel then
+  begin
+    GrayGetSrcPixel(Bits, Info, Pix64, Alpha);
+    Result.A := MulDiv(Alpha, 255, 65535);
+    Result.R := MulDiv(Pix64.A, 255, 65535);
+    Result.G := MulDiv(Pix64.A, 255, 65535);
+    Result.B := MulDiv(Pix64.A, 255, 65535);
+  end
+  else if Info.IsIndexed then
+  begin
+    IndexGetSrcPixel(Bits, Info, Index);
+    Result := Palette[Index];
+  end
+  else
+  begin
+    ChannelGetSrcPixel(Bits, Info, Pix64);
+    Result.A := MulDiv(Pix64.A, 255, 65535);
+    Result.R := MulDiv(Pix64.R, 255, 65535);
+    Result.G := MulDiv(Pix64.G, 255, 65535);
+    Result.B := MulDiv(Pix64.B, 255, 65535);
+  end;
+end;
+
+procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec);
+var
+  Pix64: TColor64Rec;
+  PixF: TColorFPRec;
+  Alpha: Word;
+  Index: LongWord;
+begin
+  if Info.Format = ifA8R8G8B8 then
+  begin
+    PColor32Rec(Bits)^ := Color
+  end
+  else if Info.Format = ifR8G8B8 then
+  begin
+    PColor24Rec(Bits)^ := Color.Color24Rec;
+  end
+  else if Info.IsFloatingPoint then
+  begin
+    PixF.A := Color.A * OneDiv8Bit;
+    PixF.R := Color.R * OneDiv8Bit;
+    PixF.G := Color.G * OneDiv8Bit;
+    PixF.B := Color.B * OneDiv8Bit;
+    FloatSetDstPixel(Bits, Info, PixF);
+  end
+  else if Info.HasGrayChannel then
+  begin
+    Alpha := MulDiv(Color.A, 65535, 255);
+    Pix64.Color := 0;
+    Pix64.A := MulDiv(Round(GrayConv.R * Color.R + GrayConv.G * Color.G +
+      GrayConv.B * Color.B), 65535, 255);
+    GraySetDstPixel(Bits, Info, Pix64, Alpha);
+  end
+  else if Info.IsIndexed then
+  begin
+    Index := FindColor(Palette, Info.PaletteEntries, Color.Color);
+    IndexSetDstPixel(Bits, Info, Index);
+  end
+  else
+  begin
+    Pix64.A := MulDiv(Color.A, 65535, 255);
+    Pix64.R := MulDiv(Color.R, 65535, 255);
+    Pix64.G := MulDiv(Color.G, 65535, 255);
+    Pix64.B := MulDiv(Color.B, 65535, 255);
+    ChannelSetDstPixel(Bits, Info, Pix64);
+  end;
+end;
+
+function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
+var
+  Pix32: TColor32Rec;
+  Pix64: TColor64Rec;
+  Alpha: Word;
+  Index: LongWord;
+begin
+  if Info.IsFloatingPoint then
+  begin
+    FloatGetSrcPixel(Bits, Info, Result);
+  end
+  else if Info.HasGrayChannel then
+  begin
+    GrayGetSrcPixel(Bits, Info, Pix64, Alpha);
+    Result.A := Alpha * OneDiv16Bit;
+    Result.R := Pix64.A * OneDiv16Bit;
+    Result.G := Pix64.A * OneDiv16Bit;
+    Result.B := Pix64.A * OneDiv16Bit;
+  end
+  else if Info.IsIndexed then
+  begin
+    IndexGetSrcPixel(Bits, Info, Index);
+    Pix32 := Palette[Index];
+    Result.A := Pix32.A * OneDiv8Bit;
+    Result.R := Pix32.R * OneDiv8Bit;
+    Result.G := Pix32.G * OneDiv8Bit;
+    Result.B := Pix32.B * OneDiv8Bit;
+  end
+  else
+  begin
+    ChannelGetSrcPixel(Bits, Info, Pix64);
+    Result.A := Pix64.A * OneDiv16Bit;
+    Result.R := Pix64.R * OneDiv16Bit;
+    Result.G := Pix64.G * OneDiv16Bit;
+    Result.B := Pix64.B * OneDiv16Bit;
+  end;
+end;
+
+procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
+var
+  Pix32: TColor32Rec;
+  Pix64: TColor64Rec;
+  Alpha: Word;
+  Index: LongWord;
+begin
+  if Info.IsFloatingPoint then
+  begin
+    FloatSetDstPixel(Bits, Info, Color);
+  end
+  else if Info.HasGrayChannel then
+  begin
+    Alpha := ClampToWord(Round(Color.A * 65535.0));
+    Pix64.Color := 0;
+    Pix64.A := ClampToWord(Round((GrayConv.R * Color.R + GrayConv.G * Color.G +
+      GrayConv.B * Color.B) * 65535.0));
+    GraySetDstPixel(Bits, Info, Pix64, Alpha);
+  end
+  else if Info.IsIndexed then
+  begin
+    Pix32.A := ClampToByte(Round(Color.A * 255.0));
+    Pix32.R := ClampToByte(Round(Color.R * 255.0));
+    Pix32.G := ClampToByte(Round(Color.G * 255.0));
+    Pix32.B := ClampToByte(Round(Color.B * 255.0));
+    Index := FindColor(Palette, Info.PaletteEntries, Pix32.Color);
+    IndexSetDstPixel(Bits, Info, Index);
+  end
+  else
+  begin
+    Pix64.A := ClampToWord(Round(Color.A * 65535.0));
+    Pix64.R := ClampToWord(Round(Color.R * 65535.0));
+    Pix64.G := ClampToWord(Round(Color.G * 65535.0));
+    Pix64.B := ClampToWord(Round(Color.B * 65535.0));
+    ChannelSetDstPixel(Bits, Info, Pix64);
+  end;
+end;
+
+
+{ Image format conversion functions }
+
+procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  Pix64: TColor64Rec;
+begin
+  // two most common conversions (RGB->ARGB and ARGB->RGB for 24/32 bit
+  // images) are made separately from general ARGB conversion to
+  // make them faster
+  if (SrcInfo.BytesPerPixel = 3) and (DstInfo.BytesPerPixel = 4) then
+  for I := 0 to NumPixels - 1 do
+    begin
+      PColor24Rec(Dst)^ := PColor24Rec(Src)^;
+      if DstInfo.HasAlphaChannel then
+        PColor32Rec(Dst).A := 255;
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end
+  else
+  if (SrcInfo.BytesPerPixel = 4) and (DstInfo.BytesPerPixel = 3) then
+    for I := 0 to NumPixels - 1 do
+    begin
+      PColor24Rec(Dst)^ := PColor24Rec(Src)^;
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end
+  else
+    for I := 0 to NumPixels - 1 do
+    begin
+      // general ARGB conversion
+      ChannelGetSrcPixel(Src, SrcInfo, Pix64);
+      ChannelSetDstPixel(Dst, DstInfo, Pix64);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end;
+end;
+
+procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  Pix64: TColor64Rec;
+  Alpha: Word;
+begin
+  // two most common conversions (R8G8B8->Gray8 nad A8R8G8B8->Gray8)
+  // are made separately from general conversions to make them faster
+  if (SrcInfo.BytesPerPixel in [3, 4]) and (DstInfo.Format = ifGray8) then
+    for I := 0 to NumPixels - 1 do
+    begin
+      Dst^ := Round(GrayConv.R * PColor24Rec(Src).R + GrayConv.G * PColor24Rec(Src).G +
+        GrayConv.B * PColor24Rec(Src).B);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end
+  else
+    for I := 0 to NumPixels - 1 do
+    begin
+      ChannelGetSrcPixel(Src, SrcInfo, Pix64);
+
+      // alpha is saved from source pixel to Alpha,
+      // Gray value is computed and set to highest word of Pix64 so
+      // Pix64.Color contains grayscale value scaled to 64 bits
+      Alpha := Pix64.A;
+      with GrayConv do
+        Pix64.A := Round(R * Pix64.R + G * Pix64.G + B * Pix64.B);
+
+      GraySetDstPixel(Dst, DstInfo, Pix64, Alpha);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end;
+end;
+
+procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  Pix64: TColor64Rec;
+  PixF: TColorFPRec;
+begin
+  for I := 0 to NumPixels - 1 do
+  begin
+    ChannelGetSrcPixel(Src, SrcInfo, Pix64);
+
+    // floating point channel values are scaled to 1.0
+    PixF.A := Pix64.A * OneDiv16Bit;
+    PixF.R := Pix64.R * OneDiv16Bit;
+    PixF.G := Pix64.G * OneDiv16Bit;
+    PixF.B := Pix64.B * OneDiv16Bit;
+
+    FloatSetDstPixel(Dst, DstInfo, PixF);
+    Inc(Src, SrcInfo.BytesPerPixel);
+    Inc(Dst, DstInfo.BytesPerPixel);
+  end;
+end;
+
+procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; DstPal: PPalette32);
+begin
+  ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries,
+    GetOption(ImagingColorReductionMask), DstPal);
+end;
+
+procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  Gray: TColor64Rec;
+  Alpha: Word;
+begin
+  // two most common conversions (Gray8->Gray16 nad Gray16->Gray8)
+  // are made separately from general conversions to make them faster
+  if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifGray16) then
+  begin
+    for I := 0 to NumPixels - 1 do
+      PWordArray(Dst)[I] := PByteArray(Src)[I] shl 8;
+  end
+  else
+  begin
+    if (DstInfo.Format = ifGray8) and (SrcInfo.Format = ifGray16) then
+    begin
+      for I := 0 to NumPixels - 1 do
+        PByteArray(Dst)[I] := PWordArray(Src)[I] shr 8;
+    end
+    else
+      for I := 0 to NumPixels - 1 do
+      begin
+        // general grayscale conversion
+        GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha);
+        GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
+        Inc(Src, SrcInfo.BytesPerPixel);
+        Inc(Dst, DstInfo.BytesPerPixel);
+      end;
+  end;
+end;
+
+procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  Pix64: TColor64Rec;
+  Alpha: Word;
+begin
+  // two most common conversions (Gray8->R8G8B8 nad Gray8->A8R8G8B8)
+  // are made separately from general conversions to make them faster
+  if (DstInfo.BytesPerPixel in [3, 4]) and (SrcInfo.Format = ifGray8) then
+    for I := 0 to NumPixels - 1 do
+    begin
+      PColor24Rec(Dst).R := Src^;
+      PColor24Rec(Dst).G := Src^;
+      PColor24Rec(Dst).B := Src^;
+      if DstInfo.HasAlphaChannel then
+        PColor32Rec(Dst).A := $FF;
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end
+  else
+    for I := 0 to NumPixels - 1 do
+    begin
+      GrayGetSrcPixel(Src, SrcInfo, Pix64, Alpha);
+
+      // most significant word of grayscale value is used for
+      // each channel and alpha channel is set to Alpha
+      Pix64.R := Pix64.A;
+      Pix64.G := Pix64.A;
+      Pix64.B := Pix64.A;
+      Pix64.A := Alpha;
+
+      ChannelSetDstPixel(Dst, DstInfo, Pix64);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end;
+end;
+
+procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  Gray: TColor64Rec;
+  PixF: TColorFPRec;
+  Alpha: Word;
+begin
+  for I := 0 to NumPixels - 1 do
+  begin
+    GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha);
+    // most significant word of grayscale value is used for
+    // each channel and alpha channel is set to Alpha
+    // then all is scaled to 0..1
+    PixF.R := Gray.A * OneDiv16Bit;
+    PixF.G := Gray.A * OneDiv16Bit;
+    PixF.B := Gray.A * OneDiv16Bit;
+    PixF.A := Alpha * OneDiv16Bit;
+
+    FloatSetDstPixel(Dst, DstInfo, PixF);
+    Inc(Src, SrcInfo.BytesPerPixel);
+    Inc(Dst, DstInfo.BytesPerPixel);
+  end;
+end;
+
+procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; DstPal: PPalette32);
+var
+  I: LongInt;
+  Idx: LongWord;
+  Gray: TColor64Rec;
+  Alpha, Shift: Word;
+begin
+  FillGrayscalePalette(DstPal, DstInfo.PaletteEntries);
+  Shift := Log2Int(DstInfo.PaletteEntries);
+  // most common conversion (Gray8->Index8)
+  // is made separately from general conversions to make it faster
+  if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifIndex8) then
+    for I := 0 to NumPixels - 1 do
+    begin
+      Dst^ := Src^;
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end
+  else
+    for I := 0 to NumPixels - 1 do
+    begin
+      // gray value is read from src and index to precomputed
+      // grayscale palette is computed and written to dst
+      // (we assume here that there will be no more than 65536 palette
+      // entries in dst format, gray value is shifted so the highest
+      // gray value match the highest possible index in palette)
+      GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha);
+      Idx := Gray.A shr (16 - Shift);
+      IndexSetDstPixel(Dst, DstInfo, Idx);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end;
+end;
+
+procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  PixF: TColorFPRec;
+begin
+  for I := 0 to NumPixels - 1 do
+  begin
+    // general floating point conversion
+    FloatGetSrcPixel(Src, SrcInfo, PixF);
+    FloatSetDstPixel(Dst, DstInfo, PixF);
+    Inc(Src, SrcInfo.BytesPerPixel);
+    Inc(Dst, DstInfo.BytesPerPixel);
+  end;
+end;
+
+procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  Pix64: TColor64Rec;
+  PixF: TColorFPRec;
+begin
+  for I := 0 to NumPixels - 1 do
+  begin
+    FloatGetSrcPixel(Src, SrcInfo, PixF);
+    ClampFloatPixel(PixF);
+
+    // floating point channel values are scaled to 1.0
+    Pix64.A := ClampToWord(Round(PixF.A * 65535));
+    Pix64.R := ClampToWord(Round(PixF.R * 65535));
+    Pix64.G := ClampToWord(Round(PixF.G * 65535));
+    Pix64.B := ClampToWord(Round(PixF.B * 65535));
+
+    ChannelSetDstPixel(Dst, DstInfo, Pix64);
+    Inc(Src, SrcInfo.BytesPerPixel);
+    Inc(Dst, DstInfo.BytesPerPixel);
+  end;
+end;
+
+procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo);
+var
+  I: LongInt;
+  PixF: TColorFPRec;
+  Gray: TColor64Rec;
+  Alpha: Word;
+begin
+  for I := 0 to NumPixels - 1 do
+  begin
+    FloatGetSrcPixel(Src, SrcInfo, PixF);
+    ClampFloatPixel(PixF);
+
+    // alpha is saved from source pixel to Alpha,
+    // Gray value is computed and set to highest word of Pix64 so
+    // Pix64.Color contains grayscale value scaled to 64 bits
+    Alpha := ClampToWord(Round(PixF.A * 65535.0));
+    Gray.A := ClampToWord(Round((GrayConv.R * PixF.R + GrayConv.G * PixF.G +
+      GrayConv.B * PixF.B) * 65535.0));
+
+    GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
+    Inc(Src, SrcInfo.BytesPerPixel);
+    Inc(Dst, DstInfo.BytesPerPixel);
+  end;
+end;
+
+procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; DstPal: PPalette32);
+begin
+  ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries,
+    GetOption(ImagingColorReductionMask), DstPal);
+end;
+
+procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32);
+var
+  I: LongInt;
+begin
+  // there is only one indexed format now, so it is just a copy
+  for I := 0 to NumPixels - 1 do
+  begin
+    Dst^ := Src^;
+    Inc(Src, SrcInfo.BytesPerPixel);
+    Inc(Dst, DstInfo.BytesPerPixel);
+  end;
+  for I := 0 to SrcInfo.PaletteEntries - 1 do
+    DstPal[I] := SrcPal[I];
+end;
+
+procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal: PPalette32);
+var
+  I: LongInt;
+  Pix64: TColor64Rec;
+  Idx: LongWord;
+begin
+  // two most common conversions (Index8->R8G8B8 nad Index8->A8R8G8B8)
+  // are made separately from general conversions to make them faster
+  if (SrcInfo.Format = ifIndex8) and (DstInfo.Format in [ifR8G8B8, ifA8R8G8B8]) then
+    for I := 0 to NumPixels - 1 do
+    begin
+      with PColor24Rec(Dst)^ do
+      begin
+        R := SrcPal[Src^].R;
+        G := SrcPal[Src^].G;
+        B := SrcPal[Src^].B;
+      end;
+      if DstInfo.Format = ifA8R8G8B8 then
+        PColor32Rec(Dst).A := SrcPal[Src^].A;
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end
+  else
+    for I := 0 to NumPixels - 1 do
+    begin
+      // index to palette is read from source and color
+      // is retrieved from palette entry. Color is then
+      // scaled to 16bits and written to dest
+      IndexGetSrcPixel(Src, SrcInfo, Idx);
+      with Pix64 do
+      begin
+        A := SrcPal[Idx].A shl 8;
+        R := SrcPal[Idx].R shl 8;
+        G := SrcPal[Idx].G shl 8;
+        B := SrcPal[Idx].B shl 8;
+      end;
+      ChannelSetDstPixel(Dst, DstInfo, Pix64);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end;
+end;
+
+procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal: PPalette32);
+var
+  I: LongInt;
+  Gray: TColor64Rec;
+  Alpha: Word;
+  Idx: LongWord;
+begin
+  // most common conversion (Index8->Gray8)
+  // is made separately from general conversions to make it faster
+  if (SrcInfo.Format = ifIndex8) and (DstInfo.Format = ifGray8) then
+  begin
+    for I := 0 to NumPixels - 1 do
+    begin
+      Dst^ := Round(GrayConv.R * SrcPal[Src^].R + GrayConv.G * SrcPal[Src^].G +
+        GrayConv.B * SrcPal[Src^].B);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end
+  end
+  else
+    for I := 0 to NumPixels - 1 do
+    begin
+      // index to palette is read from source and color
+      // is retrieved from palette entry. Color is then
+      // transformed to grayscale and assigned to the highest
+      // byte of Gray value
+      IndexGetSrcPixel(Src, SrcInfo, Idx);
+      Alpha := SrcPal[Idx].A shl 8;
+      Gray.A := MulDiv(Round(GrayConv.R * SrcPal[Idx].R + GrayConv.G * SrcPal[Idx].G +
+        GrayConv.B * SrcPal[Idx].B), 65535, 255);
+      GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
+      Inc(Src, SrcInfo.BytesPerPixel);
+      Inc(Dst, DstInfo.BytesPerPixel);
+    end;
+end;
+
+procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
+  DstInfo: PImageFormatInfo; SrcPal: PPalette32);
+var
+  I: LongInt;
+  Idx: LongWord;
+  PixF: TColorFPRec;
+begin
+  for I := 0 to NumPixels - 1 do
+  begin
+    // index to palette is read from source and color
+    // is retrieved from palette entry. Color is then
+    // scaled to 0..1 and written to dest
+    IndexGetSrcPixel(Src, SrcInfo, Idx);
+    with PixF do
+    begin
+      A := SrcPal[Idx].A * OneDiv8Bit;
+      R := SrcPal[Idx].R * OneDiv8Bit;
+      G := SrcPal[Idx].G * OneDiv8Bit;
+      B := SrcPal[Idx].B * OneDiv8Bit;
+    end;
+    FloatSetDstPixel(Dst, DstInfo, PixF);
+    Inc(Src, SrcInfo.BytesPerPixel);
+    Inc(Dst, DstInfo.BytesPerPixel);
+  end;
+end;
+
+
+{ Special formats conversion functions }
+
+type
+  // DXT RGB color block
+  TDXTColorBlock = packed record
+    Color0, Color1: Word;
+    Mask: LongWord;
+  end;
+  PDXTColorBlock = ^TDXTColorBlock;
+
+  // DXT explicit alpha for a block
+  TDXTAlphaBlockExp = packed record
+    Alphas: array[0..3] of Word;
+  end;
+  PDXTAlphaBlockExp = ^TDXTAlphaBlockExp;
+
+  // DXT interpolated alpha for a block
+  TDXTAlphaBlockInt = packed record
+    Alphas: array[0..7] of Byte;
+  end;
+  PDXTAlphaBlockInt = ^TDXTAlphaBlockInt;
+
+  TPixelInfo = record
+    Color: Word;
+    Alpha: Byte;
+    Orig: TColor32Rec;
+  end;
+
+  TPixelBlock = array[0..15] of TPixelInfo;
+
+function DecodeCol(Color: Word): TColor32Rec;
+{$IFDEF USE_INLINE} inline; {$ENDIF}
+begin
+  Result.A := $FF;
+{  Result.R := ((Color and $F800) shr 11) shl 3;
+  Result.G := ((Color and $07E0) shr 5) shl 2;
+  Result.B := (Color and $001F) shl 3;}
+  // this color expansion is slower but gives better results
+  Result.R := (Color shr 11) * 255 div 31;
+  Result.G := ((Color shr 5) and $3F) * 255 div 63;
+  Result.B := (Color and $1F) * 255 div 31;
+end;
+
+procedure DecodeDXT1(SrcBits, DestBits: PByte; Width, Height: LongInt);
+var
+  Sel, X, Y, I, J, K: LongInt;
+  Block: TDXTColorBlock;
+  Colors: array[0..3] of TColor32Rec;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      Block := PDXTColorBlock(SrcBits)^;
+      Inc(SrcBits, SizeOf(Block));
+      // we read and decode endpoint colors
+      Colors[0] := DecodeCol(Block.Color0);
+      Colors[1] := DecodeCol(Block.Color1);
+      // and interpolate between them
+      if Block.Color0 > Block.Color1 then
+      begin
+        // interpolation for block without alpha
+        Colors[2].A := $FF;
+        Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
+        Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
+        Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
+        Colors[3].A := $FF;
+        Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
+        Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
+        Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
+      end
+      else
+      begin
+        // interpolation for block with alpha
+        Colors[2].A := $FF;
+        Colors[2].R := (Colors[0].R + Colors[1].R) shr 1;
+        Colors[2].G := (Colors[0].G + Colors[1].G) shr 1;
+        Colors[2].B := (Colors[0].B + Colors[1].B) shr 1;
+        Colors[3].A := 0;
+        Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
+        Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
+        Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
+      end;
+
+      // we distribute the dxt block colors across the 4x4 block of the
+      // destination image accroding to the dxt block mask
+      K := 0;
+      for J := 0 to 3 do
+        for I := 0 to 3 do
+        begin
+          Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1);
+          if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then
+            PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] :=
+              Colors[Sel];
+          Inc(K);
+        end;
+  end;
+end;
+
+procedure DecodeDXT3(SrcBits, DestBits: PByte; Width, Height: LongInt);
+var
+  Sel, X, Y, I, J, K: LongInt;
+  Block: TDXTColorBlock;
+  AlphaBlock: TDXTAlphaBlockExp;
+  Colors: array[0..3] of TColor32Rec;
+  AWord: Word;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      AlphaBlock := PDXTAlphaBlockExp(SrcBits)^;
+      Inc(SrcBits, SizeOf(AlphaBlock));
+      Block := PDXTColorBlock(SrcBits)^;
+      Inc(SrcBits, SizeOf(Block));
+      // we read and decode endpoint colors
+      Colors[0] := DecodeCol(Block.Color0);
+      Colors[1] := DecodeCol(Block.Color1);
+      // and interpolate between them
+      Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
+      Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
+      Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
+      Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
+      Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
+      Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
+
+      // we distribute the dxt block colors and alphas
+      // across the 4x4 block of the destination image
+      // accroding to the dxt block mask and alpha block
+      K := 0;
+      for J := 0 to 3 do
+      begin
+        AWord := AlphaBlock.Alphas[J];
+        for I := 0 to 3 do
+        begin
+          Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1);
+          if (X shl 2 + I < Width) and (Y shl 2 + J < Height) then
+          begin
+            Colors[Sel].A := AWord and $0F;
+            Colors[Sel].A := Colors[Sel].A or (Colors[Sel].A shl 4);
+            PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] :=
+              Colors[Sel];
+          end;
+          Inc(K);
+          AWord := AWord shr 4;
+        end;
+      end;
+  end;
+end;
+
+procedure GetInterpolatedAlphas(var AlphaBlock: TDXTAlphaBlockInt);
+begin
+  with AlphaBlock do
+  if Alphas[0] > Alphas[1] then
+  begin
+    // Interpolation of six alphas
+    Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7;
+    Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7;
+    Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7;
+    Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7;
+    Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7;
+    Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7;
+  end
+  else
+  begin
+    // Interpolation of four alphas, two alphas are set directly
+    Alphas[2] := (4 * Alphas[0] + 1 * Alphas[1] + 2) div 5;
+    Alphas[3] := (3 * Alphas[0] + 2 * Alphas[1] + 2) div 5;
+    Alphas[4] := (2 * Alphas[0] + 3 * Alphas[1] + 2) div 5;
+    Alphas[5] := (1 * Alphas[0] + 4 * Alphas[1] + 2) div 5;
+    Alphas[6] := 0;
+    Alphas[7] := $FF;
+  end;
+end;
+
+procedure DecodeDXT5(SrcBits, DestBits: PByte; Width, Height: LongInt);
+var
+  Sel, X, Y, I, J, K: LongInt;
+  Block: TDXTColorBlock;
+  AlphaBlock: TDXTAlphaBlockInt;
+  Colors: array[0..3] of TColor32Rec;
+  AMask: array[0..1] of LongWord;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      AlphaBlock := PDXTAlphaBlockInt(SrcBits)^;
+      Inc(SrcBits, SizeOf(AlphaBlock));
+      Block := PDXTColorBlock(SrcBits)^;
+      Inc(SrcBits, SizeOf(Block));
+      // we read and decode endpoint colors
+      Colors[0] := DecodeCol(Block.Color0);
+      Colors[1] := DecodeCol(Block.Color1);
+      // and interpolate between them
+      Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
+      Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
+      Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
+      Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
+      Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
+      Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
+      // 6 bit alpha mask is copied into two long words for
+      // easier usage
+      AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF;
+      AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF;
+      // alpha interpolation between two endpoint alphas
+      GetInterpolatedAlphas(AlphaBlock);
+
+      // we distribute the dxt block colors and alphas
+      // across the 4x4 block of the destination image
+      // accroding to the dxt block mask and alpha block mask
+      K := 0;
+      for J := 0 to 3 do
+        for I := 0 to 3 do
+        begin
+          Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1);
+          if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then
+          begin
+            Colors[Sel].A := AlphaBlock.Alphas[AMask[J shr 1] and 7];
+            PPalette32(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] :=
+              Colors[Sel];
+          end;
+          Inc(K);
+          AMask[J shr 1] := AMask[J shr 1] shr 3;
+        end;
+  end;
+end;
+
+procedure GetBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos,
+  Width, Height: LongInt);
+var
+  X, Y, I: LongInt;
+  Src: PColor32Rec;
+begin
+  I := 0;
+  // 4x4 pixel block is filled with information about every
+  // pixel in the block: alpha, original color, 565 color
+  for Y := 0 to 3 do
+    for X := 0 to 3 do
+    begin
+      Src := @PPalette32(SrcBits)[(YPos shl 2 + Y) * Width + XPos shl 2 + X];
+      Block[I].Color := ((Src.R shr 3) shl 11) or ((Src.G shr 2) shl 5) or
+        (Src.B shr 3);
+      Block[I].Alpha := Src.A;
+      Block[I].Orig := Src^;
+      Inc(I);
+    end;
+end;
+
+function ColorDistance(const C1, C2: TColor32Rec): LongInt;
+{$IFDEF USE_INLINE} inline;{$ENDIF}
+begin
+  Result := (C1.R - C2.R) * (C1.R - C2.R) +
+    (C1.G - C2.G) * (C1.G - C2.G) + (C1.B - C2.B) * (C1.B - C2.B);
+end;
+
+procedure GetEndpoints(const Block: TPixelBlock; var Ep0, Ep1: Word);
+var
+  I, J, Farthest, Dist: LongInt;
+  Colors: array[0..15] of TColor32Rec;
+begin
+  // we choose two colors from the pixel block which has the
+  // largest distance between them
+  for I := 0 to 15 do
+    Colors[I] := Block[I].Orig;
+  Farthest := -1;
+  for I := 0 to 15 do
+    for J := I + 1 to 15 do
+    begin
+      Dist := ColorDistance(Colors[I], Colors[J]);
+      if Dist > Farthest then
+      begin
+        Farthest := Dist;
+        Ep0 := Block[I].Color;
+        Ep1 := Block[J].Color;
+      end;
+    end;
+end;
+
+procedure GetAlphaEndpoints(const Block: TPixelBlock; var Min, Max: Byte);
+var
+  I: LongInt;
+begin
+  Min := 255;
+  Max := 0;
+  // we choose the lowest and the highest alpha values
+  for I := 0 to 15 do
+  begin
+    if Block[I].Alpha < Min then
+      Min := Block[I].Alpha;
+    if Block[I].Alpha > Max then
+      Max := Block[I].Alpha;
+  end;
+end;
+
+procedure FixEndpoints(var Ep0, Ep1: Word; HasAlpha: Boolean);
+var
+  Temp: Word;
+begin
+  // if dxt block has alpha information, Ep0 must be smaller
+  // than Ep1, if the  block has no alpha Ep1 must be smaller
+  if HasAlpha then
+  begin
+    if Ep0 > Ep1 then
+    begin
+      Temp := Ep0;
+      Ep0 := Ep1;
+      Ep1 := Temp;
+    end;
+  end
+  else
+    if Ep0 < Ep1 then
+    begin
+      Temp := Ep0;
+      Ep0 := Ep1;
+      Ep1 := Temp;
+    end;
+end;
+
+function GetColorMask(Ep0, Ep1: Word; NumCols: LongInt;
+  const Block: TPixelBlock): LongWord;
+var
+  I, J, Closest, Dist: LongInt;
+  Colors: array[0..3] of TColor32Rec;
+  Mask: array[0..15] of Byte;
+begin
+  FillChar(Mask, sizeof(Mask), 0);
+  // we decode endpoint colors
+  Colors[0] := DecodeCol(Ep0);
+  Colors[1] := DecodeCol(Ep1);
+  // and interpolate colors between (3 for DXT1 with alpha, 4 for the others)
+  if NumCols = 3 then
+  begin
+    Colors[2].R := (Colors[0].R + Colors[1].R) shr 1;
+    Colors[2].G := (Colors[0].G + Colors[1].G) shr 1;
+    Colors[2].B := (Colors[0].B + Colors[1].B) shr 1;
+    Colors[3].R := (Colors[0].R + Colors[1].R) shr 1;
+    Colors[3].G := (Colors[0].G + Colors[1].G) shr 1;
+    Colors[3].B := (Colors[0].B + Colors[1].B) shr 1;
+  end
+  else
+  begin
+    Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3;
+    Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3;
+    Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3;
+    Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3;
+    Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3;
+    Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3;
+  end;
+
+  for I := 0 to 15 do
+  begin
+    // this is only for DXT1 with alpha
+    if (Block[I].Alpha < 128) and (NumCols = 3) then
+    begin
+      Mask[I] := 3;
+      Continue;
+    end;
+    // for each of the 16 input pixels the nearest color in the
+    // 4 dxt colors is found
+    Closest := MaxInt;
+    for J := 0 to NumCols - 1 do
+    begin
+      Dist := ColorDistance(Block[I].Orig, Colors[J]);
+      if Dist < Closest then
+      begin
+        Closest := Dist;
+        Mask[I] := J;
+      end;
+    end;
+  end;
+
+  Result := 0;
+  for I := 0 to 15 do
+    Result := Result or (Mask[I] shl (I shl 1));
+end;
+
+procedure GetAlphaMask(Ep0, Ep1: Byte; var Block: TPixelBlock; Mask: PByteArray);
+var
+  Alphas: array[0..7] of Byte;
+  M: array[0..15] of Byte;
+  I, J, Closest, Dist: LongInt;
+begin
+  FillChar(M, sizeof(M), 0);
+  Alphas[0] := Ep0;
+  Alphas[1] := Ep1;
+  // interpolation between two given alpha endpoints
+  // (I use 6 interpolated values mode)
+  Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7;
+  Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7;
+  Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7;
+  Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7;
+  Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7;
+  Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7;
+
+  // the closest interpolated values for each of the input alpha
+  // is found
+  for I := 0 to 15 do
+  begin
+    Closest := MaxInt;
+    for J := 0 to 7 do
+    begin
+      Dist := Abs(Alphas[J] - Block[I].Alpha);
+      if Dist < Closest then
+      begin
+        Closest := Dist;
+        M[I] := J;
+      end;
+    end;
+  end;
+
+  Mask[0] := M[0] or (M[1] shl 3) or ((M[2] and 3) shl 6);
+  Mask[1] := ((M[2] and 4) shr 2) or (M[3] shl 1) or (M[4] shl 4) or
+    ((M[5] and 1) shl 7);
+  Mask[2] := ((M[5] and 6) shr 1) or (M[6] shl 2) or (M[7] shl 5);
+  Mask[3] := M[8] or (M[9] shl 3) or ((M[10] and 3) shl 6);
+  Mask[4] := ((M[10] and 4) shr 2) or (M[11] shl 1) or (M[12] shl 4) or
+   ((M[13] and 1) shl 7);
+  Mask[5] := ((M[13] and 6) shr 1) or (M[14] shl 2) or (M[15] shl 5);
+end;
+
+
+procedure EncodeDXT1(SrcBits: PByte; DestBits: PByte; Width, Height: LongInt);
+var
+  X, Y, I: LongInt;
+  HasAlpha: Boolean;
+  Block: TDXTColorBlock;
+  Pixels: TPixelBlock;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      GetBlock(Pixels, SrcBits, X, Y, Width, Height);
+      HasAlpha := False;
+      for I := 0 to 15 do
+        if Pixels[I].Alpha < 128 then
+        begin
+          HasAlpha := True;
+          Break;
+        end;
+      GetEndpoints(Pixels, Block.Color0, Block.Color1);
+      FixEndpoints(Block.Color0, Block.Color1, HasAlpha);
+      if HasAlpha then
+        Block.Mask := GetColorMask(Block.Color0, Block.Color1, 3, Pixels)
+      else
+        Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels);
+      PDXTColorBlock(DestBits)^ := Block;
+      Inc(DestBits, SizeOf(Block));
+    end;
+end;
+
+procedure EncodeDXT3(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt);
+var
+  X, Y, I: LongInt;
+  Block: TDXTColorBlock;
+  AlphaBlock: TDXTAlphaBlockExp;
+  Pixels: TPixelBlock;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      GetBlock(Pixels, SrcBits, X, Y, Width, Height);
+      for I := 0 to 7 do
+        PByteArray(@AlphaBlock.Alphas)[I] :=
+          (Pixels[I shl 1].Alpha shr 4) or ((Pixels[I shl 1 + 1].Alpha shr 4) shl 4);
+      GetEndpoints(Pixels, Block.Color0, Block.Color1);
+      FixEndpoints(Block.Color0, Block.Color1, False);
+      Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels);
+      PDXTAlphaBlockExp(DestBits)^ := AlphaBlock;
+      Inc(DestBits, SizeOf(AlphaBlock));
+      PDXTColorBlock(DestBits)^ := Block;
+      Inc(DestBits, SizeOf(Block));
+    end;
+end;
+
+procedure EncodeDXT5(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt);
+var
+  X, Y: LongInt;
+  Block: TDXTColorBlock;
+  AlphaBlock: TDXTAlphaBlockInt;
+  Pixels: TPixelBlock;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      GetBlock(Pixels, SrcBits, X, Y, Width, Height);
+      GetEndpoints(Pixels, Block.Color0, Block.Color1);
+      FixEndpoints(Block.Color0, Block.Color1, False);
+      Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels);
+      GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
+      GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
+        PByteArray(@AlphaBlock.Alphas[2]));
+      PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
+      Inc(DestBits, SizeOf(AlphaBlock));
+      PDXTColorBlock(DestBits)^ := Block;
+      Inc(DestBits, SizeOf(Block));
+    end;
+end;
+
+type
+  TBTCBlock = packed record
+    MLower, MUpper: Byte;
+    BitField: Word;
+  end;
+  PBTCBlock = ^TBTCBlock;
+
+procedure EncodeBTC(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer);
+var
+  X, Y, I, J: Integer;
+  Block: TBTCBlock;
+  M, MLower, MUpper, K: Integer;
+  Pixels: array[0..15] of Byte;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      M := 0;
+      MLower := 0;
+      MUpper := 0;
+      FillChar(Block, SizeOf(Block), 0);
+      K := 0;
+
+      // Store 4x4 pixels and compute average, lower, and upper intensity levels
+      for I := 0 to 3 do
+        for J := 0 to 3 do
+        begin
+          Pixels[K] := PByteArray(SrcBits)[(Y shl 2 + I) * Width + X shl 2 + J];
+          Inc(M, Pixels[K]);
+          Inc(K);
+        end;
+
+      M := M div 16;
+      K := 0;
+
+      // Now compute upper and lower levels, number of upper pixels,
+      // and update bit field (1 when pixel is above avg. level M)
+      for I := 0 to 15 do
+      begin
+        if Pixels[I] > M then
+        begin
+          Inc(MUpper, Pixels[I]);
+          Inc(K);
+          Block.BitField := Block.BitField or (1 shl I);
+        end
+        else
+          Inc(MLower, Pixels[I]);
+      end;
+
+      // Scale levels and save them to block
+      if K > 0 then
+        Block.MUpper := ClampToByte(MUpper div K)
+      else
+        Block.MUpper := 0;
+      Block.MLower := ClampToByte(MLower div (16 - K));
+
+      // Finally save block to dest data
+      PBTCBlock(DestBits)^ := Block;
+      Inc(DestBits, SizeOf(Block));
+    end;
+end;
+
+procedure GetOneChannelBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos,
+  Width, Height, BytesPP, ChannelIdx: Integer);
+var
+  X, Y, I: Integer;
+  Src: PByte;
+begin
+  I := 0;
+  // 4x4 pixel block is filled with information about every pixel in the block,
+  // but only one channel value is stored in Alpha field
+  for Y := 0 to 3 do
+    for X := 0 to 3 do
+    begin
+      Src := @PByteArray(SrcBits)[(YPos * 4 + Y) * Width * BytesPP +
+        (XPos * 4 + X) * BytesPP + ChannelIdx];
+      Block[I].Alpha := Src^;
+      Inc(I);
+    end;
+end;
+
+procedure EncodeATI1N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer);
+var
+  X, Y: Integer;
+  AlphaBlock: TDXTAlphaBlockInt;
+  Pixels: TPixelBlock;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      // Encode one channel
+      GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 1, 0);
+      GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
+      GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
+        PByteArray(@AlphaBlock.Alphas[2]));
+      PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
+      Inc(DestBits, SizeOf(AlphaBlock));
+    end;
+end;
+
+procedure EncodeATI2N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer);
+var
+  X, Y: Integer;
+  AlphaBlock: TDXTAlphaBlockInt;
+  Pixels: TPixelBlock;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      // Encode Red/X channel
+      GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelRed);
+      GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
+      GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
+        PByteArray(@AlphaBlock.Alphas[2]));
+      PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
+      Inc(DestBits, SizeOf(AlphaBlock));
+      // Encode Green/Y channel
+      GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelGreen);
+      GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]);
+      GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels,
+        PByteArray(@AlphaBlock.Alphas[2]));
+      PDXTAlphaBlockInt(DestBits)^ := AlphaBlock;
+      Inc(DestBits, SizeOf(AlphaBlock));
+    end;
+end;
+
+procedure EncodeBinary(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer);
+var
+  Src: PByte absolute SrcBits;
+  Bitmap: PByteArray absolute DestBits;
+  X, Y, WidthBytes: Integer;
+  PixelTresholded, Treshold: Byte;
+begin
+  Treshold := ClampToByte(GetOption(ImagingBinaryTreshold));
+  WidthBytes := (Width + 7) div 8;
+
+  for Y := 0 to Height - 1 do
+    for X := 0 to Width - 1 do
+    begin
+      if Src^ > Treshold then
+        PixelTresholded := 255
+      else
+        PixelTresholded := 0;
+
+      Bitmap[Y * WidthBytes + X div 8] := Bitmap[Y * WidthBytes + X div 8] or // OR current value of byte with following:
+        (PixelTresholded and 1)  // To make 1 from 255, 0 remains 0
+        shl (7 - (X mod 8));  // Put current bit to proper place in byte
+
+      Inc(Src);
+    end;
+end;
+
+procedure DecodeBTC(SrcBits, DestBits: PByte; Width, Height: Integer);
+var
+  X, Y, I, J, K: Integer;
+  Block: TBTCBlock;
+  Dest: PByte;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      Block := PBTCBlock(SrcBits)^;
+      Inc(SrcBits, SizeOf(Block));
+      K := 0;
+
+      // Just write MUpper when there is '1' in bit field and MLower
+      // when there is '0'
+      for I := 0 to 3 do
+        for J := 0 to 3 do
+        begin
+          Dest := @PByteArray(DestBits)[(Y shl 2 + I) * Width + X shl 2 + J];
+          if Block.BitField and (1 shl K) <> 0 then
+            Dest^ := Block.MUpper
+          else
+            Dest^ := Block.MLower;
+          Inc(K);
+        end;
+    end;
+end;
+
+procedure DecodeATI1N(SrcBits, DestBits: PByte; Width, Height: Integer);
+var
+  X, Y, I, J: Integer;
+  AlphaBlock: TDXTAlphaBlockInt;
+  AMask: array[0..1] of LongWord;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      AlphaBlock := PDXTAlphaBlockInt(SrcBits)^;
+      Inc(SrcBits, SizeOf(AlphaBlock));
+      // 6 bit alpha mask is copied into two long words for
+      // easier usage
+      AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF;
+      AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF;
+      // alpha interpolation between two endpoint alphas
+      GetInterpolatedAlphas(AlphaBlock);
+
+      // we distribute the dxt block alphas
+      // across the 4x4 block of the destination image
+      for J := 0 to 3 do
+       for I := 0 to 3 do
+       begin
+         PByteArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] :=
+           AlphaBlock.Alphas[AMask[J shr 1] and 7];
+         AMask[J shr 1] := AMask[J shr 1] shr 3;
+       end;
+  end;
+end;
+
+procedure DecodeATI2N(SrcBits, DestBits: PByte; Width, Height: Integer);
+var
+  X, Y, I, J: Integer;
+  Color: TColor32Rec;
+  AlphaBlock1, AlphaBlock2: TDXTAlphaBlockInt;
+  AMask1: array[0..1] of LongWord;
+  AMask2: array[0..1] of LongWord;
+begin
+  for Y := 0 to Height div 4 - 1 do
+    for X := 0 to Width div 4 - 1 do
+    begin
+      // Read the first alpha block and get masks
+      AlphaBlock1 := PDXTAlphaBlockInt(SrcBits)^;
+      Inc(SrcBits, SizeOf(AlphaBlock1));
+      AMask1[0] := PLongWord(@AlphaBlock1.Alphas[2])^ and $00FFFFFF;
+      AMask1[1] := PLongWord(@AlphaBlock1.Alphas[5])^ and $00FFFFFF;
+      // Read the secind alpha block and get masks
+      AlphaBlock2 := PDXTAlphaBlockInt(SrcBits)^;
+      Inc(SrcBits, SizeOf(AlphaBlock2));
+      AMask2[0] := PLongWord(@AlphaBlock2.Alphas[2])^ and $00FFFFFF;
+      AMask2[1] := PLongWord(@AlphaBlock2.Alphas[5])^ and $00FFFFFF;
+      // alpha interpolation between two endpoint alphas
+      GetInterpolatedAlphas(AlphaBlock1);
+      GetInterpolatedAlphas(AlphaBlock2);
+
+      Color.A := $FF;
+      Color.B := 0;
+
+      // Distribute alpha block values across 4x4 pixel block,
+      // first alpha block represents Red channel, second is Green.
+      for J := 0 to 3 do
+       for I := 0 to 3 do
+       begin
+         Color.R := AlphaBlock1.Alphas[AMask1[J shr 1] and 7];
+         Color.G := AlphaBlock2.Alphas[AMask2[J shr 1] and 7];
+         PColor32RecArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := Color;
+         AMask1[J shr 1] := AMask1[J shr 1] shr 3;
+         AMask2[J shr 1] := AMask2[J shr 1] shr 3;
+       end;
+  end;
+end;
+
+procedure DecodeBinary(SrcBits, DestBits: PByte; Width, Height: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
+begin
+  Convert1To8(SrcBits, DestBits, Width, Height, (Width + 7) div 8, True);
+end;
+
+procedure SpecialToUnSpecial(const SrcImage: TImageData; DestBits: Pointer;
+  SpecialFormat: TImageFormat);
+begin
+  case SpecialFormat of
+    ifDXT1: DecodeDXT1(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
+    ifDXT3: DecodeDXT3(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
+    ifDXT5: DecodeDXT5(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
+    ifBTC:  DecodeBTC (SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
+    ifATI1N: DecodeATI1N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
+    ifATI2N: DecodeATI2N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
+    ifBinary: DecodeBinary(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height);
+  end;
+end;
+
+procedure UnSpecialToSpecial(SrcBits: Pointer; const DestImage: TImageData;
+  SpecialFormat: TImageFormat);
+begin
+  case SpecialFormat of
+    ifDXT1: EncodeDXT1(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
+    ifDXT3: EncodeDXT3(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
+    ifDXT5: EncodeDXT5(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
+    ifBTC:  EncodeBTC (SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
+    ifATI1N: EncodeATI1N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
+    ifATI2N: EncodeATI2N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
+    ifBinary: EncodeBinary(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height);
+  end;
+end;
+
+procedure ConvertSpecial(var Image: TImageData;
+  SrcInfo, DstInfo: PImageFormatInfo);
+var
+  WorkImage: TImageData;
+
+  procedure CheckSize(var Img: TImageData; Info: PImageFormatInfo);
+  var
+    Width, Height: Integer;
+  begin
+    Width := Img.Width;
+    Height := Img.Height;
+    DstInfo.CheckDimensions(Info.Format, Width, Height);
+    ResizeImage(Img, Width, Height, rfNearest);
+  end;
+
+begin
+  if SrcInfo.IsSpecial and DstInfo.IsSpecial then
+  begin
+    // Convert source to nearest 'normal' format
+    InitImage(WorkImage);
+    NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage);
+    SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format);
+    FreeImage(Image);
+    // Make sure output of SpecialToUnSpecial is the same as input of
+    // UnSpecialToSpecial
+    if SrcInfo.SpecialNearestFormat <> DstInfo.SpecialNearestFormat then
+      ConvertImage(WorkImage, DstInfo.SpecialNearestFormat);
+    // Convert work image to dest special format
+    CheckSize(WorkImage, DstInfo);
+    NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image);
+    UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format);
+    FreeImage(WorkImage);
+  end
+  else if SrcInfo.IsSpecial and not DstInfo.IsSpecial then
+  begin
+    // Convert source to nearest 'normal' format
+    InitImage(WorkImage);
+    NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage);
+    SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format);
+    FreeImage(Image);
+    // Now convert to dest format
+    ConvertImage(WorkImage, DstInfo.Format);
+    Image := WorkImage;
+  end
+  else if not SrcInfo.IsSpecial and DstInfo.IsSpecial then
+  begin
+    // Convert source to nearest format
+    WorkImage := Image;
+    ConvertImage(WorkImage, DstInfo.SpecialNearestFormat);
+    // Now convert from nearest to dest
+    CheckSize(WorkImage, DstInfo);
+    InitImage(Image);
+    NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image);
+    UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format);
+    FreeImage(WorkImage);
+  end;
+end;
+
+function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
+begin
+  if FInfos[Format] <> nil then
+    Result := Width * Height * FInfos[Format].BytesPerPixel
+  else
+    Result := 0;
+end;
+
+procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt);
+begin
+end;
+
+function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
+begin
+  // DXT can be used only for images with dimensions that are
+  // multiples of four
+  CheckDXTDimensions(Format, Width, Height);
+  Result := Width * Height;
+  if Format in [ifDXT1, ifATI1N] then
+    Result := Result div 2;
+end;
+
+procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt);
+begin
+  // DXT image dimensions must be multiples of four
+  Width := (Width + 3) and not 3; // div 4 * 4;
+  Height := (Height + 3) and not 3; // div 4 * 4;
+end;
+
+function GetBTCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
+begin
+  // BTC can be used only for images with dimensions that are
+  // multiples of four
+  CheckDXTDimensions(Format, Width, Height);
+  Result := Width * Height div 4; // 2bits/pixel
+end;
+
+function GetBCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
+begin
+  raise ENotImplemented.Create();
+end;
+
+procedure CheckBCDimensions(Format: TImageFormat; var Width, Height: LongInt);
+begin
+  raise ENotImplemented.Create();
+end;
+
+function GetBinaryPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt;
+begin
+  // Binary images are aligned on BYTE boundary
+  Result := ((Width + 7) div 8) * Height; // 1bit/pixel
+end;
+
+{ Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo }
+
+function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec;
+begin
+  Result.Color := PLongWord(Bits)^;
+end;
+
+procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec);
+begin
+  PLongWord(Bits)^ := Color.Color;
+end;
+
+function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
+begin
+  Result.A := PColor32Rec(Bits).A * OneDiv8Bit;
+  Result.R := PColor32Rec(Bits).R * OneDiv8Bit;
+  Result.G := PColor32Rec(Bits).G * OneDiv8Bit;
+  Result.B := PColor32Rec(Bits).B * OneDiv8Bit;
+end;
+
+procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
+begin
+  PColor32Rec(Bits).A := ClampToByte(Round(Color.A * 255.0));
+  PColor32Rec(Bits).R := ClampToByte(Round(Color.R * 255.0));
+  PColor32Rec(Bits).G := ClampToByte(Round(Color.G * 255.0));
+  PColor32Rec(Bits).B := ClampToByte(Round(Color.B * 255.0));
+end;
+
+function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec;
+begin
+  Result.A := 0;
+  Result.R := 0;
+  Result.G := 0;
+  Result.B := 0;
+  case Info.Format of
+    ifR8G8B8, ifX8R8G8B8:
+      begin
+        Result.A := $FF;
+        PColor24Rec(@Result)^ := PColor24Rec(Bits)^;
+      end;
+    ifGray8, ifA8Gray8:
+      begin
+        if Info.HasAlphaChannel then
+          Result.A := PWordRec(Bits).High
+        else
+          Result.A := $FF;
+        Result.R := PWordRec(Bits).Low;
+        Result.G := PWordRec(Bits).Low;
+        Result.B := PWordRec(Bits).Low;
+      end;
+  end;
+end;
+
+procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec);
+begin
+  case Info.Format of
+    ifR8G8B8, ifX8R8G8B8:
+      begin
+        PColor24Rec(Bits)^ := PColor24Rec(@Color)^;
+      end;
+    ifGray8, ifA8Gray8:
+      begin
+        if Info.HasAlphaChannel then
+          PWordRec(Bits).High := Color.A;
+        PWordRec(Bits).Low := Round(GrayConv.R * Color.R + GrayConv.G * Color.G +
+          GrayConv.B * Color.B);
+      end;
+  end;
+end;
+
+function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
+begin
+  Result.A := 0;
+  Result.R := 0;
+  Result.G := 0;
+  Result.B := 0;
+  case Info.Format of
+    ifR8G8B8, ifX8R8G8B8:
+      begin
+        Result.A := 1.0;
+        Result.R := PColor24Rec(Bits).R * OneDiv8Bit;
+        Result.G := PColor24Rec(Bits).G * OneDiv8Bit;
+        Result.B := PColor24Rec(Bits).B * OneDiv8Bit;
+      end;
+    ifGray8, ifA8Gray8:
+      begin
+        if Info.HasAlphaChannel then
+          Result.A := PWordRec(Bits).High * OneDiv8Bit
+        else
+          Result.A := 1.0;
+        Result.R := PWordRec(Bits).Low * OneDiv8Bit;
+        Result.G := PWordRec(Bits).Low * OneDiv8Bit;
+        Result.B := PWordRec(Bits).Low * OneDiv8Bit;
+      end;
+  end;
+end;
+
+procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
+begin
+  case Info.Format of
+    ifR8G8B8, ifX8R8G8B8:
+      begin
+        PColor24Rec(Bits).R := ClampToByte(Round(Color.R * 255.0));
+        PColor24Rec(Bits).G := ClampToByte(Round(Color.G * 255.0));
+        PColor24Rec(Bits).B := ClampToByte(Round(Color.B * 255.0));
+      end;
+    ifGray8, ifA8Gray8:
+      begin
+        if Info.HasAlphaChannel then
+          PWordRec(Bits).High := ClampToByte(Round(Color.A * 255.0));
+        PWordRec(Bits).Low := ClampToByte(Round((GrayConv.R * Color.R + GrayConv.G * Color.G +
+          GrayConv.B * Color.B) * 255.0));
+      end;
+  end;
+end;
+
+function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec;
+begin
+  case Info.Format of
+    ifA32R32G32B32F, ifA32B32G32R32F:
+      begin
+        Result := PColorFPRec(Bits)^;
+      end;
+    ifR32G32B32F, ifB32G32R32F:
+      begin
+        Result.A := 1.0;
+        Result.Color96Rec := PColor96FPRec(Bits)^;
+      end;
+    ifR32F:
+      begin
+        Result.A := 1.0;
+        Result.R := PSingle(Bits)^;
+        Result.G := 0.0;
+        Result.B := 0.0;
+      end;
+  end;
+  if Info.IsRBSwapped then
+    SwapValues(Result.R, Result.B);
+end;
+
+procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec);
+begin
+  case Info.Format of
+    ifA32R32G32B32F, ifA32B32G32R32F:
+      begin
+        PColorFPRec(Bits)^ := Color;
+      end;
+    ifR32G32B32F, ifB32G32R32F:
+      begin
+        PColor96FPRec(Bits)^ := Color.Color96Rec;
+      end;
+    ifR32F:
+      begin
+        PSingle(Bits)^ := Color.R;
+      end;
+  end;
+  if Info.IsRBSwapped then
+    SwapValues(PColor96FPRec(Bits).R, PColor96FPRec(Bits).B);
+end;
+
+initialization
+  // Initialize default sampling filter function pointers and radii
+  SamplingFilterFunctions[sfNearest]    := FilterNearest;
+  SamplingFilterFunctions[sfLinear]     := FilterLinear;
+  SamplingFilterFunctions[sfCosine]     := FilterCosine;
+  SamplingFilterFunctions[sfHermite]    := FilterHermite;
+  SamplingFilterFunctions[sfQuadratic]  := FilterQuadratic;
+  SamplingFilterFunctions[sfGaussian]   := FilterGaussian;
+  SamplingFilterFunctions[sfSpline]     := FilterSpline;
+  SamplingFilterFunctions[sfLanczos]    := FilterLanczos;
+  SamplingFilterFunctions[sfMitchell]   := FilterMitchell;
+  SamplingFilterFunctions[sfCatmullRom] := FilterCatmullRom;
+  SamplingFilterRadii[sfNearest]    := 1.0;
+  SamplingFilterRadii[sfLinear]     := 1.0;
+  SamplingFilterRadii[sfCosine]     := 1.0;
+  SamplingFilterRadii[sfHermite]    := 1.0;
+  SamplingFilterRadii[sfQuadratic]  := 1.5;
+  SamplingFilterRadii[sfGaussian]   := 1.25;
+  SamplingFilterRadii[sfSpline]     := 2.0;
+  SamplingFilterRadii[sfLanczos]    := 3.0;
+  SamplingFilterRadii[sfMitchell]   := 2.0;
+  SamplingFilterRadii[sfCatmullRom] := 2.0;
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77 Changes/Bug Fixes -------------------------------------
+    - NOT YET: Added support for Passtrough image data formats.
+    - Added ConvertToPixel32 helper function.
+
+  -- 0.26.5 Changes/Bug Fixes -----------------------------------
+    - Removed optimized codepatch for few data formats from StretchResample
+      function. It was quite buggy and not so much faster anyway.
+    - Added PaletteHasAlpha function.
+    - Added support functions for ifBinary data format.
+    - Added optional pixel scaling to Convert1To8, Convert2To8,
+      abd Convert4To8 functions.
+
+  -- 0.26.3 Changes/Bug Fixes -----------------------------------
+    - Filtered resampling ~10% faster now.
+    - Fixed DXT3 alpha encoding.
+    - ifIndex8 format now has HasAlphaChannel=True.
+
+  -- 0.25.0 Changes/Bug Fixes -----------------------------------
+    - Made some resampling stuff public so that it can be used in canvas class.
+    - Added some color constructors.
+    - Added VisualizePalette helper function.
+    - Fixed ConvertSpecial, not very readable before and error when
+      converting special->special.
+
+  -- 0.24.3 Changes/Bug Fixes -----------------------------------
+    - Some refactorings a changes to DXT based formats.
+    - Added ifATI1N and ifATI2N image data formats support structures and functions.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added ifBTC image format support structures and functions.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - FillMipMapLevel now works well with indexed and special formats too.
+    - Moved Convert1To8 and Convert4To8 functions from ImagingBitmaps here
+     and created new Convert2To8 function. They are now used by more than one
+     file format loader.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - StretchResample now uses pixel get/set functions stored in
+      TImageFormatInfo so it is  much faster for formats that override
+      them with optimized ones
+    - added pixel set/get functions optimized for various image formats
+      (to be stored in TImageFormatInfo)
+    - bug in ConvertSpecial caused problems when converting DXTC images
+      to bitmaps in ImagingCoponents
+    - bug in StretchRect caused that it didn't work with ifR32F and
+      ifR16F formats
+    - removed leftover code in FillMipMapLevel which disabled
+      filtered resizing of images witch ChannelSize <> 8bits
+    - added half float converting functions and support for half based
+      image formats where needed
+    - added TranslatePixel and IsImageFormatValid functions
+    - fixed possible range overflows when converting from FP to integer images
+    - added pixel set/get functions: GetPixel32Generic, GetPixelFPGeneric,
+      SetPixel32Generic, SetPixelFPGeneric
+    - fixed occasional range overflows in StretchResample
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - added StretchNearest, StretchResample and some sampling functions
+    - added ChannelCount values to TImageFormatInfo constants
+    - added resolution validity check to GetDXTPixelsSize
+
+  -- 0.15 Changes/Bug Fixes -----------------------------------
+    - added RBSwapFormat values to some TImageFromatInfo definitions
+    - fixed bug in ConvertSpecial (causing DXT images to convert only to 32bit)
+    - added CopyPixel, ComparePixels helper functions
+
+  -- 0.13 Changes/Bug Fixes -----------------------------------
+    - replaced pixel format conversions for colors not to be
+      darkened when converting from low bit counts
+    - ReduceColorsMedianCut was updated to support creating one
+      optimal palette for more images and it is somewhat faster
+      now too
+    - there was ugly bug in DXTC dimensions checking
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingGif.pas b/src/lib/vampimg/ImagingGif.pas
new file mode 100644 (file)
index 0000000..a38e33a
--- /dev/null
@@ -0,0 +1,1291 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader/saver for GIF images.}
+unit ImagingGif;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, Classes, Imaging, ImagingTypes, ImagingIO, ImagingUtility;
+
+type
+  { GIF (Graphics Interchange Format) loader/saver class. GIF was
+    (and is still used) popular format for storing images supporting
+    multiple images per file and single color transparency.
+    Pixel format is 8 bit indexed where each image frame can have
+    its own color palette. GIF uses lossless LZW compression
+    (patent expired few years ago).
+    Imaging can load and save all GIFs with all frames and supports
+    transparency. Imaging can load just raw ifIndex8 frames or
+    also animate them in ifA8R8G8B8 format. See ImagingGIFLoadAnimated option.}
+  TGIFFileFormat = class(TImageFileFormat)
+  private
+    FLoadAnimated: LongBool;
+    function InterlaceStep(Y, Height: Integer; var Pass: Integer): Integer;
+    procedure LZWDecompress(Stream: TStream; Handle: TImagingHandle;
+      Width, Height: Integer; Interlaced: Boolean; Data: Pointer);
+    procedure LZWCompress(const IO: TIOFunctions; Handle: TImagingHandle;
+      Width, Height, BitCount: Integer; Interlaced: Boolean; Data: Pointer);
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  published
+    property LoadAnimated: LongBool read FLoadAnimated write FLoadAnimated;
+  end;
+
+implementation
+
+const
+  SGIFFormatName = 'Graphics Interchange Format';
+  SGIFMasks      = '*.gif';
+  GIFSupportedFormats: TImageFormats = [ifIndex8];
+  GIFDefaultLoadAnimated = True;
+
+type
+  TGIFVersion = (gv87, gv89);
+  TDisposalMethod = (dmNoRemoval, dmLeave, dmRestoreBackground,
+    dmRestorePrevious, dmReserved4, dmReserved5, dmReserved6, dmReserved7);
+
+const
+  GIFSignature: TChar3 = 'GIF';
+  GIFVersions: array[TGIFVersion] of TChar3 = ('87a', '89a');
+  GIFDefaultDelay = 65;
+
+  // Masks for accessing fields in PackedFields of TGIFHeader
+  GIFGlobalColorTable = $80;
+  GIFColorResolution  = $70;
+  GIFColorTableSorted = $08;
+  GIFColorTableSize   = $07;
+
+  // Masks for accessing fields in PackedFields of TImageDescriptor
+  GIFLocalColorTable  = $80;
+  GIFInterlaced       = $40;
+  GIFLocalTableSorted = $20;
+
+  // Block identifiers
+  GIFPlainText: Byte               = $01;
+  GIFGraphicControlExtension: Byte = $F9;
+  GIFCommentExtension: Byte        = $FE;
+  GIFApplicationExtension: Byte    = $FF;
+  GIFImageDescriptor: Byte         = Ord(',');
+  GIFExtensionIntroducer: Byte     = Ord('!');
+  GIFTrailer: Byte                 = Ord(';');
+  GIFBlockTerminator: Byte         = $00;
+
+  // Masks for accessing fields in PackedFields of TGraphicControlExtension
+  GIFTransparent    = $01;
+  GIFUserInput      = $02;
+  GIFDisposalMethod = $1C;
+
+const
+  // Netscape sub block types
+  GIFAppLoopExtension   = 1;
+  GIFAppBufferExtension = 2;
+
+type
+  TGIFHeader = packed record
+    // File header part
+    Signature: TChar3;  // Header Signature (always "GIF")
+    Version: TChar3;    // GIF format version("87a" or "89a")
+    // Logical Screen Descriptor part
+    ScreenWidth: Word;  // Width of Display Screen in Pixels
+    ScreenHeight: Word; // Height of Display Screen in Pixels
+    PackedFields: Byte; // Screen and color map information
+    BackgroundColorIndex: Byte; // Background color index (in global color table)
+    AspectRatio: Byte;  // Pixel aspect ratio, ratio = (AspectRatio + 15) / 64
+  end;
+
+  TImageDescriptor = packed record
+    //Separator: Byte; // leave that out since we always read one bye ahead
+    Left: Word;        // X position of image with respect to logical screen
+    Top: Word;         // Y position
+    Width: Word;
+    Height: Word;
+    PackedFields: Byte;
+  end;
+
+const
+  // GIF extension labels
+  GIFExtTypeGraphic     = $F9;
+  GIFExtTypePlainText   = $01;
+  GIFExtTypeApplication = $FF;
+  GIFExtTypeComment     = $FE;
+
+type
+  TGraphicControlExtension = packed record
+    BlockSize: Byte;
+    PackedFields: Byte;
+    DelayTime: Word;
+    TransparentColorIndex: Byte;
+    Terminator: Byte;
+  end;
+
+type
+  TGIFIdentifierCode = array[0..7] of AnsiChar;
+  TGIFAuthenticationCode = array[0..2] of AnsiChar;
+  TGIFApplicationRec = packed record
+    Identifier: TGIFIdentifierCode;
+    Authentication: TGIFAuthenticationCode;
+  end;
+
+const
+  CodeTableSize = 4096;
+  HashTableSize = 17777;
+
+type
+  TReadContext = record
+    Inx: Integer;
+    Size: Integer;
+    Buf: array [0..255 + 4] of Byte;
+    CodeSize: Integer;
+    ReadMask: Integer;
+  end;
+  PReadContext = ^TReadContext;
+
+  TWriteContext = record
+    Inx: Integer;
+    CodeSize: Integer;
+    Buf: array [0..255 + 4] of Byte;
+  end;
+  PWriteContext = ^TWriteContext;
+
+  TOutputContext = record
+    W: Integer;
+    H: Integer;
+    X: Integer;
+    Y: Integer;
+    BitsPerPixel: Integer;
+    Pass: Integer;
+    Interlace: Boolean;
+    LineIdent: Integer;
+    Data: Pointer;
+    CurrLineData: Pointer;
+  end;
+
+  TImageDict = record
+    Tail: Word;
+    Index: Word;
+    Col: Byte;
+  end;
+  PImageDict = ^TImageDict;
+
+  PIntCodeTable = ^TIntCodeTable;
+  TIntCodeTable = array [0..CodeTableSize - 1] of Word;
+
+  TDictTable = array [0..CodeTableSize - 1] of TImageDict;
+  PDictTable = ^TDictTable;
+
+resourcestring
+  SGIFDecodingError = 'Error when decoding GIF LZW data';
+
+{
+  TGIFFileFormat implementation
+}
+
+procedure TGIFFileFormat.Define;
+begin
+  inherited;
+  FName := SGIFFormatName;
+  FFeatures := [ffLoad, ffSave, ffMultiImage];
+  FSupportedFormats := GIFSupportedFormats;
+  FLoadAnimated := GIFDefaultLoadAnimated;
+
+  AddMasks(SGIFMasks);
+  RegisterOption(ImagingGIFLoadAnimated, @FLoadAnimated);
+end;
+
+function TGIFFileFormat.InterlaceStep(Y, Height: Integer; var Pass: Integer): Integer;
+begin
+  Result := Y;
+  case Pass of
+    0, 1:
+      Inc(Result, 8);
+    2:
+      Inc(Result, 4);
+    3:
+      Inc(Result, 2);
+  end;
+  if Result >= Height then
+  begin
+    if Pass = 0 then
+    begin
+      Pass := 1;
+      Result := 4;
+      if Result < Height then
+        Exit;
+    end;
+    if Pass = 1 then
+    begin
+      Pass := 2;
+      Result := 2;
+      if Result < Height then
+        Exit;
+    end;
+    if Pass = 2 then
+    begin
+      Pass := 3;
+      Result := 1;
+    end;
+  end;
+end;
+
+{ GIF LZW decompresion code is from JVCL JvGIF.pas unit.}
+procedure TGIFFileFormat.LZWDecompress(Stream: TStream; Handle: TImagingHandle; Width, Height: Integer;
+  Interlaced: Boolean; Data: Pointer);
+var
+  MinCodeSize: Byte;
+  MaxCode, BitMask, InitCodeSize: Integer;
+  ClearCode, EndingCode, FirstFreeCode, FreeCode: Word;
+  I, OutCount, Code: Integer;
+  CurCode, OldCode, InCode, FinalChar: Word;
+  Prefix, Suffix, OutCode: PIntCodeTable;
+  ReadCtxt: TReadContext;
+  OutCtxt: TOutputContext;
+  TableFull: Boolean;
+
+  function ReadCode(var Context: TReadContext): Integer;
+  var
+    RawCode: Integer;
+    ByteIndex: Integer;
+    Bytes: Byte;
+    BytesToLose: Integer;
+  begin
+    while (Context.Inx + Context.CodeSize > Context.Size) and
+      (Stream.Position < Stream.Size) do
+    begin
+      // Not enough bits in buffer - refill it - Not very efficient, but infrequently called
+      BytesToLose := Context.Inx shr 3;
+      // Note biggest Code Size is 12 bits. And this can at worst span 3 Bytes
+      Move(Context.Buf[Word(BytesToLose)], Context.Buf[0], 3);
+      Context.Inx := Context.Inx and 7;
+      Context.Size := Context.Size - (BytesToLose shl 3);
+      Stream.Read(Bytes, 1);
+      if Bytes > 0 then
+        Stream.Read(Context.Buf[Word(Context.Size shr 3)], Bytes);
+      Context.Size := Context.Size + (Bytes shl 3);
+    end;
+    ByteIndex := Context.Inx shr 3;
+    RawCode := Context.Buf[Word(ByteIndex)] +
+      (Word(Context.Buf[Word(ByteIndex + 1)]) shl 8);
+    if Context.CodeSize > 8 then
+      RawCode := RawCode + (Integer(Context.Buf[ByteIndex + 2]) shl 16);
+    RawCode := RawCode shr (Context.Inx and 7);
+    Context.Inx := Context.Inx + Byte(Context.CodeSize);
+    Result := RawCode and Context.ReadMask;
+  end;
+
+  procedure Output(Value: Byte; var Context: TOutputContext);
+  var
+    P: PByte;
+  begin
+    if Context.Y >= Context.H then
+      Exit;
+
+    // Only ifIndex8 supported
+    P := @PByteArray(Context.CurrLineData)[Context.X];
+    P^ := Value;
+
+    {case Context.BitsPerPixel of
+      1:
+        begin
+          P := @PByteArray(Context.CurrLineData)[Context.X shr 3];
+          if (Context.X and $07) <> 0 then
+            P^ := P^ or Word(Value shl (7 - (Word(Context.X and 7))))
+          else
+            P^ := Byte(Value shl 7);
+        end;
+      4:
+        begin
+          P := @PByteArray(Context.CurrLineData)[Context.X shr 1];
+          if (Context.X and 1) <> 0 then
+            P^ := P^ or Value
+          else
+            P^ := Byte(Value shl 4);
+        end;
+      8:
+        begin
+          P := @PByteArray(Context.CurrLineData)[Context.X];
+          P^ := Value;
+        end;
+    end;}
+    Inc(Context.X);
+
+    if Context.X < Context.W then
+      Exit;
+    Context.X := 0;
+    if Context.Interlace then
+      Context.Y := InterlaceStep(Context.Y, Context.H, Context.Pass)
+    else
+      Inc(Context.Y);
+
+    Context.CurrLineData := @PByteArray(Context.Data)[Context.Y * Context.LineIdent];
+  end;
+
+begin
+  OutCount := 0;
+  OldCode := 0;
+  FinalChar := 0;
+  TableFull := False;
+  GetMem(Prefix, SizeOf(TIntCodeTable));
+  GetMem(Suffix, SizeOf(TIntCodeTable));
+  GetMem(OutCode, SizeOf(TIntCodeTable) + SizeOf(Word));
+  try
+    Stream.Read(MinCodeSize, 1);
+    if (MinCodeSize < 2) or (MinCodeSize > 9) then
+      RaiseImaging(SGIFDecodingError, []);
+    // Initial read context
+    ReadCtxt.Inx := 0;
+    ReadCtxt.Size := 0;
+    ReadCtxt.CodeSize := MinCodeSize + 1;
+    ReadCtxt.ReadMask := (1 shl ReadCtxt.CodeSize) - 1;
+    // Initialise pixel-output context
+    OutCtxt.X := 0;
+    OutCtxt.Y := 0;
+    OutCtxt.Pass := 0;
+    OutCtxt.W := Width;
+    OutCtxt.H := Height;
+    OutCtxt.BitsPerPixel := MinCodeSize;
+    OutCtxt.Interlace := Interlaced;
+    OutCtxt.LineIdent := Width;
+    OutCtxt.Data := Data;
+    OutCtxt.CurrLineData := Data;
+    BitMask := (1 shl OutCtxt.BitsPerPixel) - 1;
+    // 2 ^ MinCodeSize accounts for all colours in file
+    ClearCode := 1 shl MinCodeSize;
+    EndingCode := ClearCode + 1;
+    FreeCode := ClearCode + 2;
+    FirstFreeCode := FreeCode;
+    // 2^ (MinCodeSize + 1) includes clear and eoi Code and space too
+    InitCodeSize := ReadCtxt.CodeSize;
+    MaxCode := 1 shl ReadCtxt.CodeSize;
+    Code := ReadCode(ReadCtxt);
+    while (Code <> EndingCode) and (Code <> $FFFF) and
+      (OutCtxt.Y < OutCtxt.H) do
+    begin
+      if Code = ClearCode then
+      begin
+        ReadCtxt.CodeSize := InitCodeSize;
+        MaxCode := 1 shl ReadCtxt.CodeSize;
+        ReadCtxt.ReadMask := MaxCode - 1;
+        FreeCode := FirstFreeCode;
+        Code := ReadCode(ReadCtxt);
+        CurCode := Code;
+        OldCode := Code;
+        if Code = $FFFF then
+          Break;
+        FinalChar := (CurCode and BitMask);
+        Output(Byte(FinalChar), OutCtxt);
+        TableFull := False;
+      end
+      else
+      begin
+        CurCode := Code;
+        InCode := Code;
+        if CurCode >= FreeCode then
+        begin
+          CurCode := OldCode;
+          OutCode^[OutCount] := FinalChar;
+          Inc(OutCount);
+        end;
+        while CurCode > BitMask do
+        begin
+          if OutCount > CodeTableSize then
+            RaiseImaging(SGIFDecodingError, []);
+          OutCode^[OutCount] := Suffix^[CurCode];
+          Inc(OutCount);
+          CurCode := Prefix^[CurCode];
+        end;
+
+        FinalChar := CurCode and BitMask;
+        OutCode^[OutCount] := FinalChar;
+        Inc(OutCount);
+        for I := OutCount - 1 downto 0 do
+          Output(Byte(OutCode^[I]), OutCtxt);
+        OutCount := 0;
+        // Update dictionary
+        if not TableFull then
+        begin
+          Prefix^[FreeCode] := OldCode;
+          Suffix^[FreeCode] := FinalChar;
+          // Advance to next free slot
+          Inc(FreeCode);
+          if FreeCode >= MaxCode then
+          begin
+            if ReadCtxt.CodeSize < 12 then
+            begin
+              Inc(ReadCtxt.CodeSize);
+              MaxCode := MaxCode shl 1;
+              ReadCtxt.ReadMask := (1 shl ReadCtxt.CodeSize) - 1;
+            end
+            else
+              TableFull := True;
+          end;
+        end;
+        OldCode := InCode;
+      end;
+      Code := ReadCode(ReadCtxt);
+    end;
+    if Code = $FFFF then
+      RaiseImaging(SGIFDecodingError, []);
+  finally
+    FreeMem(Prefix);
+    FreeMem(OutCode);
+    FreeMem(Suffix);
+  end;
+end;
+
+{ GIF LZW compresion code is from JVCL JvGIF.pas unit.}
+procedure TGIFFileFormat.LZWCompress(const IO: TIOFunctions; Handle: TImagingHandle; Width, Height, BitCount: Integer;
+    Interlaced: Boolean; Data: Pointer);
+var
+  LineIdent: Integer;
+  MinCodeSize, Col: Byte;
+  InitCodeSize, X, Y: Integer;
+  Pass: Integer;
+  MaxCode: Integer; { 1 shl CodeSize }
+  ClearCode, EndingCode, LastCode, Tail: Integer;
+  I, HashValue: Integer;
+  LenString: Word;
+  Dict: PDictTable;
+  HashTable: TList;
+  PData: PByte;
+  WriteCtxt: TWriteContext;
+
+  function InitHash(P: Integer): Integer;
+  begin
+    Result := (P + 3) * 301;
+  end;
+
+  procedure WriteCode(Code: Integer; var Context: TWriteContext);
+  var
+    BufIndex: Integer;
+    Bytes: Byte;
+  begin
+    BufIndex := Context.Inx shr 3;
+    Code := Code shl (Context.Inx and 7);
+    Context.Buf[BufIndex] := Context.Buf[BufIndex] or Byte(Code);
+    Context.Buf[BufIndex + 1] := Byte(Code shr 8);
+    Context.Buf[BufIndex + 2] := Byte(Code shr 16);
+    Context.Inx := Context.Inx + Context.CodeSize;
+    if Context.Inx >= 255 * 8 then
+    begin
+      // Flush out full buffer
+      Bytes := 255;
+      IO.Write(Handle, @Bytes, 1);
+      IO.Write(Handle, @Context.Buf, Bytes);
+      Move(Context.Buf[255], Context.Buf[0], 2);
+      FillChar(Context.Buf[2], 255, 0);
+      Context.Inx := Context.Inx - (255 * 8);
+    end;
+  end;
+
+  procedure FlushCode(var Context: TWriteContext);
+  var
+    Bytes: Byte;
+  begin
+    Bytes := (Context.Inx + 7) shr 3;
+    if Bytes > 0 then
+    begin
+      IO.Write(Handle, @Bytes, 1);
+      IO.Write(Handle, @Context.Buf, Bytes);
+    end;
+    // Data block terminator - a block of zero Size
+    Bytes := 0;
+    IO.Write(Handle, @Bytes, 1);
+  end;
+
+begin
+  LineIdent := Width;
+  Tail := 0;
+  HashValue := 0;
+  Col := 0;
+  HashTable := TList.Create;
+  GetMem(Dict, SizeOf(TDictTable));
+  try
+    for I := 0 to HashTableSize - 1 do
+      HashTable.Add(nil);
+
+    // Initialise encoder variables
+    InitCodeSize := BitCount + 1;
+    if InitCodeSize = 2 then
+      Inc(InitCodeSize);
+    MinCodeSize := InitCodeSize - 1;
+    IO.Write(Handle, @MinCodeSize, 1);
+    ClearCode := 1 shl MinCodeSize;
+    EndingCode := ClearCode + 1;
+    LastCode := EndingCode;
+    MaxCode := 1 shl InitCodeSize;
+    LenString := 0;
+    // Setup write context
+    WriteCtxt.Inx := 0;
+    WriteCtxt.CodeSize := InitCodeSize;
+    FillChar(WriteCtxt.Buf, SizeOf(WriteCtxt.Buf), 0);
+    WriteCode(ClearCode, WriteCtxt);
+    Y := 0;
+    Pass := 0;
+
+    while Y < Height do
+    begin
+      PData := @PByteArray(Data)[Y * LineIdent];
+      for X := 0 to Width - 1 do
+      begin
+        // Only ifIndex8 support
+        case BitCount of
+          8:
+            begin
+              Col := PData^;
+              PData := @PByteArray(PData)[1];
+            end;
+          {4:
+            begin
+              if X and 1 <> 0 then
+              begin
+                Col := PData^ and $0F;
+                PData := @PByteArray(PData)[1];
+              end
+              else
+                Col := PData^ shr 4;
+            end;
+          1:
+            begin
+              if X and 7 = 7 then
+              begin
+                Col := PData^ and 1;
+                PData := @PByteArray(PData)[1];
+              end
+              else
+                Col := (PData^ shr (7 - (X and $07))) and $01;
+            end;}
+        end;
+        Inc(LenString);
+        if LenString = 1 then
+        begin
+          Tail := Col;
+          HashValue := InitHash(Col);
+        end
+        else
+        begin
+          HashValue := HashValue * (Col + LenString + 4);
+          I := HashValue mod HashTableSize;
+          HashValue := HashValue mod HashTableSize;
+          while (HashTable[I] <> nil) and
+            ((PImageDict(HashTable[I])^.Tail <> Tail) or
+            (PImageDict(HashTable[I])^.Col <> Col)) do
+          begin
+            Inc(I);
+            if I >= HashTableSize then
+              I := 0;
+          end;
+          if HashTable[I] <> nil then // Found in the strings table
+            Tail := PImageDict(HashTable[I])^.Index
+          else
+          begin
+            // Not found
+            WriteCode(Tail, WriteCtxt);
+            Inc(LastCode);
+            HashTable[I] := @Dict^[LastCode];
+            PImageDict(HashTable[I])^.Index := LastCode;
+            PImageDict(HashTable[I])^.Tail := Tail;
+            PImageDict(HashTable[I])^.Col := Col;
+            Tail := Col;
+            HashValue := InitHash(Col);
+            LenString := 1;
+            if LastCode >= MaxCode then
+            begin
+              // Next Code will be written longer
+              MaxCode := MaxCode shl 1;
+              Inc(WriteCtxt.CodeSize);
+            end
+            else
+            if LastCode >= CodeTableSize - 2 then
+            begin
+              // Reset tables
+              WriteCode(Tail, WriteCtxt);
+              WriteCode(ClearCode, WriteCtxt);
+              LenString := 0;
+              LastCode := EndingCode;
+              WriteCtxt.CodeSize := InitCodeSize;
+              MaxCode := 1 shl InitCodeSize;
+              for I := 0 to HashTableSize - 1 do
+                HashTable[I] := nil;
+            end;
+          end;
+        end;
+      end;
+      if Interlaced then
+        Y := InterlaceStep(Y, Height, Pass)
+      else
+        Inc(Y);
+    end;
+    WriteCode(Tail, WriteCtxt);
+    WriteCode(EndingCode, WriteCtxt);
+    FlushCode(WriteCtxt);
+  finally
+    HashTable.Free;
+    FreeMem(Dict);
+  end;
+end;
+
+function TGIFFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+type
+  TFrameInfo = record
+    Left, Top: Integer;
+    Width, Height: Integer;
+    Disposal: TDisposalMethod;
+    HasTransparency: Boolean;
+    HasLocalPal: Boolean;
+    TransIndex: Integer;
+    BackIndex: Integer;
+  end;
+var
+  Header: TGIFHeader;
+  HasGlobalPal: Boolean;
+  GlobalPalLength: Integer;
+  GlobalPal: TPalette32Size256;
+  ScreenWidth, ScreenHeight, I, CachedIndex: Integer;
+  BlockID: Byte;
+  HasGraphicExt: Boolean;
+  GraphicExt: TGraphicControlExtension;
+  FrameInfos: array of TFrameInfo;
+  AppRead: Boolean;
+  CachedFrame: TImageData;
+  AnimFrames: TDynImageDataArray;
+
+  function ReadBlockID: Byte;
+  begin
+    Result := GIFTrailer;
+    if GetIO.Read(Handle, @Result, SizeOf(Result)) < SizeOf(Result) then
+      Result := GIFTrailer;
+  end;
+
+  procedure ReadExtensions;
+  var
+    BlockSize, BlockType, ExtType: Byte;
+    AppRec: TGIFApplicationRec;
+    LoopCount: SmallInt;
+
+    procedure SkipBytes;
+    begin
+      with GetIO do
+      repeat
+        // Read block sizes and skip them
+        Read(Handle, @BlockSize, SizeOf(BlockSize));
+        Seek(Handle, BlockSize, smFromCurrent);
+      until BlockSize = 0;
+    end;
+
+  begin
+    HasGraphicExt := False;
+    AppRead := False;
+
+    // Read extensions until image descriptor is found. Only graphic extension
+    // is stored now (for transparency), others are skipped.
+    while BlockID = GIFExtensionIntroducer do
+    with GetIO do
+    begin
+      Read(Handle, @ExtType, SizeOf(ExtType));
+
+      while ExtType in [GIFGraphicControlExtension, GIFCommentExtension, GIFApplicationExtension, GIFPlainText] do
+      begin
+        if ExtType = GIFGraphicControlExtension then
+        begin
+          HasGraphicExt := True;
+          Read(Handle, @GraphicExt, SizeOf(GraphicExt));
+        end
+        else if (ExtType = GIFApplicationExtension) and not AppRead then
+        begin
+          Read(Handle, @BlockSize, SizeOf(BlockSize));
+          if BlockSize >= SizeOf(AppRec) then
+          begin
+            Read(Handle, @AppRec, SizeOf(AppRec));
+            if ((AppRec.Identifier = 'NETSCAPE') and (AppRec.Authentication = '2.0')) or
+              ((AppRec.Identifier = 'ANIMEXTS') and (AppRec.Authentication = '1.0')) then
+            begin
+              Read(Handle, @BlockSize, SizeOf(BlockSize));
+              while BlockSize <> 0 do
+              begin
+                BlockType := ReadBlockID;
+                Dec(BlockSize);
+
+                case BlockType of
+                  GIFAppLoopExtension:
+                    if (BlockSize >= SizeOf(LoopCount)) then
+                    begin
+                      // Read loop count
+                      Read(Handle, @LoopCount, SizeOf(LoopCount));
+                      Dec(BlockSize, SizeOf(LoopCount));
+                      if LoopCount > 0 then
+                        Inc(LoopCount); // Netscape extension is really "repeats" not "loops"
+                      FMetadata.SetMetaItem(SMetaAnimationLoops, LoopCount);
+                    end;
+                  GIFAppBufferExtension:
+                    begin
+                      Dec(BlockSize, SizeOf(Word));
+                      Seek(Handle, SizeOf(Word), smFromCurrent);
+                    end;
+                end;
+              end;
+              SkipBytes;
+              AppRead := True;
+            end
+            else
+              begin
+                // Revert all bytes reading
+                Seek(Handle, - SizeOf(AppRec) - SizeOf(BlockSize), smFromCurrent);
+                SkipBytes;
+              end;
+          end
+          else
+            begin
+              Seek(Handle, - BlockSize - SizeOf(BlockSize), smFromCurrent);
+              SkipBytes;
+            end;
+        end
+        else if ExtType in [GIFCommentExtension, GIFApplicationExtension, GIFPlainText] then
+        repeat
+          // Read block sizes and skip them
+          Read(Handle, @BlockSize, SizeOf(BlockSize));
+          Seek(Handle, BlockSize, smFromCurrent);
+        until BlockSize = 0;
+
+        // Read ID of following block
+        BlockID := ReadBlockID;
+        ExtType := BlockID;
+      end
+    end;
+  end;
+
+  procedure CopyLZWData(Dest: TStream);
+  var
+    CodeSize, BlockSize: Byte;
+    InputSize: Integer;
+    Buff: array[Byte] of Byte;
+  begin
+    InputSize := ImagingIO.GetInputSize(GetIO, Handle);
+    // Copy codesize to stream
+    GetIO.Read(Handle, @CodeSize, 1);
+    Dest.Write(CodeSize, 1);
+    repeat
+      // Read and write data blocks, last is block term value of 0
+      GetIO.Read(Handle, @BlockSize, 1);
+      Dest.Write(BlockSize, 1);
+      if BlockSize > 0 then
+      begin
+        GetIO.Read(Handle, @Buff[0], BlockSize);
+        Dest.Write(Buff[0], BlockSize);
+      end;
+    until (BlockSize = 0) or (GetIO.Tell(Handle) >= InputSize);
+  end;
+
+  procedure ReadFrame;
+  var
+    ImageDesc: TImageDescriptor;
+    Interlaced: Boolean;
+    I, Idx, LocalPalLength: Integer;
+    LocalPal: TPalette32Size256;
+    LZWStream: TMemoryStream;
+
+    procedure RemoveBadFrame;
+    begin
+      FreeImage(Images[Idx]);
+      SetLength(Images, Length(Images) - 1);
+    end;
+
+  begin
+    Idx := Length(Images);
+    SetLength(Images, Idx + 1);
+    SetLength(FrameInfos, Idx + 1);
+    FillChar(LocalPal, SizeOf(LocalPal), 0);
+
+    with GetIO do
+    begin
+      // Read and parse image descriptor
+      Read(Handle, @ImageDesc, SizeOf(ImageDesc));
+      FrameInfos[Idx].HasLocalPal := (ImageDesc.PackedFields and GIFLocalColorTable) = GIFLocalColorTable;
+      Interlaced := (ImageDesc.PackedFields and GIFInterlaced) = GIFInterlaced;
+      LocalPalLength := ImageDesc.PackedFields and GIFColorTableSize;
+      LocalPalLength := 1 shl (LocalPalLength + 1);   // Total pal length is 2^(n+1)
+
+      // From Mozilla source
+      if (ImageDesc.Width = 0) or (ImageDesc.Width > Header.ScreenWidth) then
+        ImageDesc.Width := Header.ScreenWidth;
+      if (ImageDesc.Height = 0) or (ImageDesc.Height > Header.ScreenHeight)  then
+        ImageDesc.Height := Header.ScreenHeight;
+
+      FrameInfos[Idx].Left := ImageDesc.Left;
+      FrameInfos[Idx].Top := ImageDesc.Top;
+      FrameInfos[Idx].Width := ImageDesc.Width;
+      FrameInfos[Idx].Height := ImageDesc.Height;
+      FrameInfos[Idx].BackIndex := Header.BackgroundColorIndex;
+
+      // Create new image for this frame which would be later pasted onto logical screen
+      NewImage(ImageDesc.Width, ImageDesc.Height, ifIndex8, Images[Idx]);
+
+      // Load local palette if there is any
+      if FrameInfos[Idx].HasLocalPal then
+        for I := 0 to LocalPalLength - 1 do
+        begin
+          LocalPal[I].A := 255;
+          Read(Handle, @LocalPal[I].R, SizeOf(LocalPal[I].R));
+          Read(Handle, @LocalPal[I].G, SizeOf(LocalPal[I].G));
+          Read(Handle, @LocalPal[I].B, SizeOf(LocalPal[I].B));
+        end;
+
+      // Use local pal if present or global pal if present or create
+      // default pal if neither of them is present
+      if FrameInfos[Idx].HasLocalPal then
+        Move(LocalPal, Images[Idx].Palette^, SizeOf(LocalPal))
+      else if HasGlobalPal then
+        Move(GlobalPal, Images[Idx].Palette^, SizeOf(GlobalPal))
+      else
+        FillCustomPalette(Images[Idx].Palette, GlobalPalLength, 3, 3, 2);
+
+      if (ImageDesc.Left <= Header.ScreenWidth + 1) and (ImageDesc.Top <= Header.ScreenHeight + 1) then
+      begin
+        // Resize the screen if needed to fit the frame
+        ScreenWidth := Max(ScreenWidth, ImageDesc.Width + ImageDesc.Left);
+        ScreenHeight := Max(ScreenHeight, ImageDesc.Height + ImageDesc.Top);
+      end
+      else
+      begin
+        // Remove frame outside logical screen
+        RemoveBadFrame;
+        Exit;
+      end;
+
+      // If Grahic Control Extension is present make use of it
+      if HasGraphicExt then
+      begin
+        FrameInfos[Idx].HasTransparency := (GraphicExt.PackedFields and GIFTransparent) = GIFTransparent;
+        FrameInfos[Idx].Disposal := TDisposalMethod((GraphicExt.PackedFields and GIFDisposalMethod) shr 2);
+        if FrameInfos[Idx].HasTransparency then
+        begin
+          FrameInfos[Idx].TransIndex := GraphicExt.TransparentColorIndex;
+          Images[Idx].Palette[FrameInfos[Idx].TransIndex].A := 0;
+        end;
+        FMetadata.SetMetaItem(SMetaFrameDelay, Integer(GraphicExt.DelayTime * 10), Idx);
+      end
+      else
+        FrameInfos[Idx].HasTransparency := False;
+
+      LZWStream := TMemoryStream.Create;
+      try
+        try
+          // Copy LZW data to temp stream, needed for correct decompression
+          CopyLZWData(LZWStream);
+          LZWStream.Position := 0;
+          // Data decompression finally
+          LZWDecompress(LZWStream, Handle, ImageDesc.Width, ImageDesc.Height, Interlaced, Images[Idx].Bits);
+        except
+          RemoveBadFrame;
+          Exit;
+        end;
+      finally
+        LZWStream.Free;
+      end;
+    end;
+  end;
+
+  procedure CopyFrameTransparent32(const Image, Frame: TImageData; Left, Top: Integer);
+  var
+    X, Y: Integer;
+    Src: PByte;
+    Dst: PColor32;
+  begin
+    Src := Frame.Bits;
+
+    // Copy all pixels from frame to log screen but ignore the transparent ones
+    for Y := 0 to Frame.Height - 1 do
+    begin
+      Dst := @PColor32RecArray(Image.Bits)[(Top + Y) * Image.Width + Left];
+      for X := 0 to Frame.Width - 1 do
+      begin
+        if (Frame.Palette[Src^].A <> 0) then
+          Dst^ := Frame.Palette[Src^].Color;
+        Inc(Src);
+        Inc(Dst);
+      end;
+    end;
+  end;
+
+  procedure AnimateFrame(Index: Integer; var AnimFrame: TImageData);
+  var
+    I, First, Last: Integer;
+    UseCache: Boolean;
+    BGColor: TColor32;
+  begin
+    // We may need to use raw frame 0 to n to correctly animate n-th frame
+    Last := Index;
+    First := Max(0, Last);
+    // See if we can use last animate frame as a basis for this one
+    // (so we don't have to use previous raw frames).
+    UseCache := TestImage(CachedFrame) and (CachedIndex = Index - 1) and (CachedIndex >= 0) and
+      (FrameInfos[CachedIndex].Disposal <> dmRestorePrevious);
+
+    // Reuse or release cache
+    if UseCache then
+      CloneImage(CachedFrame, AnimFrame)
+    else
+      FreeImage(CachedFrame);
+
+    // Default color for clearing of the screen
+    BGColor := Images[Index].Palette[FrameInfos[Index].BackIndex].Color;
+
+    // Now prepare logical screen for drawing of raw frame at Index.
+    // We may need to use all previous raw frames to get the screen
+    // to proper state (according to their disposal methods).
+
+    if not UseCache then
+    begin
+      if FrameInfos[Index].HasTransparency then
+        BGColor := Images[Index].Palette[FrameInfos[Index].TransIndex].Color;
+      // Clear whole screen
+      FillMemoryLongWord(AnimFrame.Bits, AnimFrame.Size, BGColor);
+
+      // Try to maximize First so we don't have to use all 0 to n raw frames
+      while First > 0 do
+      begin
+        if (ScreenWidth = Images[First].Width) and (ScreenHeight = Images[First].Height) then
+        begin
+          if (FrameInfos[First].Disposal = dmRestoreBackground) and (First < Last) then
+            Break;
+        end;
+        Dec(First);
+      end;
+
+      for I := First to Last - 1 do
+      begin
+        case FrameInfos[I].Disposal of
+          dmNoRemoval, dmLeave:
+            begin
+              // Copy previous raw frame  onto screen
+              CopyFrameTransparent32(AnimFrame, Images[I], FrameInfos[I].Left, FrameInfos[I].Top);
+            end;
+          dmRestoreBackground:
+            if (I > First) then
+            begin
+              // Restore background color
+              FillRect(AnimFrame, FrameInfos[I].Left, FrameInfos[I].Top,
+                FrameInfos[I].Width, FrameInfos[I].Height, @BGColor);
+            end;
+          dmRestorePrevious: ; // Do nothing - previous state is already on screen
+        end;
+      end;
+    end
+    else if FrameInfos[CachedIndex].Disposal = dmRestoreBackground then
+    begin
+      // We have our cached result but also need to restore
+      // background in a place of cached frame
+      if FrameInfos[CachedIndex].HasTransparency then
+        BGColor := Images[CachedIndex].Palette[FrameInfos[CachedIndex].TransIndex].Color;
+      FillRect(AnimFrame, FrameInfos[CachedIndex].Left, FrameInfos[CachedIndex].Top,
+        FrameInfos[CachedIndex].Width, FrameInfos[CachedIndex].Height, @BGColor);
+    end;
+
+    // Copy current raw frame to prepared screen
+    CopyFrameTransparent32(AnimFrame, Images[Index], FrameInfos[Index].Left, FrameInfos[Index].Top);
+
+    // Cache animated result
+    CloneImage(AnimFrame, CachedFrame);
+    CachedIndex := Index;
+  end;
+
+begin
+  AppRead := False;
+
+  SetLength(Images, 0);
+  FillChar(GlobalPal, SizeOf(GlobalPal), 0);
+
+  with GetIO do
+  begin
+    // Read GIF header
+    Read(Handle, @Header, SizeOf(Header));
+    ScreenWidth := Header.ScreenWidth;
+    ScreenHeight := Header.ScreenHeight;
+    HasGlobalPal := Header.PackedFields and GIFGlobalColorTable = GIFGlobalColorTable; // Bit 7
+    GlobalPalLength := Header.PackedFields and GIFColorTableSize; // Bits 0-2
+    GlobalPalLength := 1 shl (GlobalPalLength + 1);   // Total pal length is 2^(n+1)
+
+    // Read global palette from file if present
+    if HasGlobalPal then
+    begin
+      for I := 0 to GlobalPalLength - 1 do
+      begin
+        GlobalPal[I].A := 255;
+        Read(Handle, @GlobalPal[I].R, SizeOf(GlobalPal[I].R));
+        Read(Handle, @GlobalPal[I].G, SizeOf(GlobalPal[I].G));
+        Read(Handle, @GlobalPal[I].B, SizeOf(GlobalPal[I].B));
+      end;
+    end;
+
+    // Read ID of the first block
+    BlockID := ReadBlockID;
+
+    // Now read all data blocks in the file until file trailer is reached
+    while BlockID <> GIFTrailer do
+    begin
+      // Read blocks until we find the one of known type
+      while not (BlockID in [GIFTrailer, GIFExtensionIntroducer, GIFImageDescriptor]) do
+        BlockID := ReadBlockID;
+      // Read supported and skip unsupported extensions
+      ReadExtensions;
+      // If image frame is found read it
+      if BlockID = GIFImageDescriptor then
+        ReadFrame;
+      // Read next block's ID
+      BlockID := ReadBlockID;
+      // If block ID is unknown set it to end-of-GIF marker
+      if not (BlockID in [GIFExtensionIntroducer, GIFTrailer, GIFImageDescriptor]) then
+        BlockID := GIFTrailer;
+    end;
+
+    if FLoadAnimated then
+    begin
+      // Aniated frames will be stored in AnimFrames
+      SetLength(AnimFrames, Length(Images));
+      InitImage(CachedFrame);
+      CachedIndex := -1;
+
+      for I := 0 to High(Images) do
+      begin
+        // Create new logical screen
+        NewImage(ScreenWidth, ScreenHeight, ifA8R8G8B8, AnimFrames[I]);
+        // Animate frames to current log screen
+        AnimateFrame(I, AnimFrames[I]);
+      end;
+
+      // Now release raw 8bit frames and put animated 32bit ones
+      // to output array
+      FreeImage(CachedFrame);
+      for I := 0 to High(AnimFrames) do
+      begin
+        FreeImage(Images[I]);
+        Images[I] := AnimFrames[I];
+      end;
+    end;
+
+    Result := True;
+  end;
+end;
+
+function TGIFFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: Integer): Boolean;
+var
+  Header: TGIFHeader;
+  ImageDesc: TImageDescriptor;
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+  I, J: Integer;
+  GraphicExt: TGraphicControlExtension;
+
+  procedure FindMaxDimensions(var MaxWidth, MaxHeight: Word);
+  var
+    I: Integer;
+  begin
+    MaxWidth := Images[FFirstIdx].Width;
+    MaxHeight := Images[FFirstIdx].Height;
+
+    for I := FFirstIdx + 1 to FLastIdx do
+    begin
+      MaxWidth := Iff(Images[I].Width > MaxWidth, Images[I].Width, MaxWidth);
+      MaxHeight := Iff(Images[I].Height > MaxWidth, Images[I].Height, MaxHeight);
+    end;
+  end;
+
+  procedure SetFrameDelay(Idx: Integer; var Ext: TGraphicControlExtension);
+  begin
+    if FMetadata.HasMetaItemForSaving(SMetaFrameDelay, Idx) then
+      Ext.DelayTime := FMetadata.MetaItemsForSavingMulti[SMetaFrameDelay, Idx] div 10
+    else
+      Ext.DelayTime := GIFDefaultDelay;
+  end;
+
+  procedure SaveGlobalMetadata;
+  var
+    AppExt: TGIFApplicationRec;
+    BlockSize, LoopExtId: Byte;
+    Repeats: Word;
+  begin
+    if FMetadata.HasMetaItemForSaving(SMetaAnimationLoops) then
+    with GetIO do
+    begin
+      FillChar(AppExt, SizeOf(AppExt), 0);
+      AppExt.Identifier := 'NETSCAPE';
+      AppExt.Authentication := '2.0';
+      Repeats := FMetadata.MetaItemsForSaving[SMetaAnimationLoops];
+      if Repeats > 0 then
+        Dec(Repeats);
+      LoopExtId := GIFAppLoopExtension;
+
+      Write(Handle, @GIFExtensionIntroducer, SizeOf(GIFExtensionIntroducer));
+      Write(Handle, @GIFApplicationExtension, SizeOf(GIFApplicationExtension));
+      BlockSize := 11;
+      Write(Handle, @BlockSize, SizeOf(BlockSize));
+      Write(Handle, @AppExt, SizeOf(AppExt));
+      BlockSize := 3;
+      Write(Handle, @BlockSize, SizeOf(BlockSize));
+      Write(Handle, @LoopExtId, SizeOf(LoopExtId));
+      Write(Handle, @Repeats, SizeOf(Repeats));
+      Write(Handle, @GIFBlockTerminator, SizeOf(GIFBlockTerminator));
+    end;
+  end;
+
+begin
+  // Fill header with data, select size of largest image in array as
+  // logical screen size
+  FillChar(Header, Sizeof(Header), 0);
+  Header.Signature := GIFSignature;
+  Header.Version := GIFVersions[gv89];
+  FindMaxDimensions(Header.ScreenWidth, Header.ScreenHeight);
+  Header.PackedFields := GIFColorResolution; // Color resolution is 256
+  GetIO.Write(Handle, @Header, SizeOf(Header));
+
+  // Prepare default GC extension with delay
+  FillChar(GraphicExt, Sizeof(GraphicExt), 0);
+  GraphicExt.DelayTime := GIFDefaultDelay;
+  GraphicExt.BlockSize := 4;
+
+  SaveGlobalMetadata;
+
+  for I := FFirstIdx to FLastIdx do
+  begin
+    if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then
+    with GetIO, ImageToSave do
+    try
+      // Write Graphic Control Extension with default delay
+      Write(Handle, @GIFExtensionIntroducer, SizeOf(GIFExtensionIntroducer));
+      Write(Handle, @GIFGraphicControlExtension, SizeOf(GIFGraphicControlExtension));
+      SetFrameDelay(I, GraphicExt);
+      Write(Handle, @GraphicExt, SizeOf(GraphicExt));
+      // Write frame marker and fill and write image descriptor for this frame
+      Write(Handle, @GIFImageDescriptor, SizeOf(GIFImageDescriptor));
+      FillChar(ImageDesc, Sizeof(ImageDesc), 0);
+      ImageDesc.Width := Width;
+      ImageDesc.Height := Height;
+      ImageDesc.PackedFields := GIFLocalColorTable or GIFColorTableSize; // Use lccal color table with 256 entries
+      Write(Handle, @ImageDesc, SizeOf(ImageDesc));
+
+      // Write local color table for each frame
+      for J := 0 to 255 do
+      begin
+        Write(Handle, @Palette[J].R, SizeOf(Palette[J].R));
+        Write(Handle, @Palette[J].G, SizeOf(Palette[J].G));
+        Write(Handle, @Palette[J].B, SizeOf(Palette[J].B));
+      end;
+
+      // Finally compress image data
+      LZWCompress(GetIO, Handle, Width, Height, 8, False, Bits);
+
+    finally
+      if MustBeFreed then
+        FreeImage(ImageToSave);
+    end;
+  end;
+
+  GetIO.Write(Handle, @GIFTrailer, SizeOf(GIFTrailer));
+  Result := True;
+end;
+
+procedure TGIFFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+begin
+  ConvertImage(Image, ifIndex8);
+end;
+
+function TGIFFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Header: TGIFHeader;
+  ReadCount: Integer;
+begin
+  Result := False;
+  if Handle <> nil then
+  begin
+    ReadCount := GetIO.Read(Handle, @Header, SizeOf(Header));
+    GetIO.Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (ReadCount >= SizeOf(Header)) and
+      (Header.Signature = GIFSignature) and
+      ((Header.Version = GIFVersions[gv87]) or (Header.Version = GIFVersions[gv89]));
+  end;
+end;
+
+initialization
+  RegisterImageFileFormat(TGIFFileFormat);
+
+{
+  File Notes:
+
+ -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77 Changes/Bug Fixes -----------------------------------
+    - Fixed crash when resaving GIF with animation metadata.
+    - Writes frame delays of GIF animations from metadata.
+    - Reads and writes looping of GIF animations stored into/from metadata.
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Reads frame delays from GIF animations into metadata.
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Fixed bug - loading of GIF with NETSCAPE app extensions
+      failed with Delphi 2009.
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - GIF loading and animation mostly rewritten, based on
+      modification by Sergey Galezdinov (ExtraGIF in Extras/Contrib).
+
+  -- 0.25.0 Changes/Bug Fixes ---------------------------------
+    - Fixed loading of some rare GIFs, problems with LZW
+      decompression.
+
+  -- 0.24.3 Changes/Bug Fixes ---------------------------------
+    - Better solution to transparency for some GIFs. Background not
+      transparent by default.
+
+  -- 0.24.1 Changes/Bug Fixes ---------------------------------
+    - Made backround color transparent by default (alpha = 0).
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Fixed other loading bugs (local pal size, transparency).
+    - Added GIF saving.
+    - Fixed bug when loading multiframe GIFs and implemented few animation
+      features (disposal methods, ...).
+    - Loading of GIFs working.
+    - Unit created with initial stuff!
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingIO.pas b/src/lib/vampimg/ImagingIO.pas
new file mode 100644 (file)
index 0000000..32d2bc2
--- /dev/null
@@ -0,0 +1,646 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains default IO functions for reading from/writting to
+  files, streams and memory.}
+unit ImagingIO;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility;
+
+type
+  TMemoryIORec = record
+    Data: ImagingUtility.PByteArray;
+    Position: LongInt;
+    Size: LongInt;
+  end;
+  PMemoryIORec = ^TMemoryIORec;
+
+var
+  OriginalFileIO: TIOFunctions;
+  FileIO: TIOFunctions;
+  StreamIO: TIOFunctions;
+  MemoryIO: TIOFunctions;
+
+{ Helper function that returns size of input (from current position to the end)
+  represented by Handle (and opened and operated on by members of IOFunctions).}
+function GetInputSize(IOFunctions: TIOFunctions; Handle: TImagingHandle): LongInt;
+{ Helper function that initializes TMemoryIORec with given params.}
+function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec;
+{ Reads one text line from input (CR+LF, CR, or LF as line delimiter).}
+function ReadLine(IOFunctions: TIOFunctions; Handle: TImagingHandle;
+  out Line: AnsiString; FailOnControlChars: Boolean = False): Boolean;
+{ Writes one text line to input with optional line delimiter.}
+procedure WriteLine(IOFunctions: TIOFunctions; Handle: TImagingHandle;
+  const Line: AnsiString; const LineEnding: AnsiString = sLineBreak);
+
+implementation
+
+const
+  DefaultBufferSize = 16 * 1024;
+
+type
+  { Based on TaaBufferedStream
+    Copyright (c) Julian M Bucknall 1997, 1999 }
+  TBufferedStream = class
+  private
+    FBuffer: PByteArray;
+    FBufSize: Integer;
+    FBufStart: Integer;
+    FBufPos: Integer;
+    FBytesInBuf: Integer;
+    FSize: Integer;
+    FDirty: Boolean;
+    FStream: TStream;
+    function GetPosition: Integer;
+    function GetSize: Integer;
+    procedure ReadBuffer;
+    procedure WriteBuffer;
+    procedure SetPosition(const Value: Integer);
+  public
+    constructor Create(AStream: TStream);
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Integer): Integer;
+    function Write(const Buffer; Count: Integer): Integer;
+    function Seek(Offset: Integer; Origin: Word): Integer;
+    procedure Commit;
+    property Stream: TStream read FStream;
+    property Position: Integer read GetPosition write SetPosition;
+    property Size: Integer read GetSize;
+  end;
+
+constructor TBufferedStream.Create(AStream: TStream);
+begin
+  inherited Create;
+  FStream := AStream;
+  FBufSize := DefaultBufferSize;
+  GetMem(FBuffer, FBufSize);
+  FBufPos := 0;
+  FBytesInBuf := 0;
+  FBufStart := 0;
+  FDirty := False;
+  FSize := AStream.Size;
+end;
+
+destructor TBufferedStream.Destroy;
+begin
+  if FBuffer <> nil then
+  begin
+    Commit;
+    FreeMem(FBuffer);
+  end;
+  FStream.Position := Position; // Make sure source stream has right position
+  inherited Destroy;
+end;
+
+function TBufferedStream.GetPosition: Integer;
+begin
+  Result := FBufStart + FBufPos;
+end;
+
+procedure TBufferedStream.SetPosition(const Value: Integer);
+begin
+  Seek(Value, soFromCurrent);
+end;
+
+function TBufferedStream.GetSize: Integer;
+begin
+  Result := FSize;
+end;
+
+procedure TBufferedStream.ReadBuffer;
+var
+  SeekResult: Integer;
+begin
+  SeekResult := FStream.Seek(FBufStart, 0);
+  if SeekResult = -1 then
+    raise Exception.Create('TBufferedStream.ReadBuffer: seek failed');
+  FBytesInBuf := FStream.Read(FBuffer^, FBufSize);
+  if FBytesInBuf <= 0 then
+    raise Exception.Create('TBufferedStream.ReadBuffer: read failed');
+end;
+
+procedure TBufferedStream.WriteBuffer;
+var
+  SeekResult: Integer;
+  BytesWritten: Integer;
+begin
+  SeekResult := FStream.Seek(FBufStart, 0);
+  if SeekResult = -1 then
+    raise Exception.Create('TBufferedStream.WriteBuffer: seek failed');
+  BytesWritten := FStream.Write(FBuffer^, FBytesInBuf);
+  if BytesWritten <> FBytesInBuf then
+    raise Exception.Create('TBufferedStream.WriteBuffer: write failed');
+end;
+
+procedure TBufferedStream.Commit;
+begin
+  if FDirty then
+  begin
+    WriteBuffer;
+    FDirty := False;
+  end;
+end;
+
+function TBufferedStream.Read(var Buffer; Count: Integer): Integer;
+var
+  BufAsBytes  : TByteArray absolute Buffer;
+  BufIdx, BytesToGo, BytesToRead: Integer;
+begin
+  // Calculate the actual number of bytes we can read - this depends on
+  // the current position and size of the stream as well as the number
+  // of bytes requested.
+  BytesToGo := Count;
+  if FSize < (FBufStart + FBufPos + Count) then
+    BytesToGo := FSize - (FBufStart + FBufPos);
+
+  if BytesToGo <= 0 then
+  begin
+    Result := 0;
+    Exit;
+  end;
+  // Remember to return the result of our calculation
+  Result := BytesToGo;
+
+  BufIdx := 0;
+  if FBytesInBuf = 0 then
+    ReadBuffer;
+  // Calculate the number of bytes we can read prior to the loop
+  BytesToRead := FBytesInBuf - FBufPos;
+  if BytesToRead > BytesToGo then
+    BytesToRead := BytesToGo;
+  // Copy from the stream buffer to the caller's buffer
+  Move(FBuffer^[FBufPos], BufAsBytes[BufIdx], BytesToRead);
+  // Calculate the number of bytes still to read}
+  Dec(BytesToGo, BytesToRead);
+
+  // while we have bytes to read, read them
+  while BytesToGo > 0 do
+  begin
+    Inc(BufIdx, BytesToRead);
+    // As we've exhausted this buffer-full, advance to the next, check
+    //  to see whether we need to write the buffer out first
+    if FDirty then
+    begin
+      WriteBuffer;
+      FDirty := false;
+    end;
+    Inc(FBufStart, FBufSize);
+    FBufPos := 0;
+    ReadBuffer;
+    // Calculate the number of bytes we can read in this cycle
+    BytesToRead := FBytesInBuf;
+    if BytesToRead > BytesToGo then
+      BytesToRead := BytesToGo;
+    // Ccopy from the stream buffer to the caller's buffer
+    Move(FBuffer^, BufAsBytes[BufIdx], BytesToRead);
+    // Calculate the number of bytes still to read
+    Dec(BytesToGo, BytesToRead);
+  end;
+  // Remember our new position
+  Inc(FBufPos, BytesToRead);
+  if FBufPos = FBufSize then
+  begin
+    Inc(FBufStart, FBufSize);
+    FBufPos := 0;
+    FBytesInBuf := 0;
+  end;
+end;
+
+function TBufferedStream.Seek(Offset: Integer; Origin: Word): Integer;
+var
+  NewBufStart, NewPos: Integer;
+begin
+  // Calculate the new position
+  case Origin of
+    soFromBeginning : NewPos := Offset;
+    soFromCurrent   : NewPos := FBufStart + FBufPos + Offset;
+    soFromEnd       : NewPos := FSize + Offset;
+  else
+    raise Exception.Create('TBufferedStream.Seek: invalid origin');
+  end;
+
+  if (NewPos < 0) or (NewPos > FSize) then
+  begin
+    //NewPos := ClampInt(NewPos, 0, FSize); don't do this - for writing
+  end;
+  // Calculate which page of the file we need to be at
+  NewBufStart := NewPos and not Pred(FBufSize);
+  // If the new page is different than the old, mark the buffer as being
+  // ready to be replenished, and if need be write out any dirty data
+  if NewBufStart <> FBufStart then
+  begin
+    if FDirty then
+    begin
+      WriteBuffer;
+      FDirty := False;
+    end;
+    FBufStart := NewBufStart;
+    FBytesInBuf := 0;
+  end;
+  // Save the new position
+  FBufPos := NewPos - NewBufStart;
+  Result := NewPos;
+end;
+
+function TBufferedStream.Write(const Buffer; Count: Integer): Integer;
+var
+  BufAsBytes: TByteArray absolute Buffer;
+  BufIdx, BytesToGo, BytesToWrite: Integer;
+begin
+  // When we write to this stream we always assume that we can write the
+  // requested number of bytes: if we can't (eg, the disk is full) we'll
+  // get an exception somewhere eventually.
+  BytesToGo := Count;
+  // Remember to return the result of our calculation
+  Result := BytesToGo;
+
+  BufIdx := 0;
+  if (FBytesInBuf = 0) and (FSize > FBufStart) then
+    ReadBuffer;
+  // Calculate the number of bytes we can write prior to the loop
+  BytesToWrite := FBufSize - FBufPos;
+  if BytesToWrite > BytesToGo then
+    BytesToWrite := BytesToGo;
+  // Copy from the caller's buffer to the stream buffer
+  Move(BufAsBytes[BufIdx], FBuffer^[FBufPos], BytesToWrite);
+  // Mark our stream buffer as requiring a save to the actual stream,
+  // note that this will suffice for the rest of the routine as well: no
+  // inner routine will turn off the dirty flag.
+  FDirty := True;
+  // Calculate the number of bytes still to write
+  Dec(BytesToGo, BytesToWrite);
+
+  // While we have bytes to write, write them
+  while BytesToGo > 0 do
+  begin
+    Inc(BufIdx, BytesToWrite);
+    // As we've filled this buffer, write it out to the actual stream
+    // and advance to the next buffer, reading it if required
+    FBytesInBuf := FBufSize;
+    WriteBuffer;
+    Inc(FBufStart, FBufSize);
+    FBufPos := 0;
+    FBytesInBuf := 0;
+    if FSize > FBufStart then
+      ReadBuffer;
+    // Calculate the number of bytes we can write in this cycle
+    BytesToWrite := FBufSize;
+    if BytesToWrite > BytesToGo then
+      BytesToWrite := BytesToGo;
+    // Copy from the caller's buffer to our buffer
+    Move(BufAsBytes[BufIdx], FBuffer^, BytesToWrite);
+    // Calculate the number of bytes still to write
+    Dec(BytesToGo, BytesToWrite);
+  end;
+  // Remember our new position
+  Inc(FBufPos, BytesToWrite);
+  // Make sure the count of valid bytes is correct
+  if FBytesInBuf < FBufPos then
+    FBytesInBuf := FBufPos;
+  // Make sure the stream size is correct
+  if FSize < (FBufStart + FBytesInBuf) then
+    FSize := FBufStart + FBytesInBuf;
+  // If we're at the end of the buffer, write it out and advance to the
+  // start of the next page
+  if FBufPos = FBufSize then
+  begin
+    WriteBuffer;
+    FDirty := False;
+    Inc(FBufStart, FBufSize);
+    FBufPos := 0;
+    FBytesInBuf := 0;
+  end;
+end;
+
+{ File IO functions }
+
+function FileOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl;
+var
+  Stream: TStream;
+begin
+  Stream := nil;
+
+  case Mode of
+    omReadOnly:  Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+    omCreate:    Stream := TFileStream.Create(FileName, fmCreate);
+    omReadWrite:
+      begin
+        if FileExists(FileName) then
+          Stream := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive)
+        else
+          Stream := TFileStream.Create(FileName, fmCreate);
+      end;
+  end;
+
+  Assert(Stream <> nil);
+  Result := TBufferedStream.Create(Stream);
+end;
+
+procedure FileClose(Handle: TImagingHandle); cdecl;
+var
+  Stream: TStream;
+begin
+  Stream := TBufferedStream(Handle).Stream;
+  TBufferedStream(Handle).Free;
+  Stream.Free;
+end;
+
+function FileEof(Handle: TImagingHandle): Boolean; cdecl;
+begin
+  Result := TBufferedStream(Handle).Position = TBufferedStream(Handle).Size;
+end;
+
+function FileSeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode):
+  LongInt; cdecl;
+begin
+  Result := TBufferedStream(Handle).Seek(Offset, LongInt(Mode));
+end;
+
+function FileTell(Handle: TImagingHandle): LongInt; cdecl;
+begin
+  Result := TBufferedStream(Handle).Position;
+end;
+
+function FileRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
+  LongInt; cdecl;
+begin
+  Result := TBufferedStream(Handle).Read(Buffer^, Count);
+end;
+
+function FileWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
+  LongInt; cdecl;
+begin
+  Result := TBufferedStream(Handle).Write(Buffer^, Count);
+end;
+
+{ Stream IO functions }
+
+function StreamOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl;
+begin
+  Result := FileName;
+end;
+
+procedure StreamClose(Handle: TImagingHandle); cdecl;
+begin
+end;
+
+function StreamEof(Handle: TImagingHandle): Boolean; cdecl;
+begin
+  Result := TStream(Handle).Position = TStream(Handle).Size;
+end;
+
+function StreamSeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode):
+  LongInt; cdecl;
+begin
+  Result := TStream(Handle).Seek(Offset, LongInt(Mode));
+end;
+
+function StreamTell(Handle: TImagingHandle): LongInt; cdecl;
+begin
+  Result := TStream(Handle).Position;
+end;
+
+function StreamRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
+  LongInt; cdecl;
+begin
+  Result := TStream(Handle).Read(Buffer^, Count);
+end;
+
+function StreamWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
+  LongInt; cdecl;
+begin
+  Result := TStream(Handle).Write(Buffer^, Count);
+end;
+
+{ Memory IO functions }
+
+function MemoryOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl;
+begin
+  Result := FileName;
+end;
+
+procedure MemoryClose(Handle: TImagingHandle); cdecl;
+begin
+end;
+
+function MemoryEof(Handle: TImagingHandle): Boolean; cdecl;
+begin
+  Result := PMemoryIORec(Handle).Position = PMemoryIORec(Handle).Size;
+end;
+
+function MemorySeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode):
+  LongInt; cdecl;
+begin
+  Result := PMemoryIORec(Handle).Position;
+  case Mode of
+    smFromBeginning: Result := Offset;
+    smFromCurrent:   Result := PMemoryIORec(Handle).Position + Offset;
+    smFromEnd:       Result := PMemoryIORec(Handle).Size + Offset;
+  end;
+  //Result := ClampInt(Result, 0, PMemoryIORec(Handle).Size); don't do this - some file formats use it
+  PMemoryIORec(Handle).Position := Result;
+end;
+
+function MemoryTell(Handle: TImagingHandle): LongInt; cdecl;
+begin
+  Result := PMemoryIORec(Handle).Position;
+end;
+
+function MemoryRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
+  LongInt; cdecl;
+var
+  Rec: PMemoryIORec;
+begin
+  Rec := PMemoryIORec(Handle);
+  Result := Count;
+  if Rec.Position + Count > Rec.Size then
+    Result := Rec.Size - Rec.Position;
+  Move(Rec.Data[Rec.Position], Buffer^, Result);
+  Rec.Position := Rec.Position + Result;
+end;
+
+function MemoryWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt):
+  LongInt; cdecl;
+var
+  Rec: PMemoryIORec;
+begin
+  Rec := PMemoryIORec(Handle);
+  Result := Count;
+  if Rec.Position + Count > Rec.Size then
+    Result := Rec.Size - Rec.Position;
+  Move(Buffer^, Rec.Data[Rec.Position], Result);
+  Rec.Position := Rec.Position + Result;
+end;
+
+{ Helper IO functions }
+
+function GetInputSize(IOFunctions: TIOFunctions; Handle: TImagingHandle): LongInt;
+var
+  OldPos: Int64;
+begin
+  OldPos := IOFunctions.Tell(Handle);
+  IOFunctions.Seek(Handle, 0, smFromEnd);
+  Result := IOFunctions.Tell(Handle);
+  IOFunctions.Seek(Handle, OldPos, smFromBeginning);
+end;
+
+function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec;
+begin
+  Result.Data := Data;
+  Result.Position := 0;
+  Result.Size := Size;
+end;
+
+function ReadLine(IOFunctions: TIOFunctions; Handle: TImagingHandle;
+  out Line: AnsiString; FailOnControlChars: Boolean): Boolean;
+const
+  MaxLine = 1024;
+var
+  EolPos, Pos: Integer;
+  C: AnsiChar;
+  EolReached: Boolean;
+  Endings: set of AnsiChar;
+begin
+  Line := '';
+  Pos := 0;
+  EolPos := 0;
+  EolReached := False;
+  Endings := [#10, #13];
+  Result := True;
+
+  while not IOFunctions.Eof(Handle) do
+  begin
+    IOFunctions.Read(Handle, @C, SizeOf(C));
+
+    if FailOnControlChars and (Byte(C) < $20) then
+    begin
+      Break;
+    end;
+
+    if not (C in Endings) then
+    begin
+      if EolReached then
+      begin
+        IOFunctions.Seek(Handle, EolPos, smFromBeginning);
+        Exit;
+      end
+      else
+      begin
+        SetLength(Line, Length(Line) + 1);
+        Line[Length(Line)] := C;
+      end;
+    end
+    else if not EolReached then
+    begin
+      EolReached := True;
+      EolPos := IOFunctions.Tell(Handle);
+    end;
+
+    Inc(Pos);
+    if Pos >= MaxLine then
+    begin
+      Break;
+    end;
+  end;
+
+  Result := False;
+  IOFunctions.Seek(Handle, -Pos, smFromCurrent);
+end;
+
+procedure WriteLine(IOFunctions: TIOFunctions; Handle: TImagingHandle;
+  const Line: AnsiString; const LineEnding: AnsiString);
+var
+  ToWrite: AnsiString;
+begin
+  ToWrite := Line + LineEnding;
+  IOFunctions.Write(Handle, @ToWrite[1], Length(ToWrite));
+end;
+
+initialization
+  OriginalFileIO.Open := FileOpen;
+  OriginalFileIO.Close := FileClose;
+  OriginalFileIO.Eof := FileEof;
+  OriginalFileIO.Seek := FileSeek;
+  OriginalFileIO.Tell := FileTell;
+  OriginalFileIO.Read := FileRead;
+  OriginalFileIO.Write := FileWrite;
+
+  StreamIO.Open := StreamOpen;
+  StreamIO.Close := StreamClose;
+  StreamIO.Eof := StreamEof;
+  StreamIO.Seek := StreamSeek;
+  StreamIO.Tell := StreamTell;
+  StreamIO.Read := StreamRead;
+  StreamIO.Write := StreamWrite;
+
+  MemoryIO.Open := MemoryOpen;
+  MemoryIO.Close := MemoryClose;
+  MemoryIO.Eof := MemoryEof;
+  MemoryIO.Seek := MemorySeek;
+  MemoryIO.Tell := MemoryTell;
+  MemoryIO.Read := MemoryRead;
+  MemoryIO.Write := MemoryWrite;
+
+  ResetFileIO;
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 ---------------------------------------------------
+   - Updated IO Open functions according to changes in ImagingTypes.
+   - Added ReadLine and WriteLine functions.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added merge between buffered read-only and write-only file
+      stream adapters - TIFF saving needed both reading and writing.
+    - Fixed bug causing wrong value of TBufferedWriteFile.Size
+      (needed to add buffer pos to size).
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Removed TMemoryIORec.Written, use Position to get proper memory
+      position (Written didn't take Seeks into account).
+    - Added TBufferedReadFile and TBufferedWriteFile classes for
+      buffered file reading/writting. File IO functions now use these
+      classes resulting in performance increase mainly in file formats
+      that read/write many small chunks.
+    - Added fmShareDenyWrite to FileOpenRead. You can now read
+      files opened for reading by Imaging from other apps.
+    - Added GetInputSize and PrepareMemIO helper functions.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - changed behaviour of MemorySeek to act as TStream
+      based Seeks
+}
+end.
diff --git a/src/lib/vampimg/ImagingJpeg.pas b/src/lib/vampimg/ImagingJpeg.pas
new file mode 100644 (file)
index 0000000..ef9a5e7
--- /dev/null
@@ -0,0 +1,768 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader/saver for Jpeg images.}
+unit ImagingJpeg;
+
+{$I ImagingOptions.inc}
+
+{ You can choose which Pascal JpegLib implementation will be used.
+  IMJPEGLIB is version bundled with Imaging which works with all supported
+  compilers and platforms.
+  PASJPEG is original JpegLib translation or version modified for FPC
+  (and shipped with it). You can use PASJPEG if this version is already
+  linked with another part of your program and you don't want to have
+  two quite large almost the same libraries linked to your exe.
+  This is the case with Lazarus applications for example.}
+
+{$DEFINE IMJPEGLIB}
+{ $DEFINE PASJPEG}
+
+{ Automatically use FPC's PasJpeg when compiling with Lazarus. But not when
+  WINDOWS is defined. See http://galfar.vevb.net/imaging/smf/index.php/topic,90.0.html.
+  Fixed in FPC revision 13963: http://bugs.freepascal.org/view.php?id=14928 }
+{$IF Defined(LCL) and not Defined(WINDOWS)}
+  {$UNDEF IMJPEGLIB}
+  {$DEFINE PASJPEG}
+{$IFEND}
+
+{ We usually want to skip the rest of the corrupted file when loading JEPG files
+  instead of getting exception. JpegLib's error handler can only be
+  exited using setjmp/longjmp ("non-local goto") functions to get error
+  recovery when loading corrupted JPEG files. This is implemented in assembler
+  and currently available only for 32bit Delphi targets and FPC.}
+{$DEFINE ErrorJmpRecovery}
+{$IF Defined(DCC) and not Defined(CPUX86)}
+  {$UNDEF ErrorJmpRecovery}
+{$IFEND}
+
+interface
+
+uses
+  SysUtils, ImagingTypes, Imaging, ImagingColors,
+{$IF Defined(IMJPEGLIB)}
+  imjpeglib, imjmorecfg, imjcomapi, imjdapimin, imjdeferr, imjerror,
+  imjdapistd, imjcapimin, imjcapistd, imjdmarker, imjcparam,
+{$ELSEIF Defined(PASJPEG)}
+  jpeglib, jmorecfg, jcomapi, jdapimin, jdeferr, jerror,
+  jdapistd, jcapimin, jcapistd, jdmarker, jcparam,
+{$IFEND}
+  ImagingUtility;
+
+{$IF Defined(FPC) and Defined(PASJPEG)}
+  { When using FPC's pasjpeg in FPC the channel order is BGR instead of RGB}
+  {$DEFINE RGBSWAPPED}
+{$IFEND}
+
+type
+  { Class for loading/saving Jpeg images. Supports load/save of
+    8 bit grayscale and 24 bit RGB images. Jpegs can be saved with optional
+    progressive encoding.
+    Based on IJG's JpegLib so doesn't support alpha channels and lossless
+    coding.}
+  TJpegFileFormat = class(TImageFileFormat)
+  private
+    FGrayScale: Boolean;
+  protected
+    FQuality: LongInt;
+    FProgressive: LongBool;
+    procedure SetJpegIO(const JpegIO: TIOFunctions); virtual;
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+    procedure CheckOptionsValidity; override;
+  published
+    { Controls Jpeg save compression quality. It is number in range 1..100.
+      1 means small/ugly file, 100 means large/nice file. Accessible trough
+      ImagingJpegQuality option.}
+    property Quality: LongInt read FQuality write FQuality;
+    { If True Jpeg images are saved in progressive format. Accessible trough
+      ImagingJpegProgressive option.}
+    property Progressive: LongBool read FProgressive write FProgressive;
+  end;
+
+implementation
+
+const
+  SJpegFormatName = 'Joint Photographic Experts Group Image';
+  SJpegMasks      = '*.jpg,*.jpeg,*.jfif,*.jpe,*.jif';
+  JpegSupportedFormats: TImageFormats = [ifR8G8B8, ifGray8];
+  JpegDefaultQuality = 90;
+  JpegDefaultProgressive = False;
+
+const
+  { Jpeg file identifiers.}
+  JpegMagic: TChar2 = #$FF#$D8;
+  BufferSize = 16384;
+
+resourcestring
+  SJpegError = 'JPEG Error';
+
+type
+  TJpegContext = record
+    case Byte of
+      0: (common: jpeg_common_struct);
+      1: (d: jpeg_decompress_struct);
+      2: (c: jpeg_compress_struct);
+  end;
+
+  TSourceMgr = record
+    Pub: jpeg_source_mgr;
+    Input: TImagingHandle;
+    Buffer: JOCTETPTR;
+    StartOfFile: Boolean;
+  end;
+  PSourceMgr = ^TSourceMgr;
+
+  TDestMgr = record
+    Pub: jpeg_destination_mgr;
+    Output: TImagingHandle;
+    Buffer: JOCTETPTR;
+  end;
+  PDestMgr = ^TDestMgr;
+
+var
+  JIO: TIOFunctions;
+  JpegErrorMgr: jpeg_error_mgr;
+
+{ Intenal unit jpeglib support functions }
+
+{$IFDEF ErrorJmpRecovery}
+  {$IFDEF DCC}
+  type
+    jmp_buf = record
+      EBX,
+      ESI,
+      EDI,
+      ESP,
+      EBP,
+      EIP: LongWord;
+    end;
+    pjmp_buf = ^jmp_buf;
+
+  { JmpLib SetJmp/LongJmp Library
+    (C)Copyright 2003, 2004 Will DeWitt Jr. <edge@boink.net> }
+  function  SetJmp(out jmpb: jmp_buf): Integer;
+  asm
+  {     ->  EAX     jmpb   }
+  {     <-  EAX     Result }
+            MOV     EDX, [ESP]  // Fetch return address (EIP)
+            // Save task state
+            MOV     [EAX+jmp_buf.&EBX], EBX
+            MOV     [EAX+jmp_buf.&ESI], ESI
+            MOV     [EAX+jmp_buf.&EDI], EDI
+            MOV     [EAX+jmp_buf.&ESP], ESP
+            MOV     [EAX+jmp_buf.&EBP], EBP
+            MOV     [EAX+jmp_buf.&EIP], EDX
+
+            SUB     EAX, EAX
+  @@1:
+  end;
+
+  procedure LongJmp(const jmpb: jmp_buf; retval: Integer);
+  asm
+  {     ->  EAX     jmpb   }
+  {         EDX     retval }
+  {     <-  EAX     Result }
+            XCHG    EDX, EAX
+
+            MOV     ECX, [EDX+jmp_buf.&EIP]
+            // Restore task state
+            MOV     EBX, [EDX+jmp_buf.&EBX]
+            MOV     ESI, [EDX+jmp_buf.&ESI]
+            MOV     EDI, [EDX+jmp_buf.&EDI]
+            MOV     ESP, [EDX+jmp_buf.&ESP]
+            MOV     EBP, [EDX+jmp_buf.&EBP]
+            MOV     [ESP], ECX  // Restore return address (EIP)
+
+            TEST    EAX, EAX    // Ensure retval is <> 0
+            JNZ     @@1
+            MOV     EAX, 1
+  @@1:
+  end;
+  {$ENDIF}
+
+type
+  TJmpBuf = jmp_buf;
+  TErrorClientData = record
+    JmpBuf: TJmpBuf;
+    ScanlineReadReached: Boolean;
+  end;
+  PErrorClientData = ^TErrorClientData;
+{$ENDIF}
+
+procedure JpegError(CInfo: j_common_ptr);
+
+  procedure RaiseError;
+  var
+    Buffer: AnsiString;
+  begin
+    // Create the message and raise exception
+    CInfo.err.format_message(CInfo, Buffer);
+    // Warning: you can get "Invalid argument index in format" exception when
+    // using FPC (see http://bugs.freepascal.org/view.php?id=21229).
+    // Fixed in FPC 2.7.1
+  {$IF Defined(FPC) and (FPC_FULLVERSION <= 20701)}
+    raise EImagingError.CreateFmt(SJPEGError + ' %d', [CInfo.err.msg_code]);
+  {$ELSE}
+    raise EImagingError.CreateFmt(SJPEGError + ' %d: ' + string(Buffer), [CInfo.err.msg_code]);
+  {$IFEND}
+  end;
+
+begin
+{$IFDEF ErrorJmpRecovery}
+  // Only recovers on loads and when header is sucessfully loaded
+  // (error occurs when reading scanlines)
+  if (CInfo.client_data <> nil) and
+    PErrorClientData(CInfo.client_data).ScanlineReadReached then
+  begin
+    // Non-local jump to error handler in TJpegFileFormat.LoadData
+    longjmp(PErrorClientData(CInfo.client_data).JmpBuf, 1)
+  end
+  else
+    RaiseError;
+{$ELSE}
+  RaiseError;
+{$ENDIF}
+end;
+
+procedure OutputMessage(CurInfo: j_common_ptr);
+begin
+end;
+
+procedure ReleaseContext(var jc: TJpegContext);
+begin
+  if jc.common.err = nil then
+    Exit;
+  jpeg_destroy(@jc.common);
+  jpeg_destroy_decompress(@jc.d);
+  jpeg_destroy_compress(@jc.c);
+  jc.common.err := nil;
+end;
+
+procedure InitSource(cinfo: j_decompress_ptr);
+begin
+  PSourceMgr(cinfo.src).StartOfFile := True;
+end;
+
+function FillInputBuffer(cinfo: j_decompress_ptr): Boolean;
+var
+  NBytes: LongInt;
+  Src: PSourceMgr;
+begin
+  Src := PSourceMgr(cinfo.src);
+  NBytes := JIO.Read(Src.Input, Src.Buffer, BufferSize);
+
+  if NBytes <= 0 then
+  begin
+    PByteArray(Src.Buffer)[0] := $FF;
+    PByteArray(Src.Buffer)[1] := JPEG_EOI;
+    NBytes := 2;
+  end;
+  Src.Pub.next_input_byte := Src.Buffer;
+  Src.Pub.bytes_in_buffer := NBytes;
+  Src.StartOfFile := False;
+  Result := True;
+end;
+
+procedure SkipInputData(cinfo: j_decompress_ptr; num_bytes: LongInt);
+var
+  Src: PSourceMgr;
+begin
+  Src := PSourceMgr(cinfo.src);
+  if num_bytes > 0 then
+  begin
+    while num_bytes > Src.Pub.bytes_in_buffer do
+    begin
+      Dec(num_bytes, Src.Pub.bytes_in_buffer);
+      FillInputBuffer(cinfo);
+    end;
+    Src.Pub.next_input_byte := @PByteArray(Src.Pub.next_input_byte)[num_bytes];
+    //Inc(LongInt(Src.Pub.next_input_byte), num_bytes);
+    Dec(Src.Pub.bytes_in_buffer, num_bytes);
+  end;
+end;
+
+procedure TermSource(cinfo: j_decompress_ptr);
+var
+  Src: PSourceMgr;
+begin
+  Src := PSourceMgr(cinfo.src);
+  // Move stream position back just after EOI marker so that more that one
+  // JPEG images can be loaded from one stream
+  JIO.Seek(Src.Input, -Src.Pub.bytes_in_buffer, smFromCurrent);
+end;
+
+procedure JpegStdioSrc(var cinfo: jpeg_decompress_struct; Handle:
+  TImagingHandle);
+var
+  Src: PSourceMgr;
+begin
+  if cinfo.src = nil then
+  begin
+    cinfo.src := cinfo.mem.alloc_small(j_common_ptr(@cinfo), JPOOL_PERMANENT,
+      SizeOf(TSourceMgr));
+    Src := PSourceMgr(cinfo.src);
+    Src.Buffer := cinfo.mem.alloc_small(j_common_ptr(@cinfo), JPOOL_PERMANENT,
+      BufferSize * SizeOf(JOCTET));
+  end;
+  Src := PSourceMgr(cinfo.src);
+  Src.Pub.init_source := InitSource;
+  Src.Pub.fill_input_buffer := FillInputBuffer;
+  Src.Pub.skip_input_data := SkipInputData;
+  Src.Pub.resync_to_restart := jpeg_resync_to_restart;
+  Src.Pub.term_source := TermSource;
+  Src.Input := Handle;
+  Src.Pub.bytes_in_buffer := 0;
+  Src.Pub.next_input_byte := nil;
+end;
+
+procedure InitDest(cinfo: j_compress_ptr);
+var
+  Dest: PDestMgr;
+begin
+  Dest := PDestMgr(cinfo.dest);
+  Dest.Pub.next_output_byte := Dest.Buffer;
+  Dest.Pub.free_in_buffer := BufferSize;
+end;
+
+function EmptyOutput(cinfo: j_compress_ptr): Boolean;
+var
+  Dest: PDestMgr;
+begin
+  Dest := PDestMgr(cinfo.dest);
+  JIO.Write(Dest.Output, Dest.Buffer, BufferSize);
+  Dest.Pub.next_output_byte := Dest.Buffer;
+  Dest.Pub.free_in_buffer := BufferSize;
+  Result := True;
+end;
+
+procedure TermDest(cinfo: j_compress_ptr);
+var
+  Dest: PDestMgr;
+  DataCount: LongInt;
+begin
+  Dest := PDestMgr(cinfo.dest);
+  DataCount := BufferSize - Dest.Pub.free_in_buffer;
+  if DataCount > 0 then
+    JIO.Write(Dest.Output, Dest.Buffer, DataCount);
+end;
+
+procedure JpegStdioDest(var cinfo: jpeg_compress_struct; Handle:
+  TImagingHandle);
+var
+  Dest: PDestMgr;
+begin
+  if cinfo.dest = nil then
+    cinfo.dest := cinfo.mem.alloc_small(j_common_ptr(@cinfo),
+      JPOOL_PERMANENT, SizeOf(TDestMgr));
+  Dest := PDestMgr(cinfo.dest);
+  Dest.Buffer := cinfo.mem.alloc_small(j_common_ptr(@cinfo), JPOOL_IMAGE,
+    BufferSize * SIZEOF(JOCTET));
+  Dest.Pub.init_destination := InitDest;
+  Dest.Pub.empty_output_buffer := EmptyOutput;
+  Dest.Pub.term_destination := TermDest;
+  Dest.Output := Handle;
+end;
+
+procedure SetupErrorMgr(var jc: TJpegContext);
+begin
+  // Set standard error handlers and then override some
+  jc.common.err := jpeg_std_error(JpegErrorMgr);
+  jc.common.err.error_exit := JpegError;
+  jc.common.err.output_message := OutputMessage;
+end;
+
+procedure InitDecompressor(Handle: TImagingHandle; var jc: TJpegContext);
+begin
+  jpeg_CreateDecompress(@jc.d, JPEG_LIB_VERSION, sizeof(jc.d));
+  JpegStdioSrc(jc.d, Handle);
+  jpeg_read_header(@jc.d, True);
+  jc.d.scale_num := 1;
+  jc.d.scale_denom := 1;
+  jc.d.do_block_smoothing := True;
+  if jc.d.out_color_space = JCS_GRAYSCALE then
+  begin
+    jc.d.quantize_colors := True;
+    jc.d.desired_number_of_colors := 256;
+  end;
+end;
+
+procedure InitCompressor(Handle: TImagingHandle; var jc: TJpegContext;
+  Saver: TJpegFileFormat);
+begin
+  jpeg_CreateCompress(@jc.c, JPEG_LIB_VERSION, sizeof(jc.c));
+  JpegStdioDest(jc.c, Handle);
+  if Saver.FGrayScale then
+    jc.c.in_color_space := JCS_GRAYSCALE
+  else
+    jc.c.in_color_space := JCS_RGB;
+  jpeg_set_defaults(@jc.c);
+  jpeg_set_quality(@jc.c, Saver.FQuality, True);
+  if Saver.FProgressive then
+    jpeg_simple_progression(@jc.c);
+end;
+
+{ TJpegFileFormat class implementation }
+
+procedure TJpegFileFormat.Define;
+begin
+  FName := SJpegFormatName;
+  FFeatures := [ffLoad, ffSave];
+  FSupportedFormats := JpegSupportedFormats;
+
+  FQuality := JpegDefaultQuality;
+  FProgressive := JpegDefaultProgressive;
+
+  AddMasks(SJpegMasks);
+  RegisterOption(ImagingJpegQuality, @FQuality);
+  RegisterOption(ImagingJpegProgressive, @FProgressive);
+end;
+
+procedure TJpegFileFormat.CheckOptionsValidity;
+begin
+  // Check if option values are valid
+  if not (FQuality in [1..100]) then
+    FQuality := JpegDefaultQuality;
+end;
+
+function TJpegFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  PtrInc, LinesPerCall, LinesRead, I: Integer;
+  Dest: PByte;
+  jc: TJpegContext;
+  Info: TImageFormatInfo;
+  Col32: PColor32Rec;
+  NeedsRedBlueSwap: Boolean;
+  Pix: PColor24Rec;
+{$IFDEF ErrorJmpRecovery}
+  ErrorClient: TErrorClientData;
+{$ENDIF}
+
+  procedure LoadMetaData;
+  var
+    XDensity, YDensity: Single;
+    ResUnit: TResolutionUnit;
+  begin
+    // Density unit: 0 - undef, 1 - inch, 2 - cm
+    if jc.d.saw_JFIF_marker and (jc.d.density_unit > 0) and
+      (jc.d.X_density > 0) and (jc.d.Y_density > 0) then
+    begin
+      XDensity := jc.d.X_density;
+      YDensity := jc.d.Y_density;
+      ResUnit := ruDpi;
+      if jc.d.density_unit = 2 then
+        ResUnit := ruDpcm;
+      FMetadata.SetPhysicalPixelSize(ResUnit, XDensity, YDensity);
+    end;
+  end;
+
+begin
+  // Copy IO functions to global var used in JpegLib callbacks
+  Result := False;
+  SetJpegIO(GetIO);
+  SetLength(Images, 1);
+
+  with JIO, Images[0] do
+  try
+    ZeroMemory(@jc, SizeOf(jc));
+    SetupErrorMgr(jc);
+  {$IFDEF ErrorJmpRecovery}
+    ZeroMemory(@ErrorClient, SizeOf(ErrorClient));
+    jc.common.client_data := @ErrorClient;
+    if setjmp(ErrorClient.JmpBuf) <> 0 then
+    begin
+      Result := True;
+      Exit;
+    end;
+  {$ENDIF}
+    InitDecompressor(Handle, jc);
+
+    case jc.d.out_color_space of
+      JCS_GRAYSCALE: Format := ifGray8;
+      JCS_RGB:       Format := ifR8G8B8;
+      JCS_CMYK:      Format := ifA8R8G8B8;
+    else
+      Exit;
+    end;
+
+    NewImage(jc.d.image_width, jc.d.image_height, Format, Images[0]);
+    jpeg_start_decompress(@jc.d);
+    GetImageFormatInfo(Format, Info);
+    PtrInc := Width * Info.BytesPerPixel;
+    LinesPerCall := 1;
+    Dest := Bits;
+
+    // If Jpeg's colorspace is RGB and not YCbCr we need to swap
+    // R and B to get Imaging's native order
+    NeedsRedBlueSwap := jc.d.jpeg_color_space = JCS_RGB;
+  {$IFDEF RGBSWAPPED}
+    // Force R-B swap for FPC's PasJpeg
+    NeedsRedBlueSwap := True;
+  {$ENDIF}
+
+  {$IFDEF ErrorJmpRecovery}
+    ErrorClient.ScanlineReadReached := True;
+  {$ENDIF}
+
+    while jc.d.output_scanline < jc.d.output_height do
+    begin
+      LinesRead := jpeg_read_scanlines(@jc.d, @Dest, LinesPerCall);
+      if NeedsRedBlueSwap and (Format = ifR8G8B8) then
+      begin
+        Pix := PColor24Rec(Dest);
+        for I := 0 to Width - 1 do
+        begin
+          SwapValues(Pix.R, Pix.B);
+          Inc(Pix);
+        end;
+      end;
+      Inc(Dest, PtrInc * LinesRead);
+    end;
+
+    if jc.d.out_color_space = JCS_CMYK then
+    begin
+      Col32 := Bits;
+      // Translate from CMYK to RGB
+      for I := 0 to Width * Height - 1 do
+      begin
+        CMYKToRGB(255 - Col32.B, 255 - Col32.G, 255 - Col32.R, 255 - Col32.A,
+          Col32.R, Col32.G, Col32.B);
+        Col32.A := 255;
+        Inc(Col32);
+      end;
+    end;
+
+    // Store supported metadata
+    LoadMetaData;
+
+    jpeg_finish_output(@jc.d);
+    jpeg_finish_decompress(@jc.d);
+    Result := True;
+  finally
+    ReleaseContext(jc);
+  end;
+end;
+
+function TJpegFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+var
+  PtrInc, LinesWritten: LongInt;
+  Src, Line: PByte;
+  jc: TJpegContext;
+  ImageToSave: TImageData;
+  Info: TImageFormatInfo;
+  MustBeFreed: Boolean;
+{$IFDEF RGBSWAPPED}
+  I: LongInt;
+  Pix: PColor24Rec;
+{$ENDIF}
+
+  procedure SaveMetaData;
+  var
+    XRes, YRes: Single;
+  begin
+    if FMetadata.GetPhysicalPixelSize(ruDpcm, XRes, YRes, True) then
+    begin
+      jc.c.density_unit := 2; // Dots per cm
+      jc.c.X_density := Round(XRes);
+      jc.c.Y_density := Round(YRes)
+    end;
+  end;
+
+begin
+  Result := False;
+  // Copy IO functions to global var used in JpegLib callbacks
+  SetJpegIO(GetIO);
+
+  // Makes image to save compatible with Jpeg saving capabilities
+  if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
+  with JIO, ImageToSave do
+  try
+    ZeroMemory(@jc, SizeOf(jc));
+    SetupErrorMgr(jc);
+
+    GetImageFormatInfo(Format, Info);
+    FGrayScale := Format = ifGray8;
+    InitCompressor(Handle, jc, Self);
+    jc.c.image_width := Width;
+    jc.c.image_height := Height;
+    if FGrayScale then
+    begin
+      jc.c.input_components := 1;
+      jc.c.in_color_space := JCS_GRAYSCALE;
+    end
+    else
+    begin
+      jc.c.input_components := 3;
+      jc.c.in_color_space := JCS_RGB;
+    end;
+
+    PtrInc := Width * Info.BytesPerPixel;
+    Src := Bits;
+
+  {$IFDEF RGBSWAPPED}
+    GetMem(Line, PtrInc);
+  {$ENDIF}
+
+    // Save supported metadata
+    SaveMetaData;
+
+    jpeg_start_compress(@jc.c, True);
+    while (jc.c.next_scanline < jc.c.image_height) do
+    begin
+    {$IFDEF RGBSWAPPED}
+      if Format = ifR8G8B8 then
+      begin
+        Move(Src^, Line^, PtrInc);
+        Pix := PColor24Rec(Line);
+        for I := 0 to Width - 1 do
+        begin
+          SwapValues(Pix.R, Pix.B);
+          Inc(Pix, 1);
+        end;
+      end;
+    {$ELSE}
+      Line := Src;
+    {$ENDIF}
+
+      LinesWritten := jpeg_write_scanlines(@jc.c, @Line, 1);
+      Inc(Src, PtrInc * LinesWritten);
+    end;
+
+    jpeg_finish_compress(@jc.c);
+    Result := True;
+  finally
+    ReleaseContext(jc);
+    if MustBeFreed then
+      FreeImage(ImageToSave);
+  {$IFDEF RGBSWAPPED}
+    FreeMem(Line);
+  {$ENDIF}
+  end;
+end;
+
+procedure TJpegFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+begin
+  if Info.HasGrayChannel then
+    ConvertImage(Image, ifGray8)
+  else
+    ConvertImage(Image, ifR8G8B8);
+end;
+
+function TJpegFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  ReadCount: LongInt;
+  ID: array[0..9] of AnsiChar;
+begin
+  Result := False;
+  if Handle <> nil then
+  with GetIO do
+  begin
+    FillChar(ID, SizeOf(ID), 0);
+    ReadCount := Read(Handle, @ID, SizeOf(ID));
+    Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (ReadCount = SizeOf(ID)) and
+      CompareMem(@ID, @JpegMagic, SizeOf(JpegMagic));
+  end;
+end;
+
+procedure TJpegFileFormat.SetJpegIO(const JpegIO: TIOFunctions);
+begin
+  JIO := JpegIO;
+end;
+
+initialization
+  RegisterImageFileFormat(TJpegFileFormat);
+
+{
+  File Notes:
+
+ -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 ---------------------------------------------------
+    - Able to read corrupted JPEG files - loads partial image
+      and skips the corrupted parts (FPC and x86 Delphi).
+    - Fixed reading of physical resolution metadata, could cause
+      "divided by zero" later on for some files.
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Fixed loading of some JPEGs with certain APPN markers (bug in JpegLib).
+    - Fixed swapped Red-Blue order when loading Jpegs with
+      jc.d.jpeg_color_space = JCS_RGB.
+    - Added loading and saving of physical pixel size metadata.
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Changed the Jpeg error manager, messages were not properly formated.
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - Fixed wrong color space setting in InitCompressor.
+    - Fixed problem with progressive Jpegs in FPC (modified JpegLib,
+      can't use FPC's PasJpeg in Windows).
+
+  -- 0.25.0 Changes/Bug Fixes ---------------------------------
+    - FPC's PasJpeg wasn't really used in last version, fixed.
+
+  -- 0.24.1 Changes/Bug Fixes ---------------------------------
+    - Fixed loading of CMYK jpeg images. Could cause heap corruption
+      and loaded image looked wrong.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Removed JFIF/EXIF detection from TestFormat. Found JPEGs
+      with different headers (Lavc) which weren't recognized.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - MakeCompatible method moved to base class, put ConvertToSupported here.
+      GetSupportedFormats removed, it is now set in constructor.
+    - Made public properties for options registered to SetOption/GetOption
+      functions.
+    - Changed extensions to filename masks.
+    - Changed SaveData, LoadData, and MakeCompatible methods according
+      to changes in base class in Imaging unit.
+    - Changes in TestFormat, now reads JFIF and EXIF signatures too.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - input position is now set correctly to the end of the image
+      after loading is done. Loading of sequence of JPEG files stored in
+      single stream works now
+    - when loading and saving images in FPC with PASJPEG read and
+      blue channels are swapped to have the same chanel order as IMJPEGLIB
+    - you can now choose between IMJPEGLIB and PASJPEG implementations
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - added SetJpegIO method which is used by JNG image format
+}
+end.
diff --git a/src/lib/vampimg/ImagingNetworkGraphics.pas b/src/lib/vampimg/ImagingNetworkGraphics.pas
new file mode 100644 (file)
index 0000000..364cbcf
--- /dev/null
@@ -0,0 +1,2695 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loaders/savers for Network Graphics image
+  file formats PNG, MNG, and JNG.}
+unit ImagingNetworkGraphics;
+
+interface
+
+{$I ImagingOptions.inc}
+
+{ If MNG support is enabled we must make sure PNG and JNG are enabled too.}
+{$IFNDEF DONT_LINK_MNG}
+  {$UNDEF DONT_LINK_PNG}
+  {$UNDEF DONT_LINK_JNG}
+{$ENDIF}
+
+uses
+  Types, SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility, ImagingFormats, dzlib;
+
+type
+  { Basic class for Network Graphics file formats loaders/savers.}
+  TNetworkGraphicsFileFormat = class(TImageFileFormat)
+  protected
+    FSignature: TChar8;
+    FPreFilter: LongInt;
+    FCompressLevel: LongInt;
+    FLossyCompression: LongBool;
+    FLossyAlpha: LongBool;
+    FQuality: LongInt;
+    FProgressive: LongBool;
+    FZLibStategy: Integer;
+    function GetSupportedFormats: TImageFormats; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+    procedure Define; override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+    procedure CheckOptionsValidity; override;
+  published
+    { Sets precompression filter used when saving images with lossless compression.
+      Allowed values are: 0 (none), 1 (sub), 2 (up), 3 (average), 4 (paeth),
+      5 (use 0 for indexed/gray images and 4 for RGB/ARGB images),
+      6 (adaptive filtering - use best filter for each scanline - very slow).
+      Note that filters 3 and 4 are much slower than filters 1 and 2.
+      Default value is 5.}
+    property PreFilter: LongInt read FPreFilter write FPreFilter;
+    { Sets ZLib compression level used when saving images with lossless compression.
+      Allowed values are in range 0 (no compresstion) to 9 (best compression).
+      Default value is 5.}
+    property CompressLevel: LongInt read FCompressLevel write FCompressLevel;
+    { Specifies whether MNG animation frames are saved with lossy or lossless
+      compression. Lossless frames are saved as PNG images and lossy frames are
+      saved as JNG images. Allowed values are 0 (False) and 1 (True).
+      Default value is 0.}
+    property LossyCompression: LongBool read FLossyCompression write FLossyCompression;
+    { Defines whether alpha channel of lossy MNG frames or JNG images
+      is lossy compressed too. Allowed values are 0 (False) and 1 (True).
+      Default value is 0.}
+    property LossyAlpha: LongBool read FLossyAlpha write FLossyAlpha;
+    { Specifies compression quality used when saving lossy MNG frames or JNG images.
+      For details look at ImagingJpegQuality option.}
+    property Quality: LongInt read FQuality write FQuality;
+    { Specifies whether images are saved in progressive format when saving lossy
+      MNG frames or JNG images. For details look at ImagingJpegProgressive.}
+    property Progressive: LongBool read FProgressive write FProgressive;
+  end;
+
+  { Class for loading Portable Network Graphics Images.
+    Loads all types of this image format (all images in png test suite)
+    and saves all types with bitcount >= 8 (non-interlaced only).
+    Compression level and  filtering can be set by options interface.
+
+    Supported ancillary chunks (loading):
+    tRNS, bKGD
+    (for indexed images transparency contains alpha values for palette,
+    RGB/Gray images with transparency are converted to formats with alpha
+    and pixels with transparent color are replaced with background color
+    with alpha = 0).}
+  TPNGFileFormat = class(TNetworkGraphicsFileFormat)
+  private
+    FLoadAnimated: LongBool;
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+  published
+    property LoadAnimated: LongBool read FLoadAnimated write FLoadAnimated;
+  end;
+
+{$IFNDEF DONT_LINK_MNG}
+  { Class for loading Multiple Network Graphics files.
+    This format has complex animation capabilities but Imaging only
+    extracts frames. Individual frames are stored as standard PNG or JNG
+    images. Loads all types of these frames stored in IHDR-IEND and
+    JHDR-IEND streams (Note that there are MNG chunks
+    like BASI which define images but does not contain image data itself,
+    those are ignored).
+    Imaging saves MNG files as MNG-VLC (very low complexity) so it is basicaly
+    an array of image frames without MNG animation chunks. Frames can be saved
+    as lossless PNG or lossy JNG images (look at TPNGFileFormat and
+    TJNGFileFormat for info). Every frame can be in different data format.
+
+    Many frame compression settings can be modified by options interface.}
+  TMNGFileFormat = class(TNetworkGraphicsFileFormat)
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+  end;
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_JNG}
+  { Class for loading JPEG Network Graphics Images.
+    Loads all types of this image format (all images in jng test suite)
+    and saves all types except 12 bit JPEGs.
+    Alpha channel in JNG images is stored separately from color/gray data and
+    can be lossy (as JPEG image) or lossless (as PNG image) compressed.
+    Type of alpha compression, compression level and quality,
+    and filtering can be set by options interface.
+
+    Supported ancillary chunks (loading):
+    tRNS, bKGD
+    (Images with transparency are converted to formats with alpha
+    and pixels with transparent color are replaced with background color
+    with alpha = 0).}
+  TJNGFileFormat = class(TNetworkGraphicsFileFormat)
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+  end;
+{$ENDIF}
+
+
+implementation
+
+uses
+{$IFNDEF DONT_LINK_JNG}
+  ImagingJpeg, ImagingIO,
+{$ENDIF}
+  ImagingCanvases;
+
+const
+  NGDefaultPreFilter = 5;
+  NGDefaultCompressLevel = 5;
+  NGDefaultLossyAlpha = False;
+  NGDefaultLossyCompression = False;
+  NGDefaultProgressive = False;
+  NGDefaultQuality = 90;
+  NGLosslessFormats: TImageFormats = [ifIndex8, ifGray8, ifA8Gray8, ifGray16,
+    ifA16Gray16, ifR8G8B8, ifA8R8G8B8, ifR16G16B16, ifA16R16G16B16, ifB16G16R16,
+    ifA16B16G16R16, ifBinary];
+  NGLossyFormats: TImageFormats = [ifGray8, ifA8Gray8, ifR8G8B8, ifA8R8G8B8];
+  PNGDefaultLoadAnimated = True;
+  NGDefaultZLibStartegy = 1; // Z_FILTERED
+
+  SPNGFormatName = 'Portable Network Graphics';
+  SPNGMasks      = '*.png';
+  SMNGFormatName = 'Multiple Network Graphics';
+  SMNGMasks      = '*.mng';
+  SJNGFormatName = 'JPEG Network Graphics';
+  SJNGMasks      = '*.jng';
+
+resourcestring
+  SErrorLoadingChunk = 'Error when reading %s chunk data. File may be corrupted.';
+
+type
+  { Chunk header.}
+  TChunkHeader = packed record
+    DataSize: LongWord;
+    ChunkID: TChar4;
+  end;
+
+  { IHDR chunk format - PNG header.}
+  TIHDR = packed record
+    Width: LongWord;              // Image width
+    Height: LongWord;             // Image height
+    BitDepth: Byte;               // Bits per pixel or bits per sample (for truecolor)
+    ColorType: Byte;              // 0 = grayscale, 2 = truecolor, 3 = palette,
+                                  // 4 = gray + alpha, 6 = truecolor + alpha
+    Compression: Byte;            // Compression type:  0 = ZLib
+    Filter: Byte;                 // Used precompress filter
+    Interlacing: Byte;            // Used interlacing: 0 = no int, 1 = Adam7
+  end;
+  PIHDR = ^TIHDR;
+
+  { MHDR chunk format - MNG header.}
+  TMHDR = packed record
+    FrameWidth: LongWord;         // Frame width
+    FrameHeight: LongWord;        // Frame height
+    TicksPerSecond: LongWord;     // FPS of animation
+    NominalLayerCount: LongWord;  // Number of layers in file
+    NominalFrameCount: LongWord;  // Number of frames in file
+    NominalPlayTime: LongWord;    // Play time of animation in ticks
+    SimplicityProfile: LongWord;  // Defines which MNG features are used in this file
+  end;
+  PMHDR = ^TMHDR;
+
+  { JHDR chunk format - JNG header.}
+  TJHDR = packed record
+    Width: LongWord;              // Image width
+    Height: LongWord;             // Image height
+    ColorType: Byte;              // 8 = grayscale (Y), 10 = color (YCbCr),
+                                  // 12 = gray + alpha (Y-alpha), 14 = color + alpha (YCbCr-alpha)
+    SampleDepth: Byte;            // 8, 12 or 20 (8 and 12 samples together) bit
+    Compression: Byte;            // Compression type:  8 = Huffman coding
+    Interlacing: Byte;            // 0 = single scan, 8 = progressive
+    AlphaSampleDepth: Byte;       // 0, 1, 2, 4, 8, 16 if alpha compression is 0 (PNG)
+                                  // 8 if alpha compression is 8 (JNG)
+    AlphaCompression: Byte;       // 0 = PNG graysscale IDAT, 8 = grayscale 8-bit JPEG
+    AlphaFilter: Byte;            // 0 = PNG filter or no filter (JPEG)
+    AlphaInterlacing: Byte;       // 0 = non interlaced
+  end;
+  PJHDR = ^TJHDR;
+
+  { acTL chunk format - APNG animation control.}
+  TacTL = packed record
+    NumFrames: LongWord;          // Number of frames
+    NumPlay: LongWord;            // Number of times to loop the animation (0 = inf)
+  end;
+  PacTL =^TacTL;
+
+  { fcTL chunk format - APNG frame control.}
+  TfcTL = packed record
+    SeqNumber: LongWord;          // Sequence number of the animation chunk, starting from 0
+    Width: LongWord;              // Width of the following frame
+    Height: LongWord;             // Height of the following frame
+    XOffset: LongWord;            // X position at which to render the following frame
+    YOffset: LongWord;            // Y position at which to render the following frame
+    DelayNumer: Word;             // Frame delay fraction numerator
+    DelayDenom: Word;             // Frame delay fraction denominator
+    DisposeOp: Byte;              // Type of frame area disposal to be done after rendering this frame
+    BlendOp: Byte;                // Type of frame area rendering for this frame
+  end;
+  PfcTL = ^TfcTL;
+
+  { pHYs chunk format - encodes the absolute or relative dimensions of pixels.}
+  TpHYs = packed record
+    PixelsPerUnitX: LongWord;
+    PixelsPerUnitY: LongWord;
+    UnitSpecifier: Byte;
+  end;
+  PpHYs = ^TpHYs;
+
+const
+  { PNG file identifier.}
+  PNGSignature: TChar8 = #$89'PNG'#$0D#$0A#$1A#$0A;
+  { MNG file identifier.}
+  MNGSignature: TChar8 = #$8A'MNG'#$0D#$0A#$1A#$0A;
+  { JNG file identifier.}
+  JNGSignature: TChar8 = #$8B'JNG'#$0D#$0A#$1A#$0A;
+
+  { Constants for chunk identifiers and signature identifiers.
+    They are in big-endian format.}
+  IHDRChunk: TChar4 = 'IHDR';
+  IENDChunk: TChar4 = 'IEND';
+  MHDRChunk: TChar4 = 'MHDR';
+  MENDChunk: TChar4 = 'MEND';
+  JHDRChunk: TChar4 = 'JHDR';
+  IDATChunk: TChar4 = 'IDAT';
+  JDATChunk: TChar4 = 'JDAT';
+  JDAAChunk: TChar4 = 'JDAA';
+  JSEPChunk: TChar4 = 'JSEP';
+  PLTEChunk: TChar4 = 'PLTE';
+  BACKChunk: TChar4 = 'BACK';
+  DEFIChunk: TChar4 = 'DEFI';
+  TERMChunk: TChar4 = 'TERM';
+  tRNSChunk: TChar4 = 'tRNS';
+  bKGDChunk: TChar4 = 'bKGD';
+  gAMAChunk: TChar4 = 'gAMA';
+  acTLChunk: TChar4 = 'acTL';
+  fcTLChunk: TChar4 = 'fcTL';
+  fdATChunk: TChar4 = 'fdAT';
+  pHYsChunk: TChar4 = 'pHYs';
+
+  { APNG frame dispose operations.}
+  DisposeOpNone       = 0;
+  DisposeOpBackground = 1;
+  DisposeOpPrevious   = 2;
+
+  { APNG frame blending modes}
+  BlendOpSource = 0;
+  BlendOpOver   = 1;
+
+  { Interlace start and offsets.}
+  RowStart: array[0..6] of LongInt = (0, 0, 4, 0, 2, 0, 1);
+  ColumnStart: array[0..6] of LongInt = (0, 4, 0, 2, 0, 1, 0);
+  RowIncrement: array[0..6] of LongInt = (8, 8, 8, 4, 4, 2, 2);
+  ColumnIncrement: array[0..6] of LongInt = (8, 8, 4, 4, 2, 2, 1);
+
+type
+  { Helper class that holds information about MNG frame in PNG or JNG format.}
+  TFrameInfo = class
+  public
+    Index: Integer;
+    FrameWidth, FrameHeight: LongInt;
+    IsJpegFrame: Boolean;
+    IHDR: TIHDR;
+    JHDR: TJHDR;
+    fcTL: TfcTL;
+    pHYs: TpHYs;
+    Palette: PPalette24;
+    PaletteEntries: LongInt;
+    Transparency: Pointer;
+    TransparencySize: LongInt;
+    Background: Pointer;
+    BackgroundSize: LongInt;
+    IDATMemory: TMemoryStream;
+    JDATMemory: TMemoryStream;
+    JDAAMemory: TMemoryStream;
+    constructor Create(AIndex: Integer);
+    destructor Destroy; override;
+    procedure AssignSharedProps(Source: TFrameInfo);
+  end;
+
+  { Defines type of Network Graphics file.}
+  TNGFileType = (ngPNG, ngAPNG, ngMNG, ngJNG);
+
+  TNGFileHandler = class
+  public
+    FileFormat: TNetworkGraphicsFileFormat;
+    FileType: TNGFileType;
+    Frames: array of TFrameInfo;
+    MHDR: TMHDR; // Main header for MNG files
+    acTL: TacTL; // Global anim control for APNG files
+    GlobalPalette: PPalette24;
+    GlobalPaletteEntries: LongInt;
+    GlobalTransparency: Pointer;
+    GlobalTransparencySize: LongInt;
+    constructor Create(AFileFormat: TNetworkGraphicsFileFormat);
+    destructor Destroy; override;
+    procedure Clear;
+    function GetLastFrame: TFrameInfo;
+    function AddFrameInfo: TFrameInfo;
+    procedure LoadMetaData;
+  end;
+
+  { Network Graphics file parser and frame converter.}
+  TNGFileLoader = class(TNGFileHandler)
+  public
+    function LoadFile(Handle: TImagingHandle): Boolean;
+    procedure LoadImageFromPNGFrame(FrameWidth, FrameHeight: LongInt; const IHDR: TIHDR; IDATStream: TMemoryStream; var Image: TImageData);
+{$IFNDEF DONT_LINK_JNG}
+    procedure LoadImageFromJNGFrame(FrameWidth, FrameHeight: LongInt; const JHDR: TJHDR; IDATStream, JDATStream, JDAAStream: TMemoryStream; var Image: TImageData);
+{$ENDIF}
+    procedure ApplyFrameSettings(Frame: TFrameInfo; var Image: TImageData);
+  end;
+
+  TNGFileSaver = class(TNGFileHandler)
+  public
+    PreFilter: LongInt;
+    CompressLevel: LongInt;
+    LossyAlpha: Boolean;
+    Quality: LongInt;
+    Progressive: Boolean;
+    ZLibStrategy: Integer;
+    function SaveFile(Handle: TImagingHandle): Boolean;
+    procedure AddFrame(const Image: TImageData; IsJpegFrame: Boolean);
+    procedure StoreImageToPNGFrame(const IHDR: TIHDR; Bits: Pointer; FmtInfo: TImageFormatInfo; IDATStream: TMemoryStream);
+{$IFNDEF DONT_LINK_JNG}
+    procedure StoreImageToJNGFrame(const JHDR: TJHDR; const Image: TImageData; IDATStream, JDATStream, JDAAStream: TMemoryStream);
+{$ENDIF}
+    procedure SetFileOptions;
+  end;
+
+{$IFNDEF DONT_LINK_JNG}
+  TCustomIOJpegFileFormat = class(TJpegFileFormat)
+  protected
+    FCustomIO: TIOFunctions;
+    procedure SetJpegIO(const JpegIO: TIOFunctions); override;
+    procedure SetCustomIO(const CustomIO: TIOFunctions);
+  end;
+{$ENDIF}
+
+  TAPNGAnimator = class
+  public
+    class procedure Animate(var Images: TDynImageDataArray; const acTL: TacTL; const SrcFrames: array of TFrameInfo);
+  end;
+
+{ Helper routines }
+
+function PaethPredictor(A, B, C: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+var
+  P, PA, PB, PC: LongInt;
+begin
+  P := A + B - C;
+  PA := Abs(P - A);
+  PB := Abs(P - B);
+  PC := Abs(P - C);
+  if (PA <= PB) and (PA <= PC) then
+    Result := A
+  else
+    if PB <= PC then
+      Result := B
+    else
+      Result := C;
+end;
+
+procedure SwapRGB(Line: PByte; Width, SampleDepth, BytesPerPixel: LongInt);
+var
+  I: LongInt;
+  Tmp: Word;
+begin
+  case SampleDepth of
+    8:
+      for I := 0 to Width - 1 do
+      with PColor24Rec(Line)^ do
+      begin
+        Tmp := R;
+        R := B;
+        B := Tmp;
+        Inc(Line, BytesPerPixel);
+      end;
+    16:
+      for I := 0 to Width - 1 do
+      with PColor48Rec(Line)^ do
+      begin
+        Tmp := R;
+        R := B;
+        B := Tmp;
+        Inc(Line, BytesPerPixel);
+      end;
+    end;
+ end;
+
+{$IFNDEF DONT_LINK_JNG}
+
+{ TCustomIOJpegFileFormat class implementation }
+
+procedure TCustomIOJpegFileFormat.SetCustomIO(const CustomIO: TIOFunctions);
+begin
+  FCustomIO := CustomIO;
+end;
+
+procedure TCustomIOJpegFileFormat.SetJpegIO(const JpegIO: TIOFunctions);
+begin
+  inherited SetJpegIO(FCustomIO);
+end;
+
+{$ENDIF}
+
+{ TFrameInfo class implementation }
+
+constructor TFrameInfo.Create(AIndex: Integer);
+begin
+  Index := AIndex;
+  IDATMemory := TMemoryStream.Create;
+  JDATMemory := TMemoryStream.Create;
+  JDAAMemory := TMemoryStream.Create;
+end;
+
+destructor TFrameInfo.Destroy;
+begin
+  FreeMem(Palette);
+  FreeMem(Transparency);
+  FreeMem(Background);
+  IDATMemory.Free;
+  JDATMemory.Free;
+  JDAAMemory.Free;
+  inherited Destroy;
+end;
+
+procedure TFrameInfo.AssignSharedProps(Source: TFrameInfo);
+begin
+  IHDR := Source.IHDR;
+  JHDR := Source.JHDR;
+  PaletteEntries := Source.PaletteEntries;
+  GetMem(Palette, PaletteEntries * SizeOf(TColor24Rec));
+  Move(Source.Palette^, Palette^, PaletteEntries * SizeOf(TColor24Rec));
+  TransparencySize := Source.TransparencySize;
+  GetMem(Transparency, TransparencySize);
+  Move(Source.Transparency^, Transparency^, TransparencySize);
+end;
+
+{ TNGFileHandler class implementation}
+
+destructor TNGFileHandler.Destroy;
+begin
+  Clear;
+  inherited Destroy;
+end;
+
+procedure TNGFileHandler.Clear;
+var
+  I: LongInt;
+begin
+  for I := 0 to Length(Frames) - 1 do
+    Frames[I].Free;
+  SetLength(Frames, 0);
+  FreeMemNil(GlobalPalette);
+  GlobalPaletteEntries := 0;
+  FreeMemNil(GlobalTransparency);
+  GlobalTransparencySize := 0;
+end;
+
+constructor TNGFileHandler.Create(AFileFormat: TNetworkGraphicsFileFormat);
+begin
+  FileFormat := AFileFormat;
+end;
+
+function TNGFileHandler.GetLastFrame: TFrameInfo;
+var
+  Len: LongInt;
+begin
+  Len := Length(Frames);
+  if Len > 0 then
+    Result := Frames[Len - 1]
+  else
+    Result := nil;
+end;
+
+procedure TNGFileHandler.LoadMetaData;
+var
+  I: Integer;
+  Delay, Denom: Integer;
+begin
+  if FileType = ngAPNG then
+  begin
+    // Num plays of APNG animation
+    FileFormat.FMetadata.SetMetaItem(SMetaAnimationLoops, acTL.NumPlay);
+  end;
+
+  for I := 0 to High(Frames) do
+  begin
+    if Frames[I].pHYs.UnitSpecifier = 1 then
+    begin
+      // Store physical pixel dimensions, in PNG stored as pixels per meter DPM
+      FileFormat.FMetadata.SetPhysicalPixelSize(ruDpm, Frames[I].pHYs.PixelsPerUnitX,
+        Frames[I].pHYs.PixelsPerUnitY);
+    end;
+    if FileType = ngAPNG then
+    begin
+      // Store frame delay of APNG file frame
+      Denom := Frames[I].fcTL.DelayDenom;
+      if Denom = 0 then
+        Denom := 100;
+      Delay := Round(1000 * (Frames[I].fcTL.DelayNumer / Denom));
+      FileFormat.FMetadata.SetMetaItem(SMetaFrameDelay, Delay, I);
+    end;
+  end;
+end;
+
+function TNGFileHandler.AddFrameInfo: TFrameInfo;
+var
+  Len: LongInt;
+begin
+  Len := Length(Frames);
+  SetLength(Frames, Len + 1);
+  Result := TFrameInfo.Create(Len);
+  Frames[Len] := Result;
+end;
+
+{ TNGFileLoader class implementation}
+
+function TNGFileLoader.LoadFile(Handle: TImagingHandle): Boolean;
+var
+  Sig: TChar8;
+  Chunk: TChunkHeader;
+  ChunkData: Pointer;
+  ChunkCrc: LongWord;
+
+  procedure ReadChunk;
+  begin
+    GetIO.Read(Handle, @Chunk, SizeOf(Chunk));
+    Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize);
+  end;
+
+  procedure ReadChunkData;
+  var
+    ReadBytes: LongWord;
+  begin
+    FreeMemNil(ChunkData);
+    GetMem(ChunkData, Chunk.DataSize);
+    ReadBytes := GetIO.Read(Handle, ChunkData, Chunk.DataSize);
+    GetIO.Read(Handle, @ChunkCrc, SizeOf(ChunkCrc));
+    if ReadBytes <> Chunk.DataSize then
+      RaiseImaging(SErrorLoadingChunk, [string(Chunk.ChunkID)]);
+  end;
+
+  procedure SkipChunkData;
+  begin
+    GetIO.Seek(Handle, Chunk.DataSize + SizeOf(ChunkCrc), smFromCurrent);
+  end;
+
+  procedure StartNewPNGImage;
+  var
+    Frame: TFrameInfo;
+  begin
+    ReadChunkData;
+
+    if Chunk.ChunkID = fcTLChunk then
+    begin
+      if (Length(Frames) = 1) and (Frames[0].IDATMemory.Size = 0) then
+      begin
+        // First fcTL chunk maybe for first IDAT frame which is alredy created
+        Frame := Frames[0];
+      end
+      else
+      begin
+        // Subsequent APNG frames with data in fdAT
+        Frame := AddFrameInfo;
+        // Copy some shared props from first frame (IHDR is the same for all APNG frames, palette etc)
+        Frame.AssignSharedProps(Frames[0]);
+      end;
+      Frame.fcTL := PfcTL(ChunkData)^;
+      SwapEndianLongWord(@Frame.fcTL, 5);
+      Frame.fcTL.DelayNumer := SwapEndianWord(Frame.fcTL.DelayNumer);
+      Frame.fcTL.DelayDenom := SwapEndianWord(Frame.fcTL.DelayDenom);
+      Frame.FrameWidth := Frame.fcTL.Width;
+      Frame.FrameHeight := Frame.fcTL.Height;
+    end
+    else
+    begin
+      // This is frame defined by IHDR chunk
+      Frame := AddFrameInfo;
+      Frame.IHDR := PIHDR(ChunkData)^;
+      SwapEndianLongWord(@Frame.IHDR, 2);
+      Frame.FrameWidth := Frame.IHDR.Width;
+      Frame.FrameHeight := Frame.IHDR.Height;
+    end;
+    Frame.IsJpegFrame := False;
+  end;
+
+  procedure StartNewJNGImage;
+  var
+    Frame: TFrameInfo;
+  begin
+    ReadChunkData;
+    Frame := AddFrameInfo;
+    Frame.IsJpegFrame := True;
+    Frame.JHDR := PJHDR(ChunkData)^;
+    SwapEndianLongWord(@Frame.JHDR, 2);
+    Frame.FrameWidth := Frame.JHDR.Width;
+    Frame.FrameHeight := Frame.JHDR.Height;
+  end;
+
+  procedure AppendIDAT;
+  begin
+    ReadChunkData;
+    // Append current IDAT/fdAT chunk to storage stream
+    if Chunk.ChunkID = IDATChunk then
+      GetLastFrame.IDATMemory.Write(ChunkData^, Chunk.DataSize)
+    else if Chunk.ChunkID = fdATChunk then
+      GetLastFrame.IDATMemory.Write(PByteArray(ChunkData)[4], Chunk.DataSize - SizeOf(LongWord));
+  end;
+
+  procedure AppendJDAT;
+  begin
+    ReadChunkData;
+    // Append current JDAT chunk to storage stream
+    GetLastFrame.JDATMemory.Write(ChunkData^, Chunk.DataSize);
+  end;
+
+  procedure AppendJDAA;
+  begin
+    ReadChunkData;
+    // Append current JDAA chunk to storage stream
+    GetLastFrame.JDAAMemory.Write(ChunkData^, Chunk.DataSize);
+  end;
+
+  procedure LoadPLTE;
+  begin
+    ReadChunkData;
+    if GetLastFrame = nil then
+    begin
+      // Load global palette
+      GetMem(GlobalPalette, Chunk.DataSize);
+      Move(ChunkData^, GlobalPalette^, Chunk.DataSize);
+      GlobalPaletteEntries := Chunk.DataSize div 3;
+    end
+    else if GetLastFrame.Palette = nil then
+    begin
+      if (Chunk.DataSize = 0) and (GlobalPalette <> nil) then
+      begin
+        // Use global palette
+        GetMem(GetLastFrame.Palette, GlobalPaletteEntries * SizeOf(TColor24Rec));
+        Move(GlobalPalette^, GetLastFrame.Palette^, GlobalPaletteEntries * SizeOf(TColor24Rec));
+        GetLastFrame.PaletteEntries := GlobalPaletteEntries;
+      end
+      else
+      begin
+        // Load pal from PLTE chunk
+        GetMem(GetLastFrame.Palette, Chunk.DataSize);
+        Move(ChunkData^, GetLastFrame.Palette^, Chunk.DataSize);
+        GetLastFrame.PaletteEntries := Chunk.DataSize div 3;
+      end;
+    end;
+  end;
+
+  procedure LoadtRNS;
+  begin
+    ReadChunkData;
+    if GetLastFrame = nil then
+    begin
+      // Load global transparency
+      GetMem(GlobalTransparency, Chunk.DataSize);
+      Move(ChunkData^, GlobalTransparency^, Chunk.DataSize);
+      GlobalTransparencySize := Chunk.DataSize;
+    end
+    else if GetLastFrame.Transparency = nil then
+    begin
+      if (Chunk.DataSize = 0) and (GlobalTransparency <> nil) then
+      begin
+        // Use global transparency
+        GetMem(GetLastFrame.Transparency, GlobalTransparencySize);
+        Move(GlobalTransparency^, GetLastFrame.Transparency^, Chunk.DataSize);
+        GetLastFrame.TransparencySize := GlobalTransparencySize;
+      end
+      else
+      begin
+        // Load pal from tRNS chunk
+        GetMem(GetLastFrame.Transparency, Chunk.DataSize);
+        Move(ChunkData^, GetLastFrame.Transparency^, Chunk.DataSize);
+        GetLastFrame.TransparencySize := Chunk.DataSize;
+      end;
+    end;
+  end;
+
+  procedure LoadbKGD;
+  begin
+    ReadChunkData;
+    if GetLastFrame.Background = nil then
+    begin
+      GetMem(GetLastFrame.Background, Chunk.DataSize);
+      Move(ChunkData^, GetLastFrame.Background^, Chunk.DataSize);
+      GetLastFrame.BackgroundSize := Chunk.DataSize;
+    end;
+  end;
+
+  procedure HandleacTL;
+  begin
+    FileType := ngAPNG;
+    ReadChunkData;
+    acTL := PacTL(ChunkData)^;
+    SwapEndianLongWord(@acTL, SizeOf(acTL) div SizeOf(LongWord));
+  end;
+
+  procedure LoadpHYs;
+  begin
+    ReadChunkData;
+    with GetLastFrame do
+    begin
+      pHYs := PpHYs(ChunkData)^;
+      SwapEndianLongWord(@pHYs, SizeOf(pHYs) div SizeOf(LongWord));
+    end;
+  end;
+
+begin
+  Result := False;
+  Clear;
+  ChunkData := nil;
+  with GetIO do
+  try
+    Read(Handle, @Sig, SizeOf(Sig));
+    // Set file type according to the signature
+    if Sig = PNGSignature then FileType := ngPNG
+    else if Sig = MNGSignature then FileType := ngMNG
+    else if Sig = JNGSignature then FileType := ngJNG
+    else Exit;
+
+    if FileType = ngMNG then
+    begin
+      // Store MNG header if present
+      ReadChunk;
+      ReadChunkData;
+      MHDR := PMHDR(ChunkData)^;
+      SwapEndianLongWord(@MHDR, SizeOf(MHDR) div SizeOf(LongWord));
+    end;
+
+    // Read chunks until ending chunk or EOF is reached
+    repeat
+      ReadChunk;
+      if (Chunk.ChunkID = IHDRChunk) or (Chunk.ChunkID = fcTLChunk) then StartNewPNGImage
+      else if Chunk.ChunkID = JHDRChunk then StartNewJNGImage
+      else if (Chunk.ChunkID = IDATChunk) or (Chunk.ChunkID = fdATChunk) then AppendIDAT
+      else if Chunk.ChunkID = JDATChunk then AppendJDAT
+      else if Chunk.ChunkID = JDAAChunk then AppendJDAA
+      else if Chunk.ChunkID = PLTEChunk then LoadPLTE
+      else if Chunk.ChunkID = tRNSChunk then LoadtRNS
+      else if Chunk.ChunkID = bKGDChunk then LoadbKGD
+      else if Chunk.ChunkID = acTLChunk then HandleacTL
+      else if Chunk.ChunkID = pHYsChunk then LoadpHYs
+      else SkipChunkData;
+    until Eof(Handle) or (Chunk.ChunkID = MENDChunk) or
+      ((FileType <> ngMNG) and (Chunk.ChunkID = IENDChunk));
+
+    Result := True;
+  finally
+    FreeMemNil(ChunkData);
+  end;
+end;
+
+procedure TNGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight: LongInt; const IHDR: TIHDR;
+  IDATStream: TMemoryStream; var Image: TImageData);
+type
+  TGetPixelFunc = function(Line: PByteArray; X: LongInt): Byte;
+var
+  LineBuffer: array[Boolean] of PByteArray;
+  ActLine: Boolean;
+  Data, TotalBuffer, ZeroLine, PrevLine: Pointer;
+  BitCount, TotalSize, TotalPos, BytesPerPixel, I, Pass,
+  SrcDataSize, BytesPerLine, InterlaceLineBytes, InterlaceWidth: LongInt;
+  Info: TImageFormatInfo;
+
+  procedure DecodeAdam7;
+  const
+    BitTable: array[1..8] of LongInt = ($1, $3, 0, $F, 0, 0, 0, $FF);
+    StartBit: array[1..8] of LongInt = (7, 6, 0, 4, 0, 0, 0, 0);
+  var
+    Src, Dst, Dst2: PByte;
+    CurBit, Col: LongInt;
+  begin
+    Src := @LineBuffer[ActLine][1];
+    Col := ColumnStart[Pass];
+    with Image do
+      case BitCount of
+        1, 2, 4:
+          begin
+            Dst := @PByteArray(Data)[I * BytesPerLine];
+            repeat
+              CurBit := StartBit[BitCount];
+              repeat
+                Dst2 := @PByteArray(Dst)[(BitCount * Col) shr 3];
+                Dst2^ := Dst2^ or ((Src^ shr CurBit) and BitTable[BitCount])
+                  shl (StartBit[BitCount] - (Col * BitCount mod 8));
+                Inc(Col, ColumnIncrement[Pass]);
+                Dec(CurBit, BitCount);
+              until CurBit < 0;
+              Inc(Src);
+            until Col >= Width;
+          end;
+        else
+        begin
+          Dst := @PByteArray(Data)[I * BytesPerLine + Col * BytesPerPixel];
+          repeat
+            CopyPixel(Src, Dst, BytesPerPixel);
+            Inc(Dst, BytesPerPixel);
+            Inc(Src, BytesPerPixel);
+            Inc(Dst, ColumnIncrement[Pass] * BytesPerPixel - BytesPerPixel);
+            Inc(Col, ColumnIncrement[Pass]);
+          until Col >= Width;
+        end;
+      end;
+  end;
+
+  procedure FilterScanline(Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray;
+    BytesPerLine: LongInt);
+  var
+    I: LongInt;
+  begin
+    case Filter of
+      0:
+        begin
+          // No filter
+          Move(Line^, Target^, BytesPerLine);
+        end;
+      1:
+        begin
+          // Sub filter
+          Move(Line^, Target^, BytesPerPixel);
+          for I := BytesPerPixel to BytesPerLine - 1 do
+            Target[I] := (Line[I] + Target[I - BytesPerPixel]) and $FF;
+        end;
+      2:
+        begin
+          // Up filter
+          for I := 0 to BytesPerLine - 1 do
+            Target[I] := (Line[I] + PrevLine[I]) and $FF;
+        end;
+      3:
+        begin
+          // Average filter
+          for I := 0 to BytesPerPixel - 1 do
+            Target[I] := (Line[I] + PrevLine[I] shr 1) and $FF;
+          for I := BytesPerPixel to BytesPerLine - 1 do
+            Target[I] := (Line[I] + (Target[I - BytesPerPixel] + PrevLine[I]) shr 1) and $FF;
+        end;
+      4:
+        begin
+          // Paeth filter
+          for I := 0 to BytesPerPixel - 1 do
+            Target[I] := (Line[I] + PaethPredictor(0, PrevLine[I], 0)) and $FF;
+          for I := BytesPerPixel to BytesPerLine - 1 do
+            Target[I] := (Line[I] + PaethPredictor(Target[I - BytesPerPixel], PrevLine[I], PrevLine[I - BytesPerPixel])) and $FF;
+        end;
+    end;
+  end;
+
+  procedure TransformLOCOToRGB(Data: PByte; NumPixels, BytesPerPixel: LongInt);
+  var
+    I: LongInt;
+  begin
+    for I := 0 to NumPixels - 1 do
+    begin
+      if IHDR.BitDepth = 8 then
+      begin
+        PColor32Rec(Data).R := Byte(PColor32Rec(Data).R + PColor32Rec(Data).G);
+        PColor32Rec(Data).B := Byte(PColor32Rec(Data).B + PColor32Rec(Data).G);
+      end
+      else
+      begin
+        PColor64Rec(Data).R := Word(PColor64Rec(Data).R + PColor64Rec(Data).G);
+        PColor64Rec(Data).B := Word(PColor64Rec(Data).B + PColor64Rec(Data).G);
+      end;
+      Inc(Data, BytesPerPixel);
+    end;
+  end;
+
+  function CheckBinaryPalette: Boolean;
+  begin
+    with GetLastFrame do
+      Result := (PaletteEntries = 2) and
+        (Palette[0].R = 0) and (Palette[0].G = 0) and (Palette[0].B = 0) and
+        (Palette[1].R = 255) and (Palette[1].G = 255) and (Palette[1].B = 255);
+  end;
+
+begin
+  Image.Width := FrameWidth;
+  Image.Height := FrameHeight;
+  Image.Format := ifUnknown;
+
+  case IHDR.ColorType of
+    0:
+      begin
+        // Gray scale image
+        case IHDR.BitDepth of
+          1:       Image.Format := ifBinary;
+          2, 4, 8: Image.Format := ifGray8;
+          16:      Image.Format := ifGray16;
+        end;
+        BitCount := IHDR.BitDepth;
+      end;
+    2:
+      begin
+        // RGB image
+        case IHDR.BitDepth of
+          8:  Image.Format := ifR8G8B8;
+          16: Image.Format := ifR16G16B16;
+        end;
+        BitCount := IHDR.BitDepth * 3;
+      end;
+    3:
+      begin
+        // Indexed image
+        if (IHDR.BitDepth = 1) and CheckBinaryPalette  then
+          Image.Format := ifBinary
+        else
+          Image.Format := ifIndex8;
+        BitCount := IHDR.BitDepth;
+      end;
+    4:
+      begin
+        // Grayscale + alpha image
+        case IHDR.BitDepth of
+          8: Image.Format := ifA8Gray8;
+          16: Image.Format := ifA16Gray16;
+        end;
+        BitCount := IHDR.BitDepth * 2;
+      end;
+    6:
+      begin
+        // ARGB image
+        case IHDR.BitDepth of
+          8: Image.Format := ifA8R8G8B8;
+          16: Image.Format := ifA16R16G16B16;
+        end;
+        BitCount := IHDR.BitDepth * 4;
+      end;
+  end;
+
+  GetImageFormatInfo(Image.Format, Info);
+  BytesPerPixel := (BitCount + 7) div 8;
+
+  LineBuffer[True] := nil;
+  LineBuffer[False] := nil;
+  TotalBuffer := nil;
+  ZeroLine := nil;
+  ActLine := True;
+
+  // Start decoding
+  with Image do
+  try
+    BytesPerLine := (Width * BitCount + 7) div 8;
+    SrcDataSize := Height * BytesPerLine;
+    GetMem(Data, SrcDataSize);
+    FillChar(Data^, SrcDataSize, 0);
+    GetMem(ZeroLine, BytesPerLine);
+    FillChar(ZeroLine^, BytesPerLine, 0);
+
+    if IHDR.Interlacing = 1 then
+    begin
+      // Decode interlaced images
+      TotalPos := 0;
+      DecompressBuf(IDATStream.Memory, IDATStream.Size, 0,
+        Pointer(TotalBuffer), TotalSize);
+      GetMem(LineBuffer[True], BytesPerLine + 1);
+      GetMem(LineBuffer[False], BytesPerLine + 1);
+      for Pass := 0 to 6 do
+      begin
+        // Prepare next interlace run
+        if Width <= ColumnStart[Pass] then
+          Continue;
+        InterlaceWidth := (Width + ColumnIncrement[Pass] - 1 -
+          ColumnStart[Pass]) div ColumnIncrement[Pass];
+        InterlaceLineBytes := (InterlaceWidth * BitCount + 7) shr 3;
+        I := RowStart[Pass];
+        FillChar(LineBuffer[True][0], BytesPerLine + 1, 0);
+        FillChar(LineBuffer[False][0], BytesPerLine + 1, 0);
+        while I < Height do
+        begin
+          // Copy line from decompressed data to working buffer
+          Move(PByteArray(TotalBuffer)[TotalPos],
+            LineBuffer[ActLine][0], InterlaceLineBytes + 1);
+          Inc(TotalPos, InterlaceLineBytes + 1);
+          // Swap red and blue channels if necessary
+          if (IHDR.ColorType in [2, 6]) then
+            SwapRGB(@LineBuffer[ActLine][1], InterlaceWidth, IHDR.BitDepth, BytesPerPixel);
+          // Reverse-filter current scanline
+          FilterScanline(LineBuffer[ActLine][0], BytesPerPixel,
+            @LineBuffer[ActLine][1], @LineBuffer[not ActLine][1],
+            @LineBuffer[ActLine][1], InterlaceLineBytes);
+          // Decode Adam7 interlacing
+          DecodeAdam7;
+          ActLine := not ActLine;
+          // Continue with next row in interlaced order
+          Inc(I, RowIncrement[Pass]);
+        end;
+      end;
+    end
+    else
+    begin
+      // Decode non-interlaced images
+      PrevLine := ZeroLine;
+      DecompressBuf(IDATStream.Memory, IDATStream.Size, SrcDataSize + Height,
+        Pointer(TotalBuffer), TotalSize);
+      for I := 0 to Height - 1 do
+      begin
+        // Swap red and blue channels if necessary
+        if IHDR.ColorType in [2, 6] then
+          SwapRGB(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], Width,
+           IHDR.BitDepth, BytesPerPixel);
+        // reverse-filter current scanline
+        FilterScanline(PByteArray(TotalBuffer)[I * (BytesPerLine + 1)],
+          BytesPerPixel, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1],
+          PrevLine, @PByteArray(Data)[I * BytesPerLine], BytesPerLine);
+        PrevLine := @PByteArray(Data)[I * BytesPerLine];
+      end;
+    end;
+
+    Size := Info.GetPixelsSize(Info.Format, Width, Height);
+
+    if Size <> SrcDataSize then
+    begin
+      // If source data size is different from size of image in assigned
+      // format we must convert it (it is in 1/2/4 bit count)
+      GetMem(Bits, Size);
+      case IHDR.BitDepth of
+        1:
+          begin
+            // Convert only indexed, keep black and white in ifBinary
+            if IHDR.ColorType <> 0 then
+              Convert1To8(Data, Bits, Width, Height, BytesPerLine, False);
+          end;
+        2: Convert2To8(Data, Bits, Width, Height, BytesPerLine, IHDR.ColorType = 0);
+        4: Convert4To8(Data, Bits, Width, Height, BytesPerLine, IHDR.ColorType = 0);
+      end;
+      FreeMem(Data);
+    end
+    else
+    begin
+      // If source data size is the same as size of
+      // image Bits in assigned format we simply copy pointer reference
+      Bits := Data;
+    end;
+
+    // LOCO transformation was used too (only for color types 2 and 6)
+    if (IHDR.Filter = 64) and (IHDR.ColorType in [2, 6]) then
+      TransformLOCOToRGB(Bits, Width * Height, BytesPerPixel);
+
+    // Images with 16 bit channels must be swapped because of PNG's big endianity
+    if IHDR.BitDepth = 16 then
+      SwapEndianWord(Bits, Width * Height * BytesPerPixel div SizeOf(Word));
+  finally
+    FreeMem(LineBuffer[True]);
+    FreeMem(LineBuffer[False]);
+    FreeMem(TotalBuffer);
+    FreeMem(ZeroLine);
+  end;
+end;
+
+{$IFNDEF DONT_LINK_JNG}
+
+procedure TNGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight: LongInt; const JHDR: TJHDR; IDATStream,
+  JDATStream, JDAAStream: TMemoryStream; var Image: TImageData);
+var
+  AlphaImage: TImageData;
+  FakeIHDR: TIHDR;
+  FmtInfo: TImageFormatInfo;
+  I: LongInt;
+  AlphaPtr: PByte;
+  GrayPtr: PWordRec;
+  ColorPtr: PColor32Rec;
+
+  procedure LoadJpegFromStream(Stream: TStream; var DestImage: TImageData);
+  var
+    JpegFormat: TCustomIOJpegFileFormat;
+    Handle: TImagingHandle;
+    DynImages: TDynImageDataArray;
+  begin
+    if JHDR.SampleDepth <> 12 then
+    begin
+      JpegFormat := TCustomIOJpegFileFormat.Create;
+      JpegFormat.SetCustomIO(StreamIO);
+      Stream.Position := 0;
+      Handle := StreamIO.Open(Pointer(Stream), omReadOnly);
+      try
+        JpegFormat.LoadData(Handle, DynImages, True);
+        DestImage := DynImages[0];
+      finally
+        StreamIO.Close(Handle);
+        JpegFormat.Free;
+        SetLength(DynImages, 0);
+      end;
+    end
+    else
+      NewImage(FrameWidth, FrameHeight, ifR8G8B8, DestImage);
+  end;
+
+begin
+  LoadJpegFromStream(JDATStream, Image);
+
+  // If present separate alpha channel is processed
+  if (JHDR.ColorType in [12, 14]) and (Image.Format in [ifGray8, ifR8G8B8]) then
+  begin
+    InitImage(AlphaImage);
+    if JHDR.AlphaCompression = 0 then
+    begin
+      // Alpha channel is PNG compressed
+      FakeIHDR.Width := JHDR.Width;
+      FakeIHDR.Height := JHDR.Height;
+      FakeIHDR.ColorType := 0;
+      FakeIHDR.BitDepth := JHDR.AlphaSampleDepth;
+      FakeIHDR.Filter := JHDR.AlphaFilter;
+      FakeIHDR.Interlacing := JHDR.AlphaInterlacing;
+
+      LoadImageFromPNGFrame(FrameWidth, FrameHeight, FakeIHDR, IDATStream, AlphaImage);
+    end
+    else
+    begin
+      // Alpha channel is JPEG compressed
+      LoadJpegFromStream(JDAAStream, AlphaImage);
+    end;
+
+    // Check if alpha channel is the same size as image
+    if (Image.Width <> AlphaImage.Width) and (Image.Height <> AlphaImage.Height) then
+      ResizeImage(AlphaImage, Image.Width, Image.Height, rfNearest);
+
+    // Check alpha channels data format
+    GetImageFormatInfo(AlphaImage.Format, FmtInfo);
+    if (FmtInfo.BytesPerPixel > 1) or (not FmtInfo.HasGrayChannel) then
+      ConvertImage(AlphaImage, ifGray8);
+
+    // Convert image to fromat with alpha channel
+    if Image.Format = ifGray8 then
+      ConvertImage(Image, ifA8Gray8)
+    else
+      ConvertImage(Image, ifA8R8G8B8);
+
+    // Combine alpha channel with image
+    AlphaPtr := AlphaImage.Bits;
+    if Image.Format = ifA8Gray8 then
+    begin
+      GrayPtr := Image.Bits;
+      for I := 0 to Image.Width * Image.Height - 1 do
+      begin
+        GrayPtr.High := AlphaPtr^;
+        Inc(GrayPtr);
+        Inc(AlphaPtr);
+      end;
+    end
+    else
+    begin
+      ColorPtr := Image.Bits;
+      for I := 0 to Image.Width * Image.Height - 1 do
+      begin
+        ColorPtr.A := AlphaPtr^;
+        Inc(ColorPtr);
+        Inc(AlphaPtr);
+      end;
+    end;
+
+    FreeImage(AlphaImage);
+  end;
+end;
+
+{$ENDIF}
+
+procedure TNGFileLoader.ApplyFrameSettings(Frame: TFrameInfo; var Image: TImageData);
+var
+  FmtInfo: TImageFormatInfo;
+  BackGroundColor: TColor64Rec;
+  ColorKey: TColor64Rec;
+  Alphas: PByteArray;
+  AlphasSize: LongInt;
+  IsColorKeyPresent: Boolean;
+  IsBackGroundPresent: Boolean;
+  IsColorFormat: Boolean;
+
+  procedure ConverttRNS;
+  begin
+    if FmtInfo.IsIndexed then
+    begin
+      if Alphas = nil then
+      begin
+        GetMem(Alphas, Frame.TransparencySize);
+        Move(Frame.Transparency^, Alphas^, Frame.TransparencySize);
+        AlphasSize := Frame.TransparencySize;
+      end;
+    end
+    else if not FmtInfo.HasAlphaChannel then
+    begin
+      FillChar(ColorKey, SizeOf(ColorKey), 0);
+      Move(Frame.Transparency^, ColorKey, Min(Frame.TransparencySize, SizeOf(ColorKey)));
+      if IsColorFormat then
+        SwapValues(ColorKey.R, ColorKey.B);
+      SwapEndianWord(@ColorKey, 3);
+      // 1/2/4 bit images were converted to 8 bit so we must convert color key too
+      if (not Frame.IsJpegFrame) and (Frame.IHDR.ColorType in [0, 4]) then
+        case Frame.IHDR.BitDepth of
+          1: ColorKey.B := Word(ColorKey.B * 255);
+          2: ColorKey.B := Word(ColorKey.B * 85);
+          4: ColorKey.B := Word(ColorKey.B * 17);
+        end;
+      IsColorKeyPresent := True;
+    end;
+  end;
+
+  procedure ConvertbKGD;
+  begin
+    FillChar(BackGroundColor, SizeOf(BackGroundColor), 0);
+    Move(Frame.Background^, BackGroundColor, Min(Frame.BackgroundSize, SizeOf(BackGroundColor)));
+    if IsColorFormat then
+      SwapValues(BackGroundColor.R, BackGroundColor.B);
+    SwapEndianWord(@BackGroundColor, 3);
+    // 1/2/4 bit images were converted to 8 bit so we must convert back color too
+    if (not Frame.IsJpegFrame) and (Frame.IHDR.ColorType in [0, 4]) then
+      case Frame.IHDR.BitDepth of
+        1: BackGroundColor.B := Word(BackGroundColor.B * 255);
+        2: BackGroundColor.B := Word(BackGroundColor.B * 85);
+        4: BackGroundColor.B := Word(BackGroundColor.B * 17);
+      end;
+    IsBackGroundPresent := True;
+  end;
+
+  procedure ReconstructPalette;
+  var
+    I: LongInt;
+  begin
+    with Image do
+    begin
+      GetMem(Palette, FmtInfo.PaletteEntries * SizeOf(TColor32Rec));
+      FillChar(Palette^, FmtInfo.PaletteEntries * SizeOf(TColor32Rec), $FF);
+      // if RGB palette was loaded from file then use it
+      if Frame.Palette <> nil then
+        for I := 0 to Min(Frame.PaletteEntries, FmtInfo.PaletteEntries) - 1 do
+        with Palette[I] do
+        begin
+          R := Frame.Palette[I].B;
+          G := Frame.Palette[I].G;
+          B := Frame.Palette[I].R;
+        end;
+      // if palette alphas were loaded from file then use them
+      if Alphas <> nil then
+      begin
+        for I := 0 to Min(AlphasSize, FmtInfo.PaletteEntries) - 1 do
+          Palette[I].A := Alphas[I];
+      end;
+    end;
+  end;
+
+  procedure ApplyColorKey;
+  var
+    DestFmt: TImageFormat;
+    Col32, Bkg32: TColor32Rec;
+    OldPixel, NewPixel: Pointer;
+  begin
+    case Image.Format of
+      ifGray8: DestFmt := ifA8Gray8;
+      ifGray16: DestFmt := ifA16Gray16;
+      ifR8G8B8: DestFmt := ifA8R8G8B8;
+      ifR16G16B16: DestFmt := ifA16R16G16B16;
+    else
+      DestFmt := ifUnknown;
+    end;
+
+    if DestFmt <> ifUnknown then
+    begin
+      if not IsBackGroundPresent then
+        BackGroundColor := ColorKey;
+      ConvertImage(Image, DestFmt);
+
+      // Now back color and color key must be converted to image's data format, looks ugly
+      case Image.Format of
+        ifA8Gray8:
+          begin
+            Col32 := Color32(0, 0, $FF, Byte(ColorKey.B));
+            Bkg32 := Color32(0, 0, 0, Byte(BackGroundColor.B));
+          end;
+        ifA16Gray16:
+          begin
+            ColorKey.G := $FFFF;
+          end;
+        ifA8R8G8B8:
+          begin
+            Col32 := Color32($FF, Byte(ColorKey.R), Byte(ColorKey.G), Byte(ColorKey.B));
+            Bkg32 := Color32(0, Byte(BackGroundColor.R), Byte(BackGroundColor.G), Byte(BackGroundColor.B));
+          end;
+        ifA16R16G16B16:
+          begin
+            ColorKey.A := $FFFF;
+          end;
+      end;
+
+      if Image.Format in [ifA8Gray8, ifA8R8G8B8] then
+      begin
+        OldPixel := @Col32;
+        NewPixel := @Bkg32;
+      end
+      else
+      begin
+        OldPixel := @ColorKey;
+        NewPixel := @BackGroundColor;
+      end;
+
+      ReplaceColor(Image, 0, 0, Image.Width, Image.Height, OldPixel, NewPixel);
+    end;
+  end;
+
+begin
+  Alphas := nil;
+  IsColorKeyPresent := False;
+  IsBackGroundPresent := False;
+  GetImageFormatInfo(Image.Format, FmtInfo);
+
+  IsColorFormat := (Frame.IsJpegFrame and (Frame.JHDR.ColorType in [10, 14])) or
+    (not Frame.IsJpegFrame and (Frame.IHDR.ColorType in [2, 6]));
+
+  // Convert some chunk data to useful format
+  if Frame.TransparencySize > 0 then
+    ConverttRNS;
+  if Frame.BackgroundSize > 0 then
+    ConvertbKGD;
+
+  // Build palette for indexed images
+  if FmtInfo.IsIndexed then
+    ReconstructPalette;
+
+  // Apply color keying
+  if IsColorKeyPresent and not FmtInfo.HasAlphaChannel then
+    ApplyColorKey;
+
+  FreeMemNil(Alphas);
+end;
+
+{ TNGFileSaver class implementation }
+
+procedure TNGFileSaver.StoreImageToPNGFrame(const IHDR: TIHDR; Bits: Pointer;
+  FmtInfo: TImageFormatInfo; IDATStream: TMemoryStream);
+var
+  TotalBuffer, CompBuffer, ZeroLine, PrevLine: Pointer;
+  FilterLines: array[0..4] of PByteArray;
+  TotalSize, CompSize, I, BytesPerLine, BytesPerPixel: LongInt;
+  Filter: Byte;
+  Adaptive: Boolean;
+
+  procedure FilterScanline(Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray);
+  var
+    I: LongInt;
+  begin
+    case Filter of
+      0:
+        begin
+          // No filter
+          Move(Line^, Target^, BytesPerLine);
+        end;
+      1:
+        begin
+          // Sub filter
+          Move(Line^, Target^, BytesPerPixel);
+          for I := BytesPerPixel to BytesPerLine - 1 do
+            Target[I] := (Line[I] - Line[I - BytesPerPixel]) and $FF;
+        end;
+      2:
+        begin
+          // Up filter
+          for I := 0 to BytesPerLine - 1 do
+            Target[I] := (Line[I] - PrevLine[I]) and $FF;
+        end;
+      3:
+        begin
+          // Average filter
+          for I := 0 to BytesPerPixel - 1 do
+            Target[I] := (Line[I] - PrevLine[I] shr 1) and $FF;
+          for I := BytesPerPixel to BytesPerLine - 1 do
+            Target[I] := (Line[I] - (Line[I - BytesPerPixel] + PrevLine[I]) shr 1) and $FF;
+        end;
+      4:
+        begin
+          // Paeth filter
+          for I := 0 to BytesPerPixel - 1 do
+            Target[I] := (Line[I] - PaethPredictor(0, PrevLine[I], 0)) and $FF;
+          for I := BytesPerPixel to BytesPerLine - 1 do
+            Target[I] := (Line[I] - PaethPredictor(Line[I - BytesPerPixel], PrevLine[I], PrevLine[I - BytesPerPixel])) and $FF;
+        end;
+    end;
+  end;
+
+  procedure AdaptiveFilter(var Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray);
+  var
+    I, J, BestTest: LongInt;
+    Sums: array[0..4] of LongInt;
+  begin
+    // Compute the output scanline using all five filters,
+    // and select the filter that gives the smallest sum of
+    // absolute values of outputs
+    FillChar(Sums, SizeOf(Sums), 0);
+    BestTest := MaxInt;
+    for I := 0 to 4 do
+    begin
+      FilterScanline(I, BytesPerPixel, Line, PrevLine, FilterLines[I]);
+      for J := 0 to BytesPerLine - 1 do
+        Sums[I] := Sums[I] + Abs(ShortInt(FilterLines[I][J]));
+      if Sums[I] < BestTest then
+      begin
+        Filter := I;
+        BestTest := Sums[I];
+      end;
+    end;
+    Move(FilterLines[Filter]^, Target^, BytesPerLine);
+  end;
+
+begin
+  // Select precompression filter and compression level
+  Adaptive := False;
+  Filter := 0;
+  case PreFilter of
+    6:
+      if not ((IHDR.BitDepth < 8) or (IHDR.ColorType = 3)) then
+        Adaptive := True;
+    0..4: Filter := PreFilter;
+  else
+    if IHDR.ColorType in [2, 6] then
+      Filter := 4
+  end;
+
+  // Prepare data for compression
+  CompBuffer := nil;
+  FillChar(FilterLines, SizeOf(FilterLines), 0);
+  BytesPerPixel := Max(1, FmtInfo.BytesPerPixel);
+  BytesPerLine := FmtInfo.GetPixelsSize(FmtInfo.Format, LongInt(IHDR.Width), 1);
+  TotalSize := (BytesPerLine + 1) * LongInt(IHDR.Height);
+  GetMem(TotalBuffer, TotalSize);
+  GetMem(ZeroLine, BytesPerLine);
+  FillChar(ZeroLine^, BytesPerLine, 0);
+  PrevLine := ZeroLine;
+
+  if Adaptive then
+  begin
+    for I := 0 to 4 do
+      GetMem(FilterLines[I], BytesPerLine);
+  end;
+
+  try
+    // Process next scanlines
+    for I := 0 to IHDR.Height - 1 do
+    begin
+      // Filter scanline
+      if Adaptive then
+      begin
+        AdaptiveFilter(Filter, BytesPerPixel, @PByteArray(Bits)[I * BytesPerLine],
+          PrevLine, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1]);
+      end
+      else
+      begin
+        FilterScanline(Filter, BytesPerPixel, @PByteArray(Bits)[I * BytesPerLine],
+          PrevLine, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1]);
+      end;
+      PrevLine := @PByteArray(Bits)[I * BytesPerLine];
+      // Swap red and blue if necessary
+      if (IHDR.ColorType in [2, 6]) and not FmtInfo.IsRBSwapped then
+      begin
+        SwapRGB(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1],
+          IHDR.Width, IHDR.BitDepth, BytesPerPixel);
+      end;
+      // Images with 16 bit channels must be swapped because of PNG's big endianess
+      if IHDR.BitDepth = 16 then
+      begin
+        SwapEndianWord(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1],
+          BytesPerLine div SizeOf(Word));
+      end;
+      // Set filter used for this scanline
+      PByteArray(TotalBuffer)[I * (BytesPerLine + 1)] := Filter;
+    end;
+    // Compress IDAT data
+    CompressBuf(TotalBuffer, TotalSize, CompBuffer, CompSize,
+      CompressLevel, ZLibStrategy);
+    // Write IDAT data to stream
+    IDATStream.WriteBuffer(CompBuffer^, CompSize);
+  finally
+    FreeMem(TotalBuffer);
+    FreeMem(CompBuffer);
+    FreeMem(ZeroLine);
+    if Adaptive then
+      for I := 0 to 4 do
+        FreeMem(FilterLines[I]);
+  end;
+end;
+
+{$IFNDEF DONT_LINK_JNG}
+
+procedure TNGFileSaver.StoreImageToJNGFrame(const JHDR: TJHDR;
+  const Image: TImageData; IDATStream, JDATStream,
+  JDAAStream: TMemoryStream);
+var
+  ColorImage, AlphaImage: TImageData;
+  FmtInfo: TImageFormatInfo;
+  AlphaPtr: PByte;
+  GrayPtr: PWordRec;
+  ColorPtr: PColor32Rec;
+  I: LongInt;
+  FakeIHDR: TIHDR;
+
+  procedure SaveJpegToStream(Stream: TStream; const Image: TImageData);
+  var
+    JpegFormat: TCustomIOJpegFileFormat;
+    Handle: TImagingHandle;
+    DynImages: TDynImageDataArray;
+  begin
+    JpegFormat := TCustomIOJpegFileFormat.Create;
+    JpegFormat.SetCustomIO(StreamIO);
+    // Only JDAT stream can be saved progressive
+    if Stream = JDATStream then
+      JpegFormat.FProgressive := Progressive
+    else
+      JpegFormat.FProgressive := False;
+    JpegFormat.FQuality := Quality;
+    SetLength(DynImages, 1);
+    DynImages[0] := Image;
+    Handle := StreamIO.Open(Pointer(Stream), omCreate);
+    try
+      JpegFormat.SaveData(Handle, DynImages, 0);
+    finally
+      StreamIO.Close(Handle);
+      SetLength(DynImages, 0);
+      JpegFormat.Free;
+    end;
+  end;
+
+begin
+  GetImageFormatInfo(Image.Format, FmtInfo);
+  InitImage(ColorImage);
+  InitImage(AlphaImage);
+
+  if FmtInfo.HasAlphaChannel then
+  begin
+    // Create new image for alpha channel and color image without alpha
+    CloneImage(Image, ColorImage);
+    NewImage(Image.Width, Image.Height, ifGray8, AlphaImage);
+    case Image.Format of
+      ifA8Gray8:  ConvertImage(ColorImage, ifGray8);
+      ifA8R8G8B8: ConvertImage(ColorImage, ifR8G8B8);
+    end;
+
+    // Store source image's alpha to separate image
+    AlphaPtr := AlphaImage.Bits;
+    if Image.Format = ifA8Gray8 then
+    begin
+      GrayPtr := Image.Bits;
+      for I := 0 to Image.Width * Image.Height - 1 do
+      begin
+        AlphaPtr^ := GrayPtr.High;
+        Inc(GrayPtr);
+        Inc(AlphaPtr);
+      end;
+    end
+    else
+    begin
+      ColorPtr := Image.Bits;
+      for I := 0 to Image.Width * Image.Height - 1 do
+      begin
+        AlphaPtr^ := ColorPtr.A;
+        Inc(ColorPtr);
+        Inc(AlphaPtr);
+      end;
+    end;
+
+    // Write color image to stream as JPEG
+    SaveJpegToStream(JDATStream, ColorImage);
+
+    if LossyAlpha then
+    begin
+      // Write alpha image to stream as JPEG
+      SaveJpegToStream(JDAAStream, AlphaImage);
+    end
+    else
+    begin
+      // Alpha channel is PNG compressed
+      FakeIHDR.Width := JHDR.Width;
+      FakeIHDR.Height := JHDR.Height;
+      FakeIHDR.ColorType := 0;
+      FakeIHDR.BitDepth := JHDR.AlphaSampleDepth;
+      FakeIHDR.Filter := JHDR.AlphaFilter;
+      FakeIHDR.Interlacing := JHDR.AlphaInterlacing;
+
+      GetImageFormatInfo(AlphaImage.Format, FmtInfo);
+      StoreImageToPNGFrame(FakeIHDR, AlphaImage.Bits, FmtInfo, IDATStream);
+    end;
+
+    FreeImage(ColorImage);
+    FreeImage(AlphaImage);
+  end
+  else
+  begin
+    // Simply write JPEG to stream
+    SaveJpegToStream(JDATStream, Image);
+  end;
+end;
+
+{$ENDIF}
+
+procedure TNGFileSaver.AddFrame(const Image: TImageData; IsJpegFrame: Boolean);
+var
+  Frame: TFrameInfo;
+  FmtInfo: TImageFormatInfo;
+  Index: Integer;
+
+  procedure StorePalette;
+  var
+    Pal: PPalette24;
+    Alphas: PByteArray;
+    I, PalBytes: LongInt;
+    AlphasDiffer: Boolean;
+  begin
+    // Fill and save RGB part of palette to PLTE chunk
+    PalBytes := FmtInfo.PaletteEntries * SizeOf(TColor24Rec);
+    GetMem(Pal, PalBytes);
+    AlphasDiffer := False;
+    for I := 0 to FmtInfo.PaletteEntries - 1 do
+    begin
+      Pal[I].B := Image.Palette[I].R;
+      Pal[I].G := Image.Palette[I].G;
+      Pal[I].R := Image.Palette[I].B;
+      if Image.Palette[I].A < 255 then
+        AlphasDiffer := True;
+    end;
+    Frame.Palette := Pal;
+    Frame.PaletteEntries := FmtInfo.PaletteEntries;
+    // Fill and save alpha part (if there are any alphas < 255) of palette to tRNS chunk
+    if AlphasDiffer then
+    begin
+      PalBytes := FmtInfo.PaletteEntries * SizeOf(Byte);
+      GetMem(Alphas, PalBytes);
+      for I := 0 to FmtInfo.PaletteEntries - 1 do
+        Alphas[I] := Image.Palette[I].A;
+      Frame.Transparency := Alphas;
+      Frame.TransparencySize := PalBytes;
+    end;
+  end;
+
+  procedure FillFrameControlChunk(const IHDR: TIHDR; var fcTL: TfcTL);
+  var
+    Delay: Integer;
+  begin
+    fcTL.SeqNumber := 0; // Decided when writing to file
+    fcTL.Width := IHDR.Width;
+    fcTL.Height := IHDR.Height;
+    fcTL.XOffset := 0;
+    fcTL.YOffset := 0;
+    fcTL.DelayNumer := 1;
+    fcTL.DelayDenom := 3;
+    if FileFormat.FMetadata.HasMetaItemForSaving(SMetaFrameDelay, Index) then
+    begin
+      // Metadata contains frame delay information in milliseconds
+      Delay := FileFormat.FMetadata.MetaItemsForSavingMulti[SMetaFrameDelay, Index];
+      fcTL.DelayNumer := Delay;
+      fcTL.DelayDenom := 1000;
+    end;
+    fcTL.DisposeOp := DisposeOpNone;
+    fcTL.BlendOp := BlendOpSource;
+    SwapEndianLongWord(@fcTL, 5);
+    fcTL.DelayNumer := SwapEndianWord(fcTL.DelayNumer);
+    fcTL.DelayDenom := SwapEndianWord(fcTL.DelayDenom);
+  end;
+
+begin
+  // Add new frame
+  Frame := AddFrameInfo;
+  Frame.IsJpegFrame := IsJpegFrame;
+  Index := Length(Frames) - 1;
+
+  with Frame do
+  begin
+    GetImageFormatInfo(Image.Format, FmtInfo);
+
+    if IsJpegFrame then
+    begin
+{$IFNDEF DONT_LINK_JNG}
+      // Fill JNG header
+      JHDR.Width := Image.Width;
+      JHDR.Height := Image.Height;
+      case Image.Format of
+        ifGray8:    JHDR.ColorType := 8;
+        ifR8G8B8:   JHDR.ColorType := 10;
+        ifA8Gray8:  JHDR.ColorType := 12;
+        ifA8R8G8B8: JHDR.ColorType := 14;
+      end;
+      JHDR.SampleDepth := 8; // 8-bit samples and quantization tables
+      JHDR.Compression := 8; // Huffman coding
+      JHDR.Interlacing := Iff(Progressive, 8, 0);
+      JHDR.AlphaSampleDepth := Iff(FmtInfo.HasAlphaChannel, 8, 0);
+      JHDR.AlphaCompression := Iff(LossyAlpha, 8, 0);
+      JHDR.AlphaFilter := 0;
+      JHDR.AlphaInterlacing := 0;
+
+      StoreImageToJNGFrame(JHDR, Image, IDATMemory, JDATMemory, JDAAMemory);
+
+      // Finally swap endian
+      SwapEndianLongWord(@JHDR, 2);
+{$ENDIF}
+    end
+    else
+    begin
+      // Fill PNG header
+      IHDR.Width := Image.Width;
+      IHDR.Height := Image.Height;
+      IHDR.Compression := 0;
+      IHDR.Filter := 0;
+      IHDR.Interlacing := 0;
+      IHDR.BitDepth := FmtInfo.BytesPerPixel * 8;
+
+      // Select appropiate PNG color type and modify bitdepth
+      if FmtInfo.HasGrayChannel then
+      begin
+        IHDR.ColorType := 0;
+        if FmtInfo.HasAlphaChannel then
+        begin
+          IHDR.ColorType := 4;
+          IHDR.BitDepth := IHDR.BitDepth div 2;
+        end;
+      end
+      else if FmtInfo.Format = ifBinary then
+      begin
+        IHDR.ColorType := 0;
+        IHDR.BitDepth := 1;
+      end
+      else if FmtInfo.IsIndexed then
+        IHDR.ColorType := 3
+      else if FmtInfo.HasAlphaChannel then
+      begin
+        IHDR.ColorType := 6;
+        IHDR.BitDepth := IHDR.BitDepth div 4;
+      end
+      else
+      begin
+        IHDR.ColorType := 2;
+        IHDR.BitDepth := IHDR.BitDepth div 3;
+      end;
+
+      if FileType = ngAPNG then
+      begin
+        // Fill fcTL chunk of APNG file
+        FillFrameControlChunk(IHDR, fcTL);
+      end;
+
+      // Compress PNG image and store it to stream
+      StoreImageToPNGFrame(IHDR, Image.Bits, FmtInfo, IDATMemory);
+      // Store palette if necesary
+      if FmtInfo.IsIndexed then
+        StorePalette;
+
+      // Finally swap endian
+      SwapEndianLongWord(@IHDR, 2);
+    end;
+  end;
+end;
+
+function TNGFileSaver.SaveFile(Handle: TImagingHandle): Boolean;
+var
+  I: LongInt;
+  Chunk: TChunkHeader;
+  SeqNo: LongWord;
+
+  function GetNextSeqNo: LongWord;
+  begin
+    // Seq numbers of fcTL and fdAT are "interleaved" as they share the counter.
+    // Example: first fcTL for IDAT has seq=0, next is fcTL for seond frame with
+    // seq=1, then first fdAT with seq=2, fcTL seq=3, fdAT=4, ...
+    Result := SwapEndianLongWord(SeqNo);
+    Inc(SeqNo);
+  end;
+
+  function CalcChunkCrc(const ChunkHdr: TChunkHeader; Data: Pointer;
+    Size: LongInt): LongWord;
+  begin
+    Result := $FFFFFFFF;
+    CalcCrc32(Result, @ChunkHdr.ChunkID, SizeOf(ChunkHdr.ChunkID));
+    CalcCrc32(Result, Data, Size);
+    Result := SwapEndianLongWord(Result xor $FFFFFFFF);
+  end;
+
+  procedure WriteChunk(var Chunk: TChunkHeader; ChunkData: Pointer);
+  var
+    ChunkCrc: LongWord;
+    SizeToWrite: LongInt;
+  begin
+    SizeToWrite := Chunk.DataSize;
+    Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize);
+    ChunkCrc := CalcChunkCrc(Chunk, ChunkData, SizeToWrite);
+    GetIO.Write(Handle, @Chunk, SizeOf(Chunk));
+    if SizeToWrite <> 0 then
+      GetIO.Write(Handle, ChunkData, SizeToWrite);
+    GetIO.Write(Handle, @ChunkCrc, SizeOf(ChunkCrc));
+  end;
+
+  procedure WritefdAT(Frame: TFrameInfo);
+  var
+    ChunkCrc: LongWord;
+    ChunkSeqNo: LongWord;
+  begin
+    Chunk.ChunkID := fdATChunk;
+    ChunkSeqNo := GetNextSeqNo;
+    // fdAT saves seq number LongWord before compressed pixels
+    Chunk.DataSize := Frame.IDATMemory.Size + SizeOf(LongWord);
+    Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize);
+    // Calc CRC
+    ChunkCrc := $FFFFFFFF;
+    CalcCrc32(ChunkCrc, @Chunk.ChunkID, SizeOf(Chunk.ChunkID));
+    CalcCrc32(ChunkCrc, @ChunkSeqNo, SizeOf(ChunkSeqNo));
+    CalcCrc32(ChunkCrc, Frame.IDATMemory.Memory, Frame.IDATMemory.Size);
+    ChunkCrc := SwapEndianLongWord(ChunkCrc xor $FFFFFFFF);
+    // Write out all fdAT data
+    GetIO.Write(Handle, @Chunk, SizeOf(Chunk));
+    GetIO.Write(Handle, @ChunkSeqNo, SizeOf(ChunkSeqNo));
+    GetIO.Write(Handle, Frame.IDATMemory.Memory, Frame.IDATMemory.Size);
+    GetIO.Write(Handle, @ChunkCrc, SizeOf(ChunkCrc));
+  end;
+
+  procedure WriteGlobalMetaDataChunks(Frame: TFrameInfo);
+  var
+    XRes, YRes: Single;
+  begin
+    if FileFormat.FMetadata.GetPhysicalPixelSize(ruDpm, XRes, YRes, True) then
+    begin
+      // Save pHYs chunk
+      Frame.pHYs.UnitSpecifier := 1;
+      // PNG stores physical resolution as dots per meter
+      Frame.pHYs.PixelsPerUnitX := Round(XRes);
+      Frame.pHYs.PixelsPerUnitY := Round(YRes);
+
+      Chunk.DataSize := SizeOf(Frame.pHYs);
+      Chunk.ChunkID := pHYsChunk;
+      SwapEndianLongWord(@Frame.pHYs, SizeOf(Frame.pHYs) div SizeOf(LongWord));
+      WriteChunk(Chunk, @Frame.pHYs);
+    end;
+  end;
+
+  procedure WritePNGMainImageChunks(Frame: TFrameInfo);
+  begin
+    with Frame do
+    begin
+      // Write IHDR chunk
+      Chunk.DataSize := SizeOf(IHDR);
+      Chunk.ChunkID := IHDRChunk;
+      WriteChunk(Chunk, @IHDR);
+      // Write PLTE chunk if data is present
+      if Palette <> nil then
+      begin
+        Chunk.DataSize := PaletteEntries * SizeOf(TColor24Rec);
+        Chunk.ChunkID := PLTEChunk;
+        WriteChunk(Chunk, Palette);
+      end;
+      // Write tRNS chunk if data is present
+      if Transparency <> nil then
+      begin
+        Chunk.DataSize := TransparencySize;
+        Chunk.ChunkID := tRNSChunk;
+        WriteChunk(Chunk, Transparency);
+      end;
+    end;
+    // Write metadata related chunks
+    WriteGlobalMetaDataChunks(Frame);
+  end;
+
+begin
+  Result := False;
+  SeqNo := 0;
+
+  case FileType of
+    ngPNG, ngAPNG: GetIO.Write(Handle, @PNGSignature, SizeOf(TChar8));
+    ngMNG: GetIO.Write(Handle, @MNGSignature, SizeOf(TChar8));
+    ngJNG: GetIO.Write(Handle, @JNGSignature, SizeOf(TChar8));
+  end;
+
+  if FileType = ngMNG then
+  begin
+    // MNG - main header before frames
+    SwapEndianLongWord(@MHDR, SizeOf(MHDR) div SizeOf(LongWord));
+    Chunk.DataSize := SizeOf(MHDR);
+    Chunk.ChunkID := MHDRChunk;
+    WriteChunk(Chunk, @MHDR);
+  end
+  else if FileType = ngAPNG then
+  begin
+    // APNG - IHDR and global chunks for all frames, then acTL chunk, then frames
+    // (fcTL+IDAT, fcTL+fdAT, fcTL+fdAT, fcTL+fdAT, ....)
+    WritePNGMainImageChunks(Frames[0]);
+
+    // Animation control chunk
+    acTL.NumFrames := Length(Frames);
+    if FileFormat.FMetadata.HasMetaItemForSaving(SMetaAnimationLoops) then
+    begin
+      // Number of plays of APNG animation
+      acTL.NumPlay:= FileFormat.FMetadata.MetaItemsForSaving[SMetaAnimationLoops];
+    end
+    else
+      acTL.NumPlay := 0;
+    SwapEndianLongWord(@acTL, SizeOf(acTL) div SizeOf(LongWord));
+
+    Chunk.DataSize := SizeOf(acTL);
+    Chunk.ChunkID := acTLChunk;
+    WriteChunk(Chunk, @acTL);
+  end;
+
+  for I := 0 to Length(Frames) - 1 do
+  with Frames[I] do
+  begin
+    if IsJpegFrame then
+    begin
+      // Write JHDR chunk
+      Chunk.DataSize := SizeOf(JHDR);
+      Chunk.ChunkID := JHDRChunk;
+      WriteChunk(Chunk, @JHDR);
+      // Write metadata related chunks
+      WriteGlobalMetaDataChunks(Frames[I]);
+      // Write JNG image data
+      Chunk.DataSize := JDATMemory.Size;
+      Chunk.ChunkID := JDATChunk;
+      WriteChunk(Chunk, JDATMemory.Memory);
+      // Write alpha channel if present
+      if JHDR.AlphaSampleDepth > 0 then
+      begin
+        if JHDR.AlphaCompression = 0 then
+        begin
+          // Alpha is PNG compressed
+          Chunk.DataSize := IDATMemory.Size;
+          Chunk.ChunkID := IDATChunk;
+          WriteChunk(Chunk, IDATMemory.Memory);
+        end
+        else
+        begin
+          // Alpha is JNG compressed
+          Chunk.DataSize := JDAAMemory.Size;
+          Chunk.ChunkID := JDAAChunk;
+          WriteChunk(Chunk, JDAAMemory.Memory);
+        end;
+      end;
+      // Write image end
+      Chunk.DataSize := 0;
+      Chunk.ChunkID := IENDChunk;
+      WriteChunk(Chunk, nil);
+    end
+    else if FileType <> ngAPNG then
+    begin
+      // Regular PNG frame (single PNG image or MNG frame)
+      WritePNGMainImageChunks(Frames[I]);
+      // Write PNG image data
+      Chunk.DataSize := IDATMemory.Size;
+      Chunk.ChunkID := IDATChunk;
+      WriteChunk(Chunk, IDATMemory.Memory);
+      // Write image end
+      Chunk.DataSize := 0;
+      Chunk.ChunkID := IENDChunk;
+      WriteChunk(Chunk, nil);
+    end
+    else if FileType = ngAPNG then
+    begin
+      // APNG frame - Write fcTL before frame data
+      Chunk.DataSize := SizeOf(fcTL);
+      Chunk.ChunkID := fcTLChunk;
+      fcTl.SeqNumber := GetNextSeqNo;
+      WriteChunk(Chunk, @fcTL);
+      // Write data - IDAT for first frame and fdAT for following ones
+      if I = 0 then
+      begin
+        Chunk.DataSize := IDATMemory.Size;
+        Chunk.ChunkID := IDATChunk;
+        WriteChunk(Chunk, IDATMemory.Memory);
+      end
+      else
+        WritefdAT(Frames[I]);
+      // Write image end after last frame
+      if I = Length(Frames) - 1 then
+      begin
+        Chunk.DataSize := 0;
+        Chunk.ChunkID := IENDChunk;
+        WriteChunk(Chunk, nil);
+      end;
+    end;
+  end;
+
+  if FileType = ngMNG then
+  begin
+    Chunk.DataSize := 0;
+    Chunk.ChunkID := MENDChunk;
+    WriteChunk(Chunk, nil);
+  end;
+end;
+
+procedure TNGFileSaver.SetFileOptions;
+begin
+  PreFilter := FileFormat.FPreFilter;
+  CompressLevel := FileFormat.FCompressLevel;
+  LossyAlpha := FileFormat.FLossyAlpha;
+  Quality := FileFormat.FQuality;
+  Progressive := FileFormat.FProgressive;
+  ZLibStrategy := FileFormat.FZLibStategy;
+end;
+
+{ TAPNGAnimator class implementation }
+
+class procedure TAPNGAnimator.Animate(var Images: TDynImageDataArray;
+  const acTL: TacTL; const SrcFrames: array of TFrameInfo);
+var
+  I, SrcIdx, Offset, Len: Integer;
+  DestFrames: TDynImageDataArray;
+  SrcCanvas, DestCanvas: TImagingCanvas;
+  PreviousCache: TImageData;
+
+  function AnimatingNeeded: Boolean;
+  var
+    I: Integer;
+  begin
+    Result := False;
+    for I := 0 to Len - 1 do
+    with SrcFrames[I] do
+    begin
+      if (FrameWidth <> Integer(IHDR.Width)) or (FrameHeight <> Integer(IHDR.Height)) or (Len <> Integer(acTL.NumFrames)) or
+        (not ((fcTL.DisposeOp = DisposeOpNone) and (fcTL.BlendOp = BlendOpSource)) and
+        not ((fcTL.DisposeOp = DisposeOpBackground) and (fcTL.BlendOp = BlendOpSource)) and
+        not ((fcTL.DisposeOp = DisposeOpBackground) and (fcTL.BlendOp = BlendOpOver))) then
+      begin
+        Result := True;
+        Exit;
+      end;
+    end;
+  end;
+
+begin
+  Len := Length(SrcFrames);
+  if (Len = 0) or not AnimatingNeeded then
+    Exit;
+
+  if (Len = Integer(acTL.NumFrames) + 1) and (SrcFrames[0].fcTL.Width = 0) then
+  begin
+    // If default image (stored in IDAT chunk) isn't part of animation we ignore it
+    Offset := 1;
+    Len := Len - 1;
+  end
+  else
+    Offset := 0;
+
+  SetLength(DestFrames, Len);
+  DestCanvas := ImagingCanvases.FindBestCanvasForImage(Images[0]).Create;
+  SrcCanvas := ImagingCanvases.FindBestCanvasForImage(Images[0]).Create;
+  InitImage(PreviousCache);
+  NewImage(SrcFrames[0].IHDR.Width, SrcFrames[0].IHDR.Height, Images[0].Format, PreviousCache);
+
+  for I := 0 to Len - 1 do
+  begin
+    SrcIdx := I + Offset;
+    NewImage(SrcFrames[SrcIdx].IHDR.Width, SrcFrames[SrcIdx].IHDR.Height,
+      Images[SrcIdx].Format, DestFrames[I]);
+    if DestFrames[I].Format = ifIndex8 then
+      Move(Images[SrcIdx].Palette^, DestFrames[I].Palette^, 256 * SizeOf(TColor32));
+    DestCanvas.CreateForData(@DestFrames[I]);
+
+    if (SrcFrames[SrcIdx].fcTL.DisposeOp = DisposeOpPrevious) and (SrcFrames[SrcIdx - 1].fcTL.DisposeOp <> DisposeOpPrevious) then
+    begin
+      // Cache current output buffer so we may return to it later (previous dispose op)
+      CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height,
+        PreviousCache, 0, 0);
+    end;
+
+    if (I = 0) or (SrcIdx = 0) then
+    begin
+      // Clear whole frame with transparent black color (default for first frame)
+      DestCanvas.FillColor32 := pcClear;
+      DestCanvas.Clear;
+    end
+    else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpBackground then
+    begin
+      // Restore background color (clear) on previous frame's area and leave previous content outside of it
+      CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height,
+        DestFrames[I], 0, 0);
+      DestCanvas.FillColor32 := pcClear;
+      DestCanvas.FillRect(BoundsToRect(SrcFrames[SrcIdx - 1].fcTL.XOffset, SrcFrames[SrcIdx - 1].fcTL.YOffset,
+        SrcFrames[SrcIdx - 1].FrameWidth, SrcFrames[SrcIdx - 1].FrameHeight));
+    end
+    else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpNone then
+    begin
+      // Clone previous frame - no change to output buffer
+      CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height,
+        DestFrames[I], 0, 0);
+    end
+    else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpPrevious then
+    begin
+      // Revert to previous frame (cached, can't just restore DestFrames[I - 2])
+      CopyRect(PreviousCache, 0, 0, PreviousCache.Width, PreviousCache.Height,
+        DestFrames[I], 0, 0);
+    end;
+
+    // Copy pixels or alpha blend them over
+    if SrcFrames[SrcIdx].fcTL.BlendOp = BlendOpSource then
+    begin
+      CopyRect(Images[SrcIdx], 0, 0, Images[SrcIdx].Width, Images[SrcIdx].Height,
+        DestFrames[I], SrcFrames[SrcIdx].fcTL.XOffset, SrcFrames[SrcIdx].fcTL.YOffset);
+    end
+    else if SrcFrames[SrcIdx].fcTL.BlendOp = BlendOpOver then
+    begin
+      SrcCanvas.CreateForData(@Images[SrcIdx]);
+      SrcCanvas.DrawAlpha(SrcCanvas.ClipRect, DestCanvas,
+        SrcFrames[SrcIdx].fcTL.XOffset, SrcFrames[SrcIdx].fcTL.YOffset);
+    end;
+
+    FreeImage(Images[SrcIdx]);
+  end;
+
+  DestCanvas.Free;
+  SrcCanvas.Free;
+  FreeImage(PreviousCache);
+
+  // Assign dest frames to final output images
+  Images := DestFrames;
+end;
+
+{ TNetworkGraphicsFileFormat class implementation }
+
+procedure TNetworkGraphicsFileFormat.Define;
+begin
+  inherited;
+  FFeatures := [ffLoad, ffSave];
+
+  FPreFilter := NGDefaultPreFilter;
+  FCompressLevel := NGDefaultCompressLevel;
+  FLossyAlpha := NGDefaultLossyAlpha;
+  FLossyCompression := NGDefaultLossyCompression;
+  FQuality := NGDefaultQuality;
+  FProgressive := NGDefaultProgressive;
+  FZLibStategy := NGDefaultZLibStartegy;
+end;
+
+procedure TNetworkGraphicsFileFormat.CheckOptionsValidity;
+begin
+  // Just check if save options has valid values
+  if not (FPreFilter in [0..6]) then
+    FPreFilter := NGDefaultPreFilter;
+  if not (FCompressLevel in [0..9]) then
+    FCompressLevel := NGDefaultCompressLevel;
+  if not (FQuality in [1..100]) then
+    FQuality := NGDefaultQuality;
+end;
+
+function TNetworkGraphicsFileFormat.GetSupportedFormats: TImageFormats;
+begin
+  if FLossyCompression then
+    Result := NGLossyFormats
+  else
+    Result := NGLosslessFormats;
+end;
+
+procedure TNetworkGraphicsFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if not FLossyCompression then
+  begin
+    // Convert formats for lossless compression
+    if Info.HasGrayChannel then
+    begin
+      if Info.HasAlphaChannel then
+      begin
+        if Info.BytesPerPixel <= 2 then
+          // Convert <= 16bit grayscale images with alpha to ifA8Gray8
+          ConvFormat := ifA8Gray8
+        else
+          // Convert > 16bit grayscale images with alpha to ifA16Gray16
+          ConvFormat := ifA16Gray16
+      end
+      else
+        // Convert grayscale images without alpha to ifGray16
+        ConvFormat := ifGray16;
+    end
+    else
+      if Info.IsFloatingPoint then
+        // Convert floating point images to 64 bit ARGB (or RGB if no alpha)
+        ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16B16G16R16, ifB16G16R16)
+      else if Info.HasAlphaChannel or Info.IsSpecial then
+        // Convert all other images with alpha or special images to A8R8G8B8
+        ConvFormat := ifA8R8G8B8
+      else
+        // Convert images without alpha to R8G8B8
+        ConvFormat := ifR8G8B8;
+  end
+  else
+  begin
+    // Convert formats for lossy compression
+    if Info.HasGrayChannel then
+      ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8Gray8, ifGray8)
+    else
+      ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8);
+  end;
+
+  ConvertImage(Image, ConvFormat);
+end;
+
+function TNetworkGraphicsFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  ReadCount: LongInt;
+  Sig: TChar8;
+begin
+  Result := False;
+  if Handle <> nil then
+    with GetIO do
+    begin
+      FillChar(Sig, SizeOf(Sig), 0);
+      ReadCount := Read(Handle, @Sig, SizeOf(Sig));
+      Seek(Handle, -ReadCount, smFromCurrent);
+      Result := (ReadCount = SizeOf(Sig)) and (Sig = FSignature);
+    end;
+end;
+
+{ TPNGFileFormat class implementation }
+
+procedure TPNGFileFormat.Define;
+begin
+  inherited;
+  FName := SPNGFormatName;
+  FFeatures := FFeatures + [ffMultiImage];
+  FLoadAnimated := PNGDefaultLoadAnimated;
+  AddMasks(SPNGMasks);
+
+  FSignature := PNGSignature;
+
+  RegisterOption(ImagingPNGPreFilter, @FPreFilter);
+  RegisterOption(ImagingPNGCompressLevel, @FCompressLevel);
+  RegisterOption(ImagingPNGLoadAnimated, @FLoadAnimated);
+  RegisterOption(ImagingPNGZLibStrategy, @FZLibStategy);
+end;
+
+function TPNGFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  I, Len: LongInt;
+  NGFileLoader: TNGFileLoader;
+begin
+  Result := False;
+  NGFileLoader := TNGFileLoader.Create(Self);
+  try
+    // Use NG file parser to load file
+    if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then
+    begin
+      Len := Length(NGFileLoader.Frames);
+      SetLength(Images, Len);
+      for I := 0 to Len - 1 do
+      with NGFileLoader.Frames[I] do
+      begin
+        // Build actual image bits
+        if not IsJpegFrame then
+          NGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight, IHDR, IDATMemory, Images[I]);
+        // Build palette, aply color key or background
+
+        NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[I], Images[I]);
+        Result := True;
+      end;
+      // Animate APNG images
+      if (NGFileLoader.FileType = ngAPNG) and FLoadAnimated then
+        TAPNGAnimator.Animate(Images, NGFileLoader.acTL, NGFileLoader.Frames);
+    end;
+  finally
+    NGFileLoader.LoadMetaData; // Store metadata
+    NGFileLoader.Free;
+  end;
+end;
+
+function TPNGFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+var
+  I: Integer;
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+  NGFileSaver: TNGFileSaver;
+  DefaultFormat: TImageFormat;
+  Screen: TImageData;
+  AnimWidth, AnimHeight: Integer;
+begin
+  Result := False;
+  DefaultFormat := ifDefault;
+  AnimWidth := 0;
+  AnimHeight := 0;
+  NGFileSaver := TNGFileSaver.Create(Self);
+
+  // Save images with more frames as APNG format
+  if Length(Images) > 1 then
+  begin
+    NGFileSaver.FileType := ngAPNG;
+    // Get max dimensions of frames
+    AnimWidth := Images[FFirstIdx].Width;
+    AnimHeight := Images[FFirstIdx].Height;
+    for I := FFirstIdx + 1 to FLastIdx do
+    begin
+      AnimWidth := Max(AnimWidth, Images[I].Width);
+      AnimHeight := Max(AnimHeight, Images[I].Height);
+    end;
+  end
+  else
+    NGFileSaver.FileType := ngPNG;
+
+  NGFileSaver.SetFileOptions;
+
+  with NGFileSaver do
+  try
+    // Store all frames to be saved frames file saver
+    for I := FFirstIdx to FLastIdx do
+    begin
+      if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then
+      try
+        if FileType = ngAPNG then
+        begin
+          // IHDR chunk is shared for all frames so all frames must have the
+          // same data format as the first image.
+          if I = FFirstIdx then
+          begin
+            DefaultFormat := ImageToSave.Format;
+            // Subsequenet frames may be bigger than the first one.
+            // APNG doens't support this - max allowed size is what's written in
+            // IHDR - size of main/default/first image. If some frame is
+            // bigger than the first one we need to resize (create empty bigger
+            // image and copy) the first frame so all following frames could fit to
+            // its area.
+            if (ImageToSave.Width <> AnimWidth) or (ImageToSave.Height <> AnimHeight) then
+            begin
+              InitImage(Screen);
+              NewImage(AnimWidth, AnimHeight, ImageToSave.Format, Screen);
+              CopyRect(ImageToSave, 0, 0, ImageToSave.Width, ImageToSave.Height, Screen, 0, 0);
+              if MustBeFreed then
+                FreeImage(ImageToSave);
+              ImageToSave := Screen;
+            end;
+          end
+          else if ImageToSave.Format <> DefaultFormat then
+          begin
+            if MustBeFreed then
+              ConvertImage(ImageToSave, DefaultFormat)
+            else
+            begin
+              CloneImage(Images[I], ImageToSave);
+              ConvertImage(ImageToSave, DefaultFormat);
+              MustBeFreed := True;
+            end;
+          end;
+        end;
+
+        // Add image as PNG frame
+        AddFrame(ImageToSave, False);
+      finally
+        if MustBeFreed then
+          FreeImage(ImageToSave);
+      end
+      else
+        Exit;
+    end;
+
+    // Finally save PNG file
+    SaveFile(Handle);
+    Result := True;
+  finally
+    NGFileSaver.Free;
+  end;
+end;
+
+{$IFNDEF DONT_LINK_MNG}
+
+{ TMNGFileFormat class implementation }
+
+procedure TMNGFileFormat.Define;
+begin
+  inherited;
+  FName := SMNGFormatName;
+  FFeatures := FFeatures + [ffMultiImage];
+  AddMasks(SMNGMasks);
+
+  FSignature := MNGSignature;
+
+  RegisterOption(ImagingMNGLossyCompression, @FLossyCompression);
+  RegisterOption(ImagingMNGLossyAlpha, @FLossyAlpha);
+  RegisterOption(ImagingMNGPreFilter, @FPreFilter);
+  RegisterOption(ImagingMNGCompressLevel, @FCompressLevel);
+  RegisterOption(ImagingMNGQuality, @FQuality);
+  RegisterOption(ImagingMNGProgressive, @FProgressive);
+end;
+
+function TMNGFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  NGFileLoader: TNGFileLoader;
+  I, Len: LongInt;
+begin
+  Result := False;
+  NGFileLoader := TNGFileLoader.Create(Self);
+  try
+    // Use NG file parser to load file
+    if NGFileLoader.LoadFile(Handle) then
+    begin
+      Len := Length(NGFileLoader.Frames);
+      if Len > 0 then
+      begin
+        SetLength(Images, Len);
+        for I := 0 to Len - 1 do
+        with NGFileLoader.Frames[I] do
+        begin
+          // Build actual image bits
+          if IsJpegFrame then
+            NGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight, JHDR, IDATMemory, JDATMemory, JDAAMemory, Images[I])
+          else
+            NGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight, IHDR, IDATMemory, Images[I]);
+          // Build palette, aply color key or background
+          NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[I], Images[I]);
+        end;
+      end
+      else
+      begin
+        // Some MNG files (with BASI-IEND streams) dont have actual pixel data
+        SetLength(Images, 1);
+        NewImage(NGFileLoader.MHDR.FrameWidth, NGFileLoader.MHDR.FrameWidth, ifDefault, Images[0]);
+      end;
+      Result := True;
+    end;
+  finally
+    NGFileLoader.LoadMetaData; // Store metadata
+    NGFileLoader.Free;
+  end;
+end;
+
+function TMNGFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+var
+  NGFileSaver: TNGFileSaver;
+  I, LargestWidth, LargestHeight: LongInt;
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+begin
+  Result := False;
+  LargestWidth := 0;
+  LargestHeight := 0;
+
+  NGFileSaver := TNGFileSaver.Create(Self);
+  NGFileSaver.FileType := ngMNG;
+  NGFileSaver.SetFileOptions;
+
+  with NGFileSaver do
+  try
+    // Store all frames to be saved frames file saver
+    for I := FFirstIdx to FLastIdx do
+    begin
+      if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then
+      try
+        // Add image as PNG or JNG frame
+        AddFrame(ImageToSave, FLossyCompression);
+        // Remember largest frame width and height
+        LargestWidth := Iff(LargestWidth < ImageToSave.Width, ImageToSave.Width, LargestWidth);
+        LargestHeight := Iff(LargestHeight < ImageToSave.Height, ImageToSave.Height, LargestHeight);
+      finally
+        if MustBeFreed then
+          FreeImage(ImageToSave);
+      end
+      else
+        Exit;
+    end;
+
+    // Fill MNG header
+    MHDR.FrameWidth := LargestWidth;
+    MHDR.FrameHeight := LargestHeight;
+    MHDR.TicksPerSecond := 0;
+    MHDR.NominalLayerCount := 0;
+    MHDR.NominalFrameCount := Length(Frames);
+    MHDR.NominalPlayTime := 0;
+    MHDR.SimplicityProfile := 473; // 111011001 binary, defines MNG-VLC with transparency and JNG support
+
+    // Finally save MNG file
+    SaveFile(Handle);
+    Result := True;
+  finally
+    NGFileSaver.Free;
+  end;
+end;
+
+{$ENDIF}
+
+{$IFNDEF DONT_LINK_JNG}
+
+{ TJNGFileFormat class implementation }
+
+procedure TJNGFileFormat.Define;
+begin
+  inherited;
+  FName := SJNGFormatName;
+  AddMasks(SJNGMasks);
+
+  FSignature := JNGSignature;
+  FLossyCompression := True;
+
+  RegisterOption(ImagingJNGLossyAlpha, @FLossyAlpha);
+  RegisterOption(ImagingJNGAlphaPreFilter, @FPreFilter);
+  RegisterOption(ImagingJNGAlphaCompressLevel, @FCompressLevel);
+  RegisterOption(ImagingJNGQuality, @FQuality);
+  RegisterOption(ImagingJNGProgressive, @FProgressive);
+
+end;
+
+function TJNGFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  NGFileLoader: TNGFileLoader;
+begin
+  Result := False;
+  NGFileLoader := TNGFileLoader.Create(Self);
+  try
+    // Use NG file parser to load file
+    if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then
+    with NGFileLoader.Frames[0] do
+    begin
+      SetLength(Images, 1);
+      // Build actual image bits
+      if IsJpegFrame then
+        NGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight, JHDR, IDATMemory, JDATMemory, JDAAMemory, Images[0]);
+      // Build palette, aply color key or background
+      NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[0], Images[0]);
+      Result := True;
+    end;
+  finally
+    NGFileLoader.LoadMetaData; // Store metadata
+    NGFileLoader.Free;
+  end;
+end;
+
+function TJNGFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+var
+  NGFileSaver: TNGFileSaver;
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+begin
+  // Make image JNG compatible, store it in saver, and save it to file
+  Result := MakeCompatible(Images[Index], ImageToSave, MustBeFreed);
+  if Result then
+  begin
+    NGFileSaver := TNGFileSaver.Create(Self);
+    with NGFileSaver do
+    try
+      FileType := ngJNG;
+      SetFileOptions;
+      AddFrame(ImageToSave, True);
+      SaveFile(Handle);
+    finally
+      // Free NG saver and compatible image
+      NGFileSaver.Free;
+      if MustBeFreed then
+        FreeImage(ImageToSave);
+    end;
+  end;
+end;
+
+{$ENDIF}
+
+initialization
+  RegisterImageFileFormat(TPNGFileFormat);
+{$IFNDEF DONT_LINK_MNG}
+  RegisterImageFileFormat(TMNGFileFormat);
+{$ENDIF}
+{$IFNDEF DONT_LINK_JNG}
+  RegisterImageFileFormat(TJNGFileFormat);
+{$ENDIF}
+finalization
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77 Changes/Bug Fixes -----------------------------------
+    - Reads and writes APNG animation loop count metadata.
+    - Writes frame delays of APNG from metadata.
+    - Fixed color keys in 8bit depth PNG/MNG loading.
+    - Fixed needless (and sometimes buggy) conversion to format with alpha
+      channel in FPC (GetMem(0) <> nil!).
+    - Added support for optional ZLib compression strategy.
+    - Added loading and saving of ifBinary (1bit black and white)
+      format images. During loading grayscale 1bpp and indexed 1bpp
+      (with only black and white colors in palette) are treated as ifBinary.
+      ifBinary are saved as 1bpp grayscale PNGs.
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Reads frame delays from APNG files into metadata.
+    - Added loading and saving of metadata from these chunks: pHYs.
+    - Simplified decoding of 1/2/4 bit images a bit (less code).
+
+  -- 0.26.3 Changes/Bug Fixes ---------------------------------
+    - Added APNG saving support.
+    - Added APNG support to NG loader and animating to PNG loader.
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - Changed file format conditional compilation to reflect changes
+      in LINK symbols.
+
+  -- 0.24.3 Changes/Bug Fixes ---------------------------------
+    - Changes for better thread safety.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added loading of global palettes and transparencies in MNG files
+      (and by doing so fixed crash when loading images with global PLTE or tRNS).
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Small changes in converting to supported formats.
+    - MakeCompatible method moved to base class, put ConvertToSupported here.
+      GetSupportedFormats removed, it is now set in constructor.
+    - Made public properties for options registered to SetOption/GetOption
+      functions.
+    - Changed extensions to filename masks.
+    - Changed SaveData, LoadData, and MakeCompatible methods according
+      to changes in base class in Imaging unit.
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - MNG and JNG support added, PNG support redesigned to support NG file handlers
+    - added classes for working with NG file formats
+    - stuff from old ImagingPng unit added and that unit was deleted
+    - unit created and initial stuff added
+
+  -- 0.15 Changes/Bug Fixes -----------------------------------
+    - when saving indexed images save alpha to tRNS?
+    - added some defines and ifdefs to dzlib unit to allow choosing
+      impaszlib, fpc's paszlib, zlibex or other zlib implementation
+    - added colorkeying support
+    - fixed 16bit channel image handling - pixels were not swapped
+    - fixed arithmetic overflow (in paeth filter) in FPC
+    - data of unknown chunks are skipped and not needlesly loaded
+
+  -- 0.13 Changes/Bug Fixes -----------------------------------
+    - adaptive filtering added to PNG saving
+    - TPNGFileFormat class added
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingOptions.inc b/src/lib/vampimg/ImagingOptions.inc
new file mode 100644 (file)
index 0000000..deb21e4
--- /dev/null
@@ -0,0 +1,216 @@
+{
+  User Options
+  Following defines and options can be changed by user.
+}
+
+{ Source options }
+
+{$DEFINE USE_INLINE}          // Use function inlining for some functions
+                              // works in Free Pascal and Delphi 9+.
+{$DEFINE USE_ASM}             // Ff defined, assembler versions of some
+                              // functions will be used (only for x86).
+
+                              // Debug options: If none of these two are defined
+                              // your project settings are used.
+{ $DEFINE IMAGING_DEBUG}      // If defined, debug info, range/IO/overflow
+                              // checking, stack frames, assertions, and
+                              // other debugging options will be turned on.
+{ $DEFINE IMAGING_RELEASE}    // If defined, all debug info is off.
+
+
+
+(* File format support linking options.
+  Define formats which you don't want to be registred automatically.
+  Default: all formats are registered = no symbols defined.
+  Example: If you want to disable JPEG support just uncomment //{$DEFINE DONT_LINK_JPEG} line
+*)
+
+//{$DEFINE DONT_LINK_JPEG}        // link support for Jpeg images
+//{$DEFINE DONT_LINK_PNG}         // link support for PNG images
+//{$DEFINE DONT_LINK_TARGA}       // link support for Targa images
+//{$DEFINE DONT_LINK_BITMAP}      // link support for Windows Bitmap images
+//{$DEFINE DONT_LINK_DDS}         // link support for DDS images
+//{$DEFINE DONT_LINK_GIF}         // link support for GIF images
+{$DEFINE DONT_LINK_MNG}         // link support for MNG images
+{$DEFINE DONT_LINK_JNG}         // link support for JNG images
+//{$DEFINE DONT_LINK_PNM}         // link support for PortableMap images (PBM, PGM, PPM, PAM, PFM)
+{$DEFINE DONT_LINK_RADHDR}      // link support for Radiance HDR/RGBE file format
+
+//{$DEFINE DONT_LINK_EXTRAS}  // link support for file formats defined in
+                             // Extras package. Exactly which formats will be
+                             // registered depends on settings in
+                             // ImagingExtras.pas unit.
+
+{ Component set used in ImagignComponents.pas unit. You usually don't need
+  to be concerned with this - proper component library is selected automatically
+  according to your compiler. }
+
+{ $DEFINE COMPONENT_SET_VCL}   // use Delphi VCL
+{ $DEFINE COMPONENT_SET_LCL}  // use Lazarus LCL (set automatically when compiling with FPC)
+
+{
+  Auto Options
+  Following options and defines are set automatically and some
+  are required for Imaging to compile successfully. Do not change
+  anything here if you don't know what you are doing.
+}
+
+{ Compiler options }
+
+{$ALIGN ON}               // Field alignment: 8 Bytes (in D6+)
+{$BOOLEVAL OFF}           // Boolean eval: off
+{$EXTENDEDSYNTAX ON}      // Extended syntax: on
+{$LONGSTRINGS ON}         // string = AnsiString: on
+{$MINENUMSIZE 4}          // Min enum size: 4 B
+{$TYPEDADDRESS OFF}       // Typed pointers: off
+{$WRITEABLECONST OFF}     // Writeable constants: off
+
+{$IFNDEF FPC}
+  {$DEFINE DCC}           // if not using FPC then DCC compiler is used (Delphi/BCB)
+                          // others are not supported
+{$ENDIF}
+
+{$IFDEF DCC}
+  {$DEFINE DELPHI}
+{$ENDIF}
+
+{$IF (Defined(DCC) and (CompilerVersion >= 18.5))}
+  {$IFDEF RELEASE}
+    {$UNDEF DEBUG} // If we are using Delphi 2007+ where you can set
+                   // DEBUG/RELEASE mode in project options and RELEASE
+                   // is currently set we undef DEBUG mode
+  {$ENDIF}
+{$IFEND}
+
+{$IF Defined(IMAGING_DEBUG)}
+  {$ASSERTIONS ON}
+  {$DEBUGINFO ON}
+  {$RANGECHECKS ON}
+  {$IOCHECKS ON}
+  {$OVERFLOWCHECKS ON}
+  {$IFDEF DCC}
+    {$OPTIMIZATION OFF}
+    {$STACKFRAMES ON}
+    {$LOCALSYMBOLS ON}
+    {$DEFINE MEMCHECK}
+  {$ENDIF}
+  {$IFDEF FPC}
+    {$S+}
+    {$CHECKPOINTER ON}
+  {$ENDIF}
+{$ELSEIF Defined(IMAGING_RELEASE)}
+  {$ASSERTIONS OFF}
+  {$DEBUGINFO OFF}
+  {$RANGECHECKS OFF}
+  {$IOCHECKS OFF}
+  {$OVERFLOWCHECKS OFF}
+  {$IFDEF DCC}
+    {$OPTIMIZATION ON}
+    {$STACKFRAMES OFF}
+    {$LOCALSYMBOLS OFF}
+  {$ENDIF}
+  {$IFDEF FPC}
+    {$S-}
+  {$ENDIF}
+{$IFEND}
+
+{$IF Defined (CPU86) and not Defined(CPUX86)}
+  {$DEFINE CPUX86} // Compatibility with Delphi
+{$IFEND}
+
+{$IF Defined (CPUX86_64) and not Defined(CPUX64)}
+  {$DEFINE CPUX64} // Compatibility with Delphi
+{$IFEND}
+
+{$IF Defined (DARWIN) and not Defined(MACOSX)}
+  {$DEFINE MACOS} // Compatibility with Delphi
+{$IFEND}
+
+{$IF Defined(DCC) and (CompilerVersion < 23)}
+  {$DEFINE CPUX86} // Compatibility with older Delphi
+{$IFEND}
+
+{ Compiler capabilities }
+
+// Define if compiler supports inlining of functions and procedures
+{$IF (Defined(DCC) and (CompilerVersion >= 17)) or Defined(FPC)}
+  {$DEFINE HAS_INLINE}
+{$IFEND}
+
+// Define if compiler supports advanced records with methods
+{$IF (Defined(DCC) and (CompilerVersion >= 18)) or
+  (Defined(FPC) and (FPC_FULLVERSION >= 20600))}
+  {$DEFINE HAS_ADVANCED_RECORDS}
+{$IFEND}
+
+// Define if compiler supports operator overloading
+// (unfortunately Delphi and FPC operator overloading is not compatible).
+// FPC supports Delphi compatible operator overloads since 2.6.0
+{$IF (Defined(DCC) and (CompilerVersion >= 18)) or
+  (Defined(FPC) and (FPC_FULLVERSION >= 20600))}
+  {$DEFINE HAS_OPERATOR_OVERLOADING}
+{$IFEND}
+
+// Anonymous methods
+{$IF Defined(DCC) and (CompilerVersion >= 20) }
+  {$DEFINE HAS_ANON_METHODS}
+{$IFEND}
+
+// Generic types (Delphi and FPC implementations incompatible).
+// Update: FPC supports Delphi compatible generics since 2.6.0
+{$IF (Defined(DCC) and (CompilerVersion >= 20)) or
+  (Defined(FPC) and (FPC_FULLVERSION >= 20600))}
+  {$DEFINE HAS_GENERICS}
+{$IFEND}
+
+{ Imaging options check}
+
+{$IFNDEF HAS_INLINE}
+  {$UNDEF USE_INLINE}
+{$ENDIF}
+
+{$IF not Defined(CPUX86)}
+  {$UNDEF USE_ASM}
+{$IFEND}
+
+{$IFDEF FPC}
+  {$DEFINE COMPONENT_SET_LCL}
+  {$UNDEF COMPONENT_SET_VCL}
+{$ENDIF}
+
+{$IFDEF DELPHI}
+  {$UNDEF COMPONENT_SET_LCL}
+  {$DEFINE COMPONENT_SET_VCL}
+{$ENDIF}
+
+{ Platform options }
+
+{$IF Defined(WIN32) or Defined(WIN64)}
+  {$DEFINE MSWINDOWS}
+{$IFEND}
+
+{$IFDEF LINUX}
+  {$DEFINE UNIX}
+{$ENDIF}
+
+{ More compiler options }
+
+{$IFDEF FPC}               // Free Pascal options - some options set above (like min enum size)
+                           // are reset to defaults by setting {$MODE} so they are
+                           // redeclared here
+  {$MODE DELPHI}           // compatible with delphi
+  {$GOTO ON}               // alow goto
+  {$PACKRECORDS 8}         // same as ALING 8 for Delphi
+  {$PACKENUM 4}            // Min enum size: 4 B
+  {$IFDEF CPU86}
+    {$ASMMODE INTEL}       // intel assembler mode
+  {$ENDIF}
+{$ENDIF}
+
+{$IFDEF HAS_INLINE}
+  {$INLINE ON}             // turns inlining on for compilers that support it
+{$ENDIF}
+
+{$WARNINGS OFF}
+{$HINTS OFF}
+{$NOTES OFF}
diff --git a/src/lib/vampimg/ImagingPcx.pas b/src/lib/vampimg/ImagingPcx.pas
new file mode 100644 (file)
index 0000000..d278542
--- /dev/null
@@ -0,0 +1,375 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader for ZSoft Paintbrush images known as PCX.}
+unit ImagingPcx;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  ImagingTypes, Imaging, ImagingFormats, ImagingUtility, ImagingIO;
+
+type
+  { Class for loading  ZSoft Paintbrush images known as PCX. It is old
+    format which can store 1bit, 2bit, 4bit, 8bit, and 24bit (and 32bit but is
+    probably non-standard) images. Only loading is supported (you can still come
+    accross some PCX files) but saving is not (I don't wont this venerable format
+    to spread).}
+  TPCXFileFormat = class(TImageFileFormat)
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  end;
+
+implementation
+
+const
+  SPCXFormatName = 'ZSoft Paintbrush Image';
+  SPCXMasks      = '*.pcx';
+
+type
+  TPCXHeader = packed record
+    Id: Byte;            // Always $0A
+    Version: Byte;       // 0, 2, 3, 4, 5
+    Encoding: Byte;      // 0, 1
+    BitsPerPixel: Byte;  // 1, 2, 4, 8
+    X0, Y0: Word;        // Image window top-left
+    X1, Y1: Word;        // Image window bottom-right
+    DpiX: Word;
+    DpiY: Word;
+    Palette16: array [0..15] of TColor24Rec;
+    Reserved1: Byte;
+    Planes: Byte;        // 1, 3, 4
+    BytesPerLine: Word;
+    PaletteType: Word;   // 1: color or s/w   2: grayscale
+    Reserved2: array [0..57] of Byte;
+  end;
+
+{ TPCXFileFormat }
+
+procedure TPCXFileFormat.Define;
+begin
+  inherited;
+  FName := SPCXFormatName;
+  FFeatures := [ffLoad];
+
+  AddMasks(SPCXMasks);
+end;
+
+function TPCXFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+const
+  ifMono: TImageFormat = TImageFormat(250);
+  ifIndex2: TImageFormat = TImageFormat(251);
+  ifIndex4: TImageFormat = TImageFormat(252);
+var
+  Hdr: TPCXHeader;
+  PalID, B: Byte;
+  PalPCX: TPalette24Size256;
+  FileDataFormat: TImageFormat;
+  I, J, UncompSize, BytesPerLine, ByteNum, BitNum: LongInt;
+  UncompData, RowPointer, PixelIdx: PByte;
+  Pixel24: PColor24Rec;
+  Pixel32: PColor32Rec;
+  AlphaPlane, RedPlane, GreenPlane, BluePlane,
+  Plane1, Plane2, Plane3, Plane4: PByteArray;
+
+  procedure RleDecode(Target: PByte; UnpackedSize: LongInt);
+  var
+    Count: LongInt;
+    Source: Byte;
+  begin
+    while UnpackedSize > 0 do
+    with GetIO do
+    begin
+      GetIO.Read(Handle, @Source, SizeOf(Source));
+      if (Source and $C0) = $C0 then
+      begin
+        // RLE data
+        Count := Source and $3F;
+        if UnpackedSize < Count then
+          Count := UnpackedSize;
+        Read(Handle, @Source, SizeOf(Source));
+        FillChar(Target^, Count, Source);
+        //Inc(Source);
+        Inc(Target, Count);
+        Dec(UnpackedSize, Count);
+      end
+      else
+      begin
+        // Uncompressed data
+        Target^ := Source;
+        Inc(Target);
+        Dec(UnpackedSize);
+      end;
+    end;
+  end;
+
+begin
+  Result := False;
+  SetLength(Images, 1);
+  with GetIO, Images[0] do
+  begin
+    // Read PCX header and store input position (start of image data)
+    Read(Handle, @Hdr, SizeOf(Hdr));
+    FileDataFormat := ifUnknown;
+
+    // Determine image's data format and find its Imaging equivalent
+    // (using some custom TImageFormat constants)
+    case Hdr.BitsPerPixel of
+      1:
+        case Hdr.Planes of
+          1: FileDataFormat := ifMono;
+          4: FileDataFormat := ifIndex4;
+        end;
+      2: FileDataFormat := ifIndex2;
+      4: FileDataFormat := ifIndex4;
+      8:
+        case Hdr.Planes of
+          1: FileDataFormat := ifIndex8;
+          3: FileDataFormat := ifR8G8B8;
+          4: FileDataFormat := ifA8R8G8B8;
+        end;
+    end;
+
+    // No compatible Imaging format found, exit
+    if FileDataFormat = ifUnknown then
+      Exit;
+
+    // Get width, height, and output data format (unsupported formats
+    // like ifMono are converted later to ifIndex8)
+    Width := Hdr.X1 - Hdr.X0 + 1;
+    Height := Hdr.Y1 - Hdr.Y0 + 1;
+    if FileDataFormat in [ifIndex8, ifR8G8B8] then
+      Format := FileDataFormat
+    else
+      Format := ifIndex8;
+
+    NewImage(Width, Height, Format, Images[0]);
+
+    if not (FileDataFormat in [ifIndex8, ifR8G8B8]) then
+    begin
+      // other formats use palette embedded to file header
+      for I := Low(Hdr.Palette16) to High(Hdr.Palette16) do
+      begin
+        Palette[I].A := $FF;
+        Palette[I].R := Hdr.Palette16[I].B;
+        Palette[I].G := Hdr.Palette16[I].G;
+        Palette[I].B := Hdr.Palette16[I].R;
+      end;
+    end;
+
+    // Now we determine various data sizes
+    BytesPerLine := Hdr.BytesPerLine * Hdr.Planes;
+    UncompSize := BytesPerLine * Height;
+
+    GetMem(UncompData, UncompSize);
+    try
+      if Hdr.Encoding = 1 then
+      begin
+        // Image data is compressed -> read and decompress
+        RleDecode(UncompData, UncompSize);
+      end
+      else
+      begin
+        // Just read uncompressed data
+        Read(Handle, UncompData, UncompSize);
+      end;
+
+      if FileDataFormat in [ifR8G8B8, ifA8R8G8B8] then
+      begin
+        // RGB and ARGB images are stored in layout different from
+        // Imaging's (and most other file formats'). First there is
+        // Width red values then there is Width green values and so on
+        RowPointer := UncompData;
+
+        if FileDataFormat = ifA8R8G8B8 then
+        begin
+          Pixel32 := Bits;
+          for I := 0 to Height - 1 do
+          begin
+            AlphaPlane := PByteArray(RowPointer);
+            RedPlane :=   @AlphaPlane[Hdr.BytesPerLine];
+            GreenPlane := @AlphaPlane[Hdr.BytesPerLine * 2];
+            BluePlane :=  @AlphaPlane[Hdr.BytesPerLine * 3];
+            for J := 0 to Width - 1 do
+            begin
+              Pixel32.A := AlphaPlane[J];
+              Pixel32.R := RedPlane[J];
+              Pixel32.G := GreenPlane[J];
+              Pixel32.B := BluePlane[J];
+              Inc(Pixel32);
+            end;
+            Inc(RowPointer, BytesPerLine);
+          end;
+        end
+        else
+        begin
+          Pixel24 := Bits;
+          for I := 0 to Height - 1 do
+          begin
+            RedPlane :=   PByteArray(RowPointer);
+            GreenPlane := @RedPlane[Hdr.BytesPerLine];
+            BluePlane :=  @RedPlane[Hdr.BytesPerLine * 2];
+            for J := 0 to Width - 1 do
+            begin
+              Pixel24.R := RedPlane[J];
+              Pixel24.G := GreenPlane[J];
+              Pixel24.B := BluePlane[J];
+              Inc(Pixel24);
+            end;
+            Inc(RowPointer, BytesPerLine);
+          end;
+        end;
+      end
+      else if FileDataFormat = ifIndex8 then
+      begin
+        // Just copy 8bit lines
+        for I := 0 to Height - 1 do
+          Move(PByteArray(UncompData)[I * Hdr.BytesPerLine], PByteArray(Bits)[I * Width], Width);
+      end
+      else if FileDataFormat = ifMono then
+      begin
+        // Convert 1bit images to ifIndex8
+        Convert1To8(UncompData, Bits, Width, Height, Hdr.BytesPerLine, False);
+      end
+      else if FileDataFormat = ifIndex2 then
+      begin
+        // Convert 2bit images to ifIndex8. Note that 2bit PCX images
+        // usually use (from specs, I've never seen one myself) CGA palette
+        // which is not array of RGB tripplets. So 2bit PCXs are loaded but
+        // their colors would be wrong
+        Convert2To8(UncompData, Bits, Width, Height, Hdr.BytesPerLine, False);
+      end
+      else if FileDataFormat = ifIndex4 then
+      begin
+        // 4bit images can be stored similar to RGB images (in four one bit planes)
+        // or like array of nibbles (which is more common)
+        if (Hdr.BitsPerPixel = 1) and (Hdr.Planes = 4) then
+        begin
+          RowPointer := UncompData;
+          PixelIdx := Bits;
+          for I := 0 to Height - 1 do
+          begin
+            Plane1 := PByteArray(RowPointer);
+            Plane2 := @Plane1[Hdr.BytesPerLine];
+            Plane3 := @Plane1[Hdr.BytesPerLine * 2];
+            Plane4 := @Plane1[Hdr.BytesPerLine * 3];
+
+            for J := 0 to Width - 1 do
+            begin
+              B := 0;
+              ByteNum := J div 8;
+              BitNum := 7 - (J mod 8);
+              if (Plane1[ByteNum] shr BitNum) and $1 <> 0 then B := B or $01;
+              if (Plane2[ByteNum] shr BitNum) and $1 <> 0 then B := B or $02;
+              if (Plane3[ByteNum] shr BitNum) and $1 <> 0 then B := B or $04;
+              if (Plane4[ByteNum] shr BitNum) and $1 <> 0 then B := B or $08;
+              PixelIdx^ := B;
+              Inc(PixelIdx);
+            end;
+            Inc(RowPointer, BytesPerLine);
+          end;
+        end
+        else if (Hdr.BitsPerPixel = 4) and (Hdr.Planes = 1) then
+        begin
+          // Convert 4bit images to ifIndex8
+          Convert4To8(UncompData, Bits, Width, Height, Hdr.BytesPerLine, False);
+        end
+      end;
+
+      if FileDataFormat = ifIndex8 then
+      begin
+        // 8bit palette is appended at the end of the file
+        // with $0C identifier
+        //Seek(Handle, -769, smFromEnd);
+        Read(Handle, @PalID, SizeOf(PalID));
+        if PalID = $0C then
+        begin
+          Read(Handle, @PalPCX, SizeOf(PalPCX));
+          for I := Low(PalPCX) to High(PalPCX) do
+          begin
+            Palette[I].A := $FF;
+            Palette[I].R := PalPCX[I].B;
+            Palette[I].G := PalPCX[I].G;
+            Palette[I].B := PalPCX[I].R;
+          end;
+        end
+        else
+          Seek(Handle, -SizeOf(PalID), smFromCurrent);
+      end;
+
+    finally
+      FreeMem(UncompData);
+    end;
+    Result := True;
+  end;
+end;
+
+function TPCXFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Hdr: TPCXHeader;
+  ReadCount: LongInt;
+begin
+  Result := False;
+  if Handle <> nil then
+  begin
+    ReadCount := GetIO.Read(Handle, @Hdr, SizeOf(Hdr));
+    GetIO.Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (ReadCount >= SizeOf(Hdr)) and
+      (Hdr.Id = $0A) and
+      (Hdr.Version in [0, 2, 3, 4, 5]) and
+      (Hdr.Encoding in [0..1]) and
+      (Hdr.BitsPerPixel in [1, 2, 4, 8]) and
+      (Hdr.Planes in [1, 3, 4]) and
+      (Hdr.PaletteType in [1..2]);
+  end;
+
+end;
+
+initialization
+  RegisterImageFileFormat(TPCXFileFormat);
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Made loader stream-safe - stream position is exactly at the end of the
+      image after loading and file size doesn't need to be know during the process.
+    - Initial TPCXFileFormat class implemented.
+
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingPortableMaps.pas b/src/lib/vampimg/ImagingPortableMaps.pas
new file mode 100644 (file)
index 0000000..89d862d
--- /dev/null
@@ -0,0 +1,977 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains loader/saver for Portable Maps file format family (or PNM).
+  That includes PBM, PGM, PPM, PAM, and PFM formats.}
+unit ImagingPortableMaps;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, ImagingTypes, Imaging, ImagingFormats, ImagingUtility;
+
+type
+  { Types of pixels of PNM images.}
+  TTupleType = (ttInvalid, ttBlackAndWhite, ttGrayScale, ttRGB, ttBlackAndWhiteAlpha,
+    ttGrayScaleAlpha, ttRGBAlpha, ttGrayScaleFP, ttRGBFP);
+
+  { Record with info about PNM image used in both loading and saving functions.}
+  TPortableMapInfo = record
+    Width: LongInt;
+    Height: LongInt;
+    FormatId: AnsiChar;
+    MaxVal: LongInt;
+    BitCount: LongInt;
+    Depth: LongInt;
+    TupleType: TTupleType;
+    Binary: Boolean;
+    HasPAMHeader: Boolean;
+    IsBigEndian: Boolean;
+  end;
+
+  { Base class for Portable Map file formats (or Portable AnyMaps or PNM).
+    There are several types of PNM file formats that share common
+    (simple) structure. This class can actually load all supported PNM formats.
+    Saving is also done by this class but descendants (each for different PNM
+    format) control it.}
+  TPortableMapFileFormat = class(TImageFileFormat)
+  protected
+    FIdNumbers: TChar2;
+    FSaveBinary: LongBool;
+    FUSFormat: TFormatSettings;
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveDataInternal(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt; var MapInfo: TPortableMapInfo): Boolean;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  published
+    { If set to True images will be saved in binary format. If it is False
+      they will be saved in text format (which could result in 5-10x bigger file).
+      Default is value True. Note that PAM and PFM files are always saved in binary.}
+    property SaveBinary: LongBool read FSaveBinary write FSaveBinary;
+  end;
+
+  { Portable Bit Map is used to store monochrome 1bit images. Raster data
+    can be saved as text or binary data. Either way value of 0 represents white
+    and 1 is black. As Imaging does not have support for 1bit data formats
+    PBM images can be loaded but not saved. Loaded images are returned in
+    ifGray8 format (witch pixel values scaled from 1bit to 8bit).}
+  TPBMFileFormat = class(TPortableMapFileFormat)
+  protected
+    procedure Define; override;
+  end;
+
+  { Portable Gray Map is used to store grayscale 8bit or 16bit images.
+    Raster data can be saved as text or binary data.}
+  TPGMFileFormat = class(TPortableMapFileFormat)
+  protected
+    procedure Define; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  end;
+
+  { Portable Pixel Map is used to store RGB images with 8bit or 16bit channels.
+    Raster data can be saved as text or binary data.}
+  TPPMFileFormat = class(TPortableMapFileFormat)
+  protected
+    procedure Define; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  end;
+
+  { Portable Arbitrary Map is format that can store image data formats
+    of PBM, PGM, and PPM formats with optional alpha channel. Raster data
+    can be stored only in binary format. All data formats supported
+    by this format are ifGray8, ifGray16, ifA8Gray8, ifA16Gray16,
+    ifR8G8B8, ifR16G16R16, ifA8R8G8B8, and ifA16R16G16B16.}
+  TPAMFileFormat = class(TPortableMapFileFormat)
+  protected
+    procedure Define; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  end;
+
+  { Portable Float Map is unofficial extension of PNM format family which
+    can store images with floating point pixels. Raster data is saved in
+    binary format as array of IEEE 32 bit floating point numbers. One channel
+    or RGB images are supported by PFM format (so no alpha).}
+  TPFMFileFormat = class(TPortableMapFileFormat)
+  protected
+    procedure Define; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  end;
+
+implementation
+
+const
+  PortableMapDefaultBinary = True;
+
+  SPBMFormatName = 'Portable Bit Map';
+  SPBMMasks =      '*.pbm';
+  SPGMFormatName = 'Portable Gray Map';
+  SPGMMasks =      '*.pgm';
+  PGMSupportedFormats = [ifGray8, ifGray16];
+  SPPMFormatName = 'Portable Pixel Map';
+  SPPMMasks =      '*.ppm';
+  PPMSupportedFormats = [ifR8G8B8, ifR16G16B16];
+  SPAMFormatName = 'Portable Arbitrary Map';
+  SPAMMasks =      '*.pam';
+  PAMSupportedFormats = [ifGray8, ifGray16, ifA8Gray8, ifA16Gray16,
+    ifR8G8B8, ifR16G16B16, ifA8R8G8B8, ifA16R16G16B16];
+  SPFMFormatName = 'Portable Float Map';
+  SPFMMasks =      '*.pfm';
+  PFMSupportedFormats = [ifR32F, ifB32G32R32F];
+
+const
+  { TAB, CR, LF, and Space are used as seperators in Portable map headers and data.}
+  WhiteSpaces = [#9, #10, #13, #32];
+  SPAMWidth = 'WIDTH';
+  SPAMHeight = 'HEIGHT';
+  SPAMDepth = 'DEPTH';
+  SPAMMaxVal = 'MAXVAL';
+  SPAMTupleType = 'TUPLTYPE';
+  SPAMEndHdr = 'ENDHDR';
+
+  { Size of buffer used to speed up text PNM loading/saving.}
+  LineBufferCapacity = 16 * 1024;
+
+  TupleTypeNames: array[TTupleType] of string = (
+    'INVALID', 'BLACKANDWHITE', 'GRAYSCALE', 'RGB',
+    'BLACKANDWHITE_ALPHA', 'GRAYSCALE_ALPHA', 'RGB_ALPHA', 'GRAYSCALEFP',
+    'RGBFP');
+
+{ TPortableMapFileFormat }
+
+procedure TPortableMapFileFormat.Define;
+begin
+  inherited;
+  FFeatures := [ffLoad, ffSave];
+  FSaveBinary := PortableMapDefaultBinary;
+  FUSFormat := GetFormatSettingsForFloats;
+end;
+
+function TPortableMapFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  I, ScanLineSize, MonoSize: LongInt;
+  Dest: PByte;
+  MonoData: Pointer;
+  Info: TImageFormatInfo;
+  LineBuffer: array[0..LineBufferCapacity - 1] of AnsiChar;
+  LineEnd, LinePos: LongInt;
+  MapInfo: TPortableMapInfo;
+  LineBreak: string;
+
+  procedure CheckBuffer;
+  begin
+    if (LineEnd = 0) or (LinePos = LineEnd) then
+    begin
+      // Reload buffer if its is empty or its end was reached
+      LineEnd := GetIO.Read(Handle, @LineBuffer[0], LineBufferCapacity);
+      LinePos := 0;
+    end;
+  end;
+
+  procedure FixInputPos;
+  begin
+    // Sets input's position to its real pos as it would be without buffering
+    if LineEnd > 0 then
+    begin
+      GetIO.Seek(Handle, -LineEnd + LinePos, smFromCurrent);
+      LineEnd := 0;
+    end;
+  end;
+
+  function ReadString: string;
+  var
+    S: AnsiString;
+    C: AnsiChar;
+  begin
+    // First skip all whitespace chars
+    SetLength(S, 1);
+    repeat
+      CheckBuffer;
+      S[1] := LineBuffer[LinePos];
+      Inc(LinePos);
+      if S[1] = '#' then
+      repeat
+        // Comment detected, skip everything until next line is reached
+        CheckBuffer;
+        S[1] := LineBuffer[LinePos];
+        Inc(LinePos);
+      until S[1] = #10;
+    until not(S[1] in WhiteSpaces);
+    // Now we have reached some chars other than white space, read them until
+    // there is whitespace again
+    repeat
+      SetLength(S, Length(S) + 1);
+      CheckBuffer;
+      S[Length(S)] := LineBuffer[LinePos];
+      Inc(LinePos);
+      // Repeat until current char is whitespace or end of file is reached
+      // (Line buffer has 0 bytes which happens only on EOF)
+    until (S[Length(S)] in WhiteSpaces) or (LineEnd = 0);
+    // Get rid of last char - whitespace or null
+    SetLength(S, Length(S) - 1);
+    // Move position to the beginning of next string (skip white space - needed
+    // to make the loader stop at the right input position)
+    repeat
+      CheckBuffer;
+      C := LineBuffer[LinePos];
+      Inc(LinePos);
+    until not (C in WhiteSpaces) or (LineEnd = 0);
+    // Dec pos, current is the begining of the the string
+    Dec(LinePos);
+
+    Result := string(S);
+  end;
+
+  function ReadIntValue: LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+  begin
+    Result := StrToInt(ReadString);
+  end;
+
+  procedure FindLineBreak;
+  var
+    C: AnsiChar;
+  begin
+    LineBreak := #10;
+    repeat
+      CheckBuffer;
+      C := LineBuffer[LinePos];
+      Inc(LinePos);
+
+      if C = #13 then
+        LineBreak := #13#10;
+
+    until C = #10;
+  end;
+
+  function ParseHeader: Boolean;
+  var
+    Id: TChar2;
+    I: TTupleType;
+    TupleTypeName: string;
+    Scale: Single;
+  begin
+    Result := False;
+    with GetIO do
+    begin
+      FillChar(MapInfo, SizeOf(MapInfo), 0);
+      Read(Handle, @Id, SizeOf(Id));
+      FindLineBreak;
+
+      if Id[1] in ['1'..'6'] then
+      begin
+        // Read header for PBM, PGM, and PPM files
+        MapInfo.Width := ReadIntValue;
+        MapInfo.Height := ReadIntValue;
+
+        if Id[1] in ['1', '4'] then
+        begin
+          MapInfo.MaxVal := 1;
+          MapInfo.BitCount := 1
+        end
+        else
+        begin
+          // Read channel max value, <=255 for 8bit images, >255 for 16bit images
+          // but some programs think its max colors so put <=256 here
+          MapInfo.MaxVal := ReadIntValue;
+          MapInfo.BitCount := Iff(MapInfo.MaxVal <= 256, 8, 16);
+        end;
+
+        MapInfo.Depth := 1;
+        case Id[1] of
+          '1', '4': MapInfo.TupleType := ttBlackAndWhite;
+          '2', '5': MapInfo.TupleType := ttGrayScale;
+          '3', '6':
+            begin
+              MapInfo.TupleType := ttRGB;
+              MapInfo.Depth := 3;
+            end;
+        end;
+      end
+      else if Id[1] = '7' then
+      begin
+        // Read values from PAM header
+        // WIDTH
+        if (ReadString <> SPAMWidth) then Exit;
+        MapInfo.Width := ReadIntValue;
+        // HEIGHT
+        if (ReadString <> SPAMheight) then Exit;
+        MapInfo.Height := ReadIntValue;
+        // DEPTH
+        if (ReadString <> SPAMDepth) then Exit;
+        MapInfo.Depth := ReadIntValue;
+        // MAXVAL
+        if (ReadString <> SPAMMaxVal) then Exit;
+        MapInfo.MaxVal := ReadIntValue;
+        MapInfo.BitCount := Iff(MapInfo.MaxVal <= 256, 8, 16);
+        // TUPLETYPE
+        if (ReadString <> SPAMTupleType) then Exit;
+        TupleTypeName := ReadString;
+        for I := Low(TTupleType) to High(TTupleType) do
+          if SameText(TupleTypeName, TupleTypeNames[I]) then
+          begin
+            MapInfo.TupleType := I;
+            Break;
+          end;
+        // ENDHDR
+        if (ReadString <> SPAMEndHdr) then Exit;
+      end
+      else if Id[1] in ['F', 'f'] then
+      begin
+        // Read header of PFM file
+        MapInfo.Width := ReadIntValue;
+        MapInfo.Height := ReadIntValue;
+        Scale := StrToFloatDef(ReadString, 0, FUSFormat);
+        MapInfo.IsBigEndian := Scale > 0.0;
+        if Id[1] = 'F' then
+          MapInfo.TupleType := ttRGBFP
+        else
+          MapInfo.TupleType := ttGrayScaleFP;
+        MapInfo.Depth := Iff(MapInfo.TupleType = ttRGBFP, 3, 1);
+        MapInfo.BitCount := Iff(MapInfo.TupleType = ttRGBFP, 96, 32);
+      end;
+
+      FixInputPos;
+      MapInfo.Binary := (Id[1] in ['4', '5', '6', '7', 'F', 'f']);
+
+      if MapInfo.Binary  and not (Id[1] in ['F', 'f']) then
+      begin
+        // Mimic the behaviour of Photoshop and other editors/viewers:
+        // If linenreaks in file are DOS CR/LF 16bit binary values are
+        // little endian, Unix LF only linebreak indicates big endian.
+        MapInfo.IsBigEndian := LineBreak = #10;
+      end;
+
+      // Check if values found in header are valid
+      Result := (MapInfo.Width > 0) and (MapInfo.Height > 0) and
+        (MapInfo.BitCount in [1, 8, 16, 32, 96]) and (MapInfo.TupleType <> ttInvalid);
+      // Now check if image has proper number of channels (PAM)
+      if Result then
+        case MapInfo.TupleType of
+          ttBlackAndWhite, ttGrayScale:           Result := MapInfo.Depth = 1;
+          ttBlackAndWhiteAlpha, ttGrayScaleAlpha: Result := MapInfo.Depth = 2;
+          ttRGB:      Result := MapInfo.Depth = 3;
+          ttRGBAlpha: Result := MapInfo.Depth = 4;
+        end;
+    end;
+  end;
+
+begin
+  Result := False;
+  LineEnd := 0;
+  LinePos := 0;
+  SetLength(Images, 1);
+
+  with GetIO, Images[0] do
+  begin
+    Format := ifUnknown;
+    // Try to parse file header
+    if not ParseHeader then Exit;
+    // Select appropriate data format based on values read from file header
+    case MapInfo.TupleType of
+      ttBlackAndWhite:      Format := ifGray8;
+      ttBlackAndWhiteAlpha: Format := ifA8Gray8;
+      ttGrayScale:          Format := IffFormat(MapInfo.BitCount = 8, ifGray8, ifGray16);
+      ttGrayScaleAlpha:     Format := IffFormat(MapInfo.BitCount = 8, ifA8Gray8, ifA16Gray16);
+      ttRGB:                Format := IffFormat(MapInfo.BitCount = 8, ifR8G8B8, ifR16G16B16);
+      ttRGBAlpha:           Format := IffFormat(MapInfo.BitCount = 8, ifA8R8G8B8, ifA16R16G16B16);
+      ttGrayScaleFP:        Format := ifR32F;
+      ttRGBFP:              Format := ifB32G32R32F;
+    end;
+    // Exit if no matching data format was found
+    if Format = ifUnknown then Exit;
+
+    NewImage(MapInfo.Width, MapInfo.Height, Format, Images[0]);
+    Info := GetFormatInfo(Format);
+
+    // Now read pixels from file to dest image
+    if not MapInfo.Binary then
+    begin
+      Dest := Bits;
+      for I := 0 to Width * Height - 1 do
+      begin
+        case Format of
+          ifGray8:
+            begin
+              Dest^ := ReadIntValue;
+              if MapInfo.BitCount = 1 then
+                // If source is 1bit mono image (where 0=white, 1=black)
+                // we must scale it to 8bits
+                Dest^ := 255 - Dest^ * 255;
+            end;
+          ifGray16: PWord(Dest)^ := ReadIntValue;
+          ifR8G8B8:
+            with PColor24Rec(Dest)^ do
+            begin
+              R := ReadIntValue;
+              G := ReadIntValue;
+              B := ReadIntValue;
+            end;
+          ifR16G16B16:
+            with PColor48Rec(Dest)^ do
+            begin
+              R := ReadIntValue;
+              G := ReadIntValue;
+              B := ReadIntValue;
+            end;
+        end;
+        Inc(Dest, Info.BytesPerPixel);
+      end;
+    end
+    else
+    begin
+      if MapInfo.BitCount > 1 then
+      begin
+        if not (MapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then
+        begin
+          // Just copy bytes from binary Portable Maps (non 1bit, non FP)
+          Read(Handle, Bits, Size);
+        end
+        else
+        begin
+          Dest := Bits;
+          // FP images are in BGR order and endian swap maybe needed.
+          // Some programs store scanlines in bottom-up order but
+          // I will stick with Photoshops behaviour here
+          Read(Handle, Bits, Size);
+          if MapInfo.IsBigEndian then
+            SwapEndianLongWord(PLongWord(Dest), Size div SizeOf(LongWord));
+        end;
+
+        if MapInfo.TupleType in [ttBlackAndWhite, ttBlackAndWhiteAlpha] then
+        begin
+          // Black and white PAM files must be scaled to 8bits. Note that
+          // in PAM files 1=white, 0=black (reverse of PBM)
+          for I := 0 to Width * Height * Iff(MapInfo.TupleType = ttBlackAndWhiteAlpha, 2, 1) - 1 do
+            PByteArray(Bits)[I] := PByteArray(Bits)[I] * 255;
+        end
+        else if MapInfo.TupleType in [ttRGB, ttRGBAlpha] then
+        begin
+          // Swap channels of RGB/ARGB images. Binary RGB image files use BGR order.
+          SwapChannels(Images[0], ChannelBlue, ChannelRed);
+        end;
+
+        // Swap byte order if needed
+        if (MapInfo.BitCount = 16) and MapInfo.IsBigEndian then
+          SwapEndianWord(Bits, Width * Height * Info.BytesPerPixel div SizeOf(Word));
+      end
+      else
+      begin
+        // Handle binary PBM files (ttBlackAndWhite 1bit)
+        ScanLineSize := (Width + 7) div 8;
+        // Get total binary data size, read it from file to temp
+        // buffer and convert the data to Gray8
+        MonoSize := ScanLineSize * Height;
+        GetMem(MonoData, MonoSize);
+        try
+          Read(Handle, MonoData, MonoSize);
+          Convert1To8(MonoData, Bits, Width, Height, ScanLineSize, False);
+          // 1bit mono images must be scaled to 8bit, but inverted (where 0=white, 1=black)
+          for I := 0 to Width * Height - 1 do
+            PByteArray(Bits)[I] := 255 - PByteArray(Bits)[I] * 255;
+        finally
+          FreeMem(MonoData);
+        end;
+      end;
+    end;
+
+    FixInputPos;
+
+    if (MapInfo.MaxVal <> Pow2Int(MapInfo.BitCount) - 1) and
+      (MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha, ttRGB, ttRGBAlpha]) then
+    begin
+      Dest := Bits;
+      // Scale color values according to MaxVal we got from header
+      // if necessary.
+      for I := 0 to Width * Height * Info.BytesPerPixel div (MapInfo.BitCount shr 3) - 1 do
+      begin
+        if MapInfo.BitCount = 8 then
+          Dest^ := Dest^ * 255 div MapInfo.MaxVal
+        else
+          PWord(Dest)^ := PWord(Dest)^ * 65535 div MapInfo.MaxVal;
+        Inc(Dest, MapInfo.BitCount shr 3);
+      end;
+    end;
+
+    Result := True;
+  end;
+end;
+
+function TPortableMapFileFormat.SaveDataInternal(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: Integer; var MapInfo: TPortableMapInfo): Boolean;
+const
+  // Use Unix linebreak, for many viewers/editors it means that
+  // 16bit samples are stored as big endian - so we need to swap byte order
+  // before saving
+  LineDelimiter  = #10;
+  PixelDelimiter = #32;
+var
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+  Info: TImageFormatInfo;
+  I, LineLength: LongInt;
+  Src: PByte;
+  Pixel32: TColor32Rec;
+  Pixel64: TColor64Rec;
+  W: Word;
+
+  procedure WriteString(S: string; Delimiter: Char = LineDelimiter);
+  begin
+    SetLength(S, Length(S) + 1);
+    S[Length(S)] := Delimiter;
+  {$IF Defined(DCC) and Defined(UNICODE)}
+    GetIO.Write(Handle, @AnsiString(S)[1], Length(S));
+  {$ELSE}
+    GetIO.Write(Handle, @S[1], Length(S));
+  {$IFEND}
+    Inc(LineLength, Length(S));
+  end;
+
+  procedure WriteHeader;
+  begin
+    WriteString('P' + MapInfo.FormatId);
+    if not MapInfo.HasPAMHeader then
+    begin
+      // Write header of PGM, PPM, and PFM files
+      WriteString(IntToStr(ImageToSave.Width));
+      WriteString(IntToStr(ImageToSave.Height));
+      case MapInfo.TupleType of
+        ttGrayScale, ttRGB: WriteString(IntToStr(Pow2Int(MapInfo.BitCount) - 1));
+        ttGrayScaleFP, ttRGBFP:
+          begin
+            // Negative value indicates that raster data is saved in little endian
+            WriteString(FloatToStr(-1.0, FUSFormat));
+          end;
+      end;
+    end
+    else
+    begin
+      // Write PAM file header
+      WriteString(Format('%s %d', [SPAMWidth, ImageToSave.Width]));
+      WriteString(Format('%s %d', [SPAMHeight, ImageToSave.Height]));
+      WriteString(Format('%s %d', [SPAMDepth, MapInfo.Depth]));
+      WriteString(Format('%s %d', [SPAMMaxVal, Pow2Int(MapInfo.BitCount) - 1]));
+      WriteString(Format('%s %s', [SPAMTupleType, TupleTypeNames[MapInfo.TupleType]]));
+      WriteString(SPAMEndHdr);
+    end;
+  end;
+
+begin
+  Result := False;
+  if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
+  with GetIO, ImageToSave do
+  try
+    Info := GetFormatInfo(Format);
+    // Fill values of MapInfo record that were not filled by
+    // descendants in their SaveData methods
+    MapInfo.BitCount := (Info.BytesPerPixel div Info.ChannelCount) * 8;
+    MapInfo.Depth := Info.ChannelCount;
+    if MapInfo.TupleType = ttInvalid then
+    begin
+      if Info.HasGrayChannel then
+      begin
+        if Info.HasAlphaChannel then
+          MapInfo.TupleType := ttGrayScaleAlpha
+        else
+          MapInfo.TupleType := ttGrayScale;
+      end
+      else
+      begin
+        if Info.HasAlphaChannel then
+          MapInfo.TupleType := ttRGBAlpha
+        else
+          MapInfo.TupleType := ttRGB;
+      end;
+    end;
+    // Write file header
+    WriteHeader;
+
+    if not MapInfo.Binary then
+    begin
+      Src := Bits;
+      LineLength := 0;
+      // For each pixel find its text representation and write it to file
+      for I := 0 to Width * Height  - 1 do
+      begin
+        case Format of
+          ifGray8: WriteString(IntToStr(Src^), PixelDelimiter);
+          ifGray16: WriteString(IntToStr(PWord(Src)^), PixelDelimiter);
+          ifR8G8B8:
+            with PColor24Rec(Src)^ do
+              WriteString(SysUtils.Format('%d %d %d', [R, G, B]), PixelDelimiter);
+          ifR16G16B16:
+            with PColor48Rec(Src)^ do
+              WriteString(SysUtils.Format('%d %d %d', [R, G, B]), PixelDelimiter);
+        end;
+        // Lines in text PNM images should have length <70
+        if LineLength > 65 then
+        begin
+          LineLength := 0;
+          WriteString('', LineDelimiter);
+        end;
+        Inc(Src, Info.BytesPerPixel);
+      end;
+    end
+    else
+    begin
+      // Write binary images
+      if not (MapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then
+      begin
+        // Save integer binary images
+        if  MapInfo.BitCount = 8 then
+        begin
+          if MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then
+          begin
+            // 8bit grayscale images can be written in one Write call
+            Write(Handle, Bits, Size);
+          end
+          else
+          begin
+            // 8bit RGB/ARGB images: red and blue must be swapped and
+            // 3 or 4 bytes must be written
+            Src := Bits;
+            for I := 0 to Width * Height - 1 do
+            with PColor32Rec(Src)^ do
+            begin
+              if MapInfo.TupleType = ttRGBAlpha then
+                Pixel32.A := A;
+              Pixel32.R := B;
+              Pixel32.G := G;
+              Pixel32.B := R;
+              Write(Handle, @Pixel32, Info.BytesPerPixel);
+              Inc(Src, Info.BytesPerPixel);
+            end;
+          end;
+        end
+        else
+        begin
+          // Images with 16bit channels: make sure that channel values are saved in big endian
+          Src := Bits;
+          if MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then
+          begin
+            // 16bit grayscale image
+            for I := 0 to Width * Height * Info.BytesPerPixel div SizeOf(Word) - 1 do
+            begin
+              W := SwapEndianWord(PWord(Src)^);
+              Write(Handle, @W, SizeOf(Word));
+              Inc(Src, SizeOf(Word));
+            end;
+          end
+          else
+          begin
+            // RGB images with 16bit channels: swap RB and endian too
+            for I := 0 to Width * Height - 1 do
+            with PColor64Rec(Src)^ do
+            begin
+              if MapInfo.TupleType = ttRGBAlpha then
+                Pixel64.A := SwapEndianWord(A);
+              Pixel64.R := SwapEndianWord(B);
+              Pixel64.G := SwapEndianWord(G);
+              Pixel64.B := SwapEndianWord(R);
+              Write(Handle, @Pixel64, Info.BytesPerPixel);
+              Inc(Src, Info.BytesPerPixel);
+            end;
+          end;
+        end;
+      end
+      else
+      begin
+        // Floating point images (no need to swap endian here - little
+        // endian is specified in file header)
+        Write(Handle, Bits, Size);
+      end;
+    end;
+    Result := True;
+  finally
+    if MustBeFreed then
+      FreeImage(ImageToSave);
+  end;
+end;
+
+function TPortableMapFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Id: TChar4;
+  ReadCount: LongInt;
+begin
+  Result := False;
+  if Handle <> nil then
+  with GetIO do
+  begin
+    ReadCount := Read(Handle, @Id, SizeOf(Id));
+    Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (Id[0] = 'P') and (Id[1] in [FIdNumbers[0], FIdNumbers[1]]) and
+      (Id[2] in WhiteSpaces);
+  end;
+end;
+
+{ TPBMFileFormat }
+
+procedure TPBMFileFormat.Define;
+begin
+  inherited;
+  FName := SPBMFormatName;
+  FFeatures := [ffLoad];
+  AddMasks(SPBMMasks);
+  FIdNumbers := '14';
+end;
+
+{ TPGMFileFormat }
+
+procedure TPGMFileFormat.Define;
+begin
+  inherited;
+  FName := SPGMFormatName;
+  FSupportedFormats := PGMSupportedFormats;
+  AddMasks(SPGMMasks);
+  RegisterOption(ImagingPGMSaveBinary, @FSaveBinary);
+  FIdNumbers := '25';
+end;
+
+function TPGMFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: Integer): Boolean;
+var
+  MapInfo: TPortableMapInfo;
+begin
+  FillChar(MapInfo, SizeOf(MapInfo), 0);
+  if FSaveBinary then
+    MapInfo.FormatId := FIdNumbers[1]
+  else
+    MapInfo.FormatId := FIdNumbers[0];
+  MapInfo.Binary := FSaveBinary;
+  Result := SaveDataInternal(Handle, Images, Index, MapInfo);
+end;
+
+procedure TPGMFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if Info.IsFloatingPoint then
+    // All FP images go to 16bit
+    ConvFormat :=  ifGray16
+  else if Info.HasGrayChannel then
+    // Grayscale will be 8 or 16 bit - depends on input's bitcount
+    ConvFormat := IffFormat(Info.BytesPerPixel div Info.ChannelCount > 1,
+      ifGray16, ifGray8)
+  else if Info.BytesPerPixel > 4 then
+    // Large bitcounts -> 16bit
+    ConvFormat := ifGray16
+  else
+    // Rest of the formats -> 8bit
+    ConvFormat := ifGray8;
+
+  ConvertImage(Image, ConvFormat);
+end;
+
+{ TPPMFileFormat }
+
+procedure TPPMFileFormat.Define;
+begin
+  inherited;
+  FName := SPPMFormatName;
+  FSupportedFormats := PPMSupportedFormats;
+  AddMasks(SPPMMasks);
+  RegisterOption(ImagingPPMSaveBinary, @FSaveBinary);
+  FIdNumbers := '36';
+end;
+
+function TPPMFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: Integer): Boolean;
+var
+  MapInfo: TPortableMapInfo;
+begin
+  FillChar(MapInfo, SizeOf(MapInfo), 0);
+  if FSaveBinary then
+    MapInfo.FormatId := FIdNumbers[1]
+  else
+    MapInfo.FormatId := FIdNumbers[0];
+  MapInfo.Binary := FSaveBinary;
+  Result := SaveDataInternal(Handle, Images, Index, MapInfo);
+end;
+
+procedure TPPMFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if Info.IsFloatingPoint then
+    // All FP images go to 48bit RGB
+    ConvFormat :=  ifR16G16B16
+  else if Info.HasGrayChannel then
+    // Grayscale will be 24 or 48 bit RGB - depends on input's bitcount
+    ConvFormat := IffFormat(Info.BytesPerPixel div Info.ChannelCount > 1,
+      ifR16G16B16, ifR8G8B8)
+  else if Info.BytesPerPixel > 4 then
+    // Large bitcounts -> 48bit RGB
+    ConvFormat := ifR16G16B16
+  else
+    // Rest of the formats -> 24bit RGB
+    ConvFormat := ifR8G8B8;
+
+  ConvertImage(Image, ConvFormat);
+end;
+
+{ TPAMFileFormat }
+
+procedure TPAMFileFormat.Define;
+begin
+  inherited;
+  FName := SPAMFormatName;
+  FSupportedFormats := PAMSupportedFormats;
+  AddMasks(SPAMMasks);
+  FIdNumbers := '77';
+end;
+
+function TPAMFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: Integer): Boolean;
+var
+  MapInfo: TPortableMapInfo;
+begin
+  FillChar(MapInfo, SizeOf(MapInfo), 0);
+  MapInfo.FormatId := FIdNumbers[0];
+  MapInfo.Binary := True;
+  MapInfo.HasPAMHeader := True;
+  Result := SaveDataInternal(Handle, Images, Index, MapInfo);
+end;
+
+procedure TPAMFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if Info.IsFloatingPoint then
+    ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16R16G16B16, ifR16G16B16)
+  else if Info.HasGrayChannel then
+    ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray16)
+  else
+  begin
+    if Info.BytesPerPixel <= 4 then
+      ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8)
+    else
+      ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16R16G16B16, ifR16G16B16);
+  end;
+  ConvertImage(Image, ConvFormat);
+end;
+
+{ TPFMFileFormat }
+
+procedure TPFMFileFormat.Define;
+begin
+  inherited;
+  FName := SPFMFormatName;
+  AddMasks(SPFMMasks);
+  FIdNumbers := 'Ff';
+  FSupportedFormats := PFMSupportedFormats;
+end;
+
+function TPFMFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: Integer): Boolean;
+var
+  Info: TImageFormatInfo;
+  MapInfo: TPortableMapInfo;
+begin
+  FillChar(MapInfo, SizeOf(MapInfo), 0);
+  Info := GetFormatInfo(Images[Index].Format);
+
+  if (Info.ChannelCount > 1) or Info.IsIndexed then
+    MapInfo.TupleType := ttRGBFP
+  else
+    MapInfo.TupleType := ttGrayScaleFP;
+
+  if MapInfo.TupleType = ttGrayScaleFP then
+    MapInfo.FormatId := FIdNumbers[1]
+  else
+    MapInfo.FormatId := FIdNumbers[0];
+
+  MapInfo.Binary := True;
+  Result := SaveDataInternal(Handle, Images, Index, MapInfo);
+end;
+
+procedure TPFMFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+begin
+  if (Info.ChannelCount > 1) or Info.IsIndexed then
+    ConvertImage(Image, ifB32G32R32F)
+  else
+    ConvertImage(Image, ifR32F);
+end;
+
+initialization
+  RegisterImageFileFormat(TPBMFileFormat);
+  RegisterImageFileFormat(TPGMFileFormat);
+  RegisterImageFileFormat(TPPMFileFormat);
+  RegisterImageFileFormat(TPAMFileFormat);
+  RegisterImageFileFormat(TPFMFileFormat);
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 Changes/Bug Fixes -----------------------------------
+    - Native RGB floating point format of PFM is now supported by Imaging
+      so we use it now for saving instead of A32B32G32B32.
+    - String to float formatting changes (don't change global settings).
+
+  -- 0.26.3 Changes/Bug Fixes -----------------------------------
+    - Fixed D2009 Unicode related bug in PNM saving.
+
+  -- 0.24.3 Changes/Bug Fixes -----------------------------------
+    - Improved compatibility of 16bit/component image loading.
+    - Changes for better thread safety.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Made modifications to ASCII PNM loading to be more "stream-safe".
+    - Fixed bug: indexed images saved as grayscale in PFM.
+    - Changed converting to supported formats little bit.
+    - Added scaling of channel values (non-FP and non-mono images) according
+      to MaxVal.
+    - Added buffering to loading of PNM files. More than 10x faster now
+      for text files.
+    - Added saving support to PGM, PPM, PAM, and PFM format.
+    - Added PFM file format.
+    - Initial version created.
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingPsd.pas b/src/lib/vampimg/ImagingPsd.pas
new file mode 100644 (file)
index 0000000..cd395ca
--- /dev/null
@@ -0,0 +1,800 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader/saver for Photoshop PSD image format.}
+unit ImagingPsd;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, ImagingTypes, Imaging, ImagingColors, ImagingUtility;
+
+type
+  { Class for loading and saving Adobe Photoshop PSD images.
+    Loading and saving of indexed, grayscale, RGB(A), HDR (FP32), and CMYK
+    (auto converted to RGB) images is supported. Non-HDR gray, RGB,
+    and CMYK images can have 8bit or 16bit color channels.
+    There is no support for loading mono images, duotone images are treated
+    like grayscale images, and multichannel and CIE Lab images are loaded as
+    RGB images but without actual conversion to RGB color space.
+    Also no layer information is loaded.}
+  TPSDFileFormat = class(TImageFileFormat)
+  private
+    FSaveAsLayer: LongBool;
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  published
+    property SaveAsLayer: LongBool read FSaveAsLayer write FSaveAsLayer;
+  end;
+
+implementation
+
+uses
+  ImagingExtras;
+
+const
+  SPSDFormatName = 'Photoshop Image';
+  SPSDMasks      = '*.psd,*.pdd';
+  PSDSupportedFormats: TImageFormats = [ifIndex8, ifGray8, ifA8Gray8,
+    ifR8G8B8, ifA8R8G8B8, ifGray16, ifA16Gray16, ifR16G16B16, ifA16R16G16B16,
+    ifR32F, ifR32G32B32F, ifA32R32G32B32F];
+  PSDDefaultSaveAsLayer = True;
+
+const
+  SPSDMagic = '8BPS';
+  CompressionNone: Word = 0;
+  CompressionRLE: Word  = 1;
+
+type
+  {$MINENUMSIZE 2}
+  { PSD Image color mode.}
+  TPSDColorMode = (
+    cmMono         = 0,
+    cmGrayscale    = 1,
+    cmIndexed      = 2,
+    cmRGB          = 3,
+    cmCMYK         = 4,
+    cmMultiChannel = 7,
+    cmDuoTone      = 8,
+    cmLab          = 9
+  );
+
+  { PSD image main header.}
+  TPSDHeader = packed record
+    Signature: TChar4;             // Format ID '8BPS'
+    Version: Word;                 // Always 1
+    Reserved: array[0..5] of Byte; // Reserved, all zero
+    Channels: Word;                // Number of color channels (1-24) including alpha channels
+    Rows : LongWord;               // Height of image in pixels (1-30000)
+    Columns: LongWord;             // Width of image in pixels (1-30000)
+    Depth: Word;                   // Number of bits per channel (1, 8, and 16)
+    Mode: TPSDColorMode;           // Color mode
+  end;
+
+  TPSDChannelInfo = packed record
+    ChannelID: Word;               // 0 = Red, 1 = Green, 2 = Blue etc., -1 = Transparency mask, -2 = User mask
+    Size: LongWord;                // Size of channel data.
+  end;
+
+procedure SwapHeader(var Header: TPSDHeader);
+begin
+  Header.Version := SwapEndianWord(Header.Version);
+  Header.Channels := SwapEndianWord(Header.Channels);
+  Header.Depth := SwapEndianWord(Header.Depth);
+  Header.Rows := SwapEndianLongWord(Header.Rows);
+  Header.Columns := SwapEndianLongWord(Header.Columns);
+  Header.Mode := TPSDColorMode(SwapEndianWord(Word(Header.Mode)));
+end;
+
+{
+  TPSDFileFormat class implementation
+}
+
+procedure TPSDFileFormat.Define;
+begin
+  inherited;
+  FName := SPSDFormatName;
+  FFeatures := [ffLoad, ffSave];
+  FSupportedFormats := PSDSupportedFormats;
+  AddMasks(SPSDMasks);
+
+  FSaveAsLayer := PSDDefaultSaveAsLayer;
+  RegisterOption(ImagingPSDSaveAsLayer, @FSaveAsLayer);
+end;
+
+function TPSDFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Header: TPSDHeader;
+  ByteCount: LongWord;
+  RawPal: array[0..767] of Byte;
+  Compression, PackedSize: Word;
+  LineSize, ChannelPixelSize, WidthBytes,
+    CurrChannel, MaxRLESize, I, Y, X: LongInt;
+  Info: TImageFormatInfo;
+  PackedLine, LineBuffer: PByte;
+  RLELineSizes: array of Word;
+  Col32: TColor32Rec;
+  Col64: TColor64Rec;
+  PCol32: PColor32Rec;
+  PCol64: PColor64Rec;
+
+  { PackBits RLE decode code from Mike Lischke's GraphicEx library.}
+  procedure DecodeRLE(Source, Dest: PByte; PackedSize, UnpackedSize: LongInt);
+  var
+    Count: LongInt;
+  begin
+    while (UnpackedSize > 0) and (PackedSize > 0) do
+    begin
+      Count := ShortInt(Source^);
+      Inc(Source);
+      Dec(PackedSize);
+      if Count < 0 then
+      begin
+        // Replicate next byte -Count + 1 times
+        if Count = -128 then
+          Continue;
+        Count := -Count + 1;
+        if Count > UnpackedSize then
+          Count := UnpackedSize;
+        FillChar(Dest^, Count, Source^);
+        Inc(Source);
+        Dec(PackedSize);
+        Inc(Dest, Count);
+        Dec(UnpackedSize, Count);
+      end
+      else
+      begin
+        // Copy next Count + 1 bytes from input
+        Inc(Count);
+        if Count > UnpackedSize then
+          Count := UnpackedSize;
+        if Count > PackedSize then
+          Count := PackedSize;
+        Move(Source^, Dest^, Count);
+        Inc(Dest, Count);
+        Inc(Source, Count);
+        Dec(PackedSize, Count);
+        Dec(UnpackedSize, Count);
+      end;
+    end;
+  end;
+
+begin
+  Result := False;
+  SetLength(Images, 1);
+  with GetIO, Images[0] do
+  begin
+    // Read PSD header
+    Read(Handle, @Header, SizeOf(Header));
+    SwapHeader(Header);
+
+    // Determine image data format
+    Format := ifUnknown;
+    case Header.Mode of
+      cmGrayscale, cmDuoTone:
+        begin
+          if Header.Depth in [8, 16] then
+          begin
+            if Header.Channels = 1 then
+              Format := IffFormat(Header.Depth = 8, ifGray8, ifGray16)
+            else if Header.Channels >= 2 then
+              Format := IffFormat(Header.Depth = 8, ifA8Gray8, ifA16Gray16);
+          end
+          else if (Header.Depth = 32) and (Header.Channels = 1) then
+            Format := ifR32F;
+        end;
+      cmIndexed:
+        begin
+          if Header.Depth = 8 then
+            Format := ifIndex8;
+        end;
+      cmRGB, cmMultiChannel, cmCMYK, cmLab:
+        begin
+          if Header.Depth in [8, 16] then
+          begin
+            if Header.Channels = 3 then
+              Format := IffFormat(Header.Depth = 8, ifR8G8B8, ifR16G16B16)
+            else if Header.Channels >= 4 then
+              Format := IffFormat(Header.Depth = 8, ifA8R8G8B8, ifA16R16G16B16);
+          end
+          else if Header.Depth = 32 then
+          begin
+            if Header.Channels = 3 then
+              Format := ifR32G32B32F
+            else if Header.Channels >= 4 then
+              Format := ifA32R32G32B32F;
+          end;
+        end;
+      cmMono:; // Not supported
+    end;
+
+    // Exit if no compatible format was found
+    if Format = ifUnknown then
+      Exit;
+
+    NewImage(Header.Columns, Header.Rows, Format, Images[0]);
+    Info := GetFormatInfo(Format);
+
+    // Read or skip Color Mode Data Block (palette)
+    Read(Handle, @ByteCount, SizeOf(ByteCount));
+    ByteCount := SwapEndianLongWord(ByteCount);
+    if Format = ifIndex8 then
+    begin
+      // Read palette only for indexed images
+      Read(Handle, @RawPal, SizeOf(RawPal));
+      for I := 0 to 255 do
+      begin
+        Palette[I].A := $FF;
+        Palette[I].R := RawPal[I + 0];
+        Palette[I].G := RawPal[I + 256];
+        Palette[I].B := RawPal[I + 512];
+      end;
+    end
+    else
+      Seek(Handle, ByteCount, smFromCurrent);
+
+    // Skip Image Resources Block
+    Read(Handle, @ByteCount, SizeOf(ByteCount));
+    ByteCount := SwapEndianLongWord(ByteCount);
+    Seek(Handle, ByteCount, smFromCurrent);
+    // Now there is Layer and Mask Information Block
+    Read(Handle, @ByteCount, SizeOf(ByteCount));
+    ByteCount := SwapEndianLongWord(ByteCount);
+    // Skip Layer and Mask Information Block
+    Seek(Handle, ByteCount, smFromCurrent);
+
+    // Read compression flag
+    Read(Handle, @Compression, SizeOf(Compression));
+    Compression := SwapEndianWord(Compression);
+
+    if Compression = CompressionRLE then
+    begin
+      // RLE compressed PSDs (most) have first lengths of compressed scanlines
+      // for each channel stored
+      SetLength(RLELineSizes, Height * Header.Channels);
+      Read(Handle, @RLELineSizes[0], Length(RLELineSizes) * SizeOf(Word));
+      SwapEndianWord(@RLELineSizes[0], Height * Header.Channels);
+      MaxRLESize := RLELineSizes[0];
+      for I := 1 to High(RLELineSizes) do
+      begin
+        if MaxRLESize < RLELineSizes[I] then
+          MaxRLESize := RLELineSizes[I];
+      end;
+    end
+    else
+      MaxRLESize := 0;
+
+    ChannelPixelSize := Info.BytesPerPixel div Info.ChannelCount;
+    LineSize := Width * ChannelPixelSize;
+    WidthBytes := Width * Info.BytesPerPixel;
+    GetMem(LineBuffer, LineSize);
+    GetMem(PackedLine, MaxRLESize);
+
+    try
+      // Image color chanels are stored separately in PSDs so we will load
+      // one by one and copy their data to appropriate addresses of dest image.
+      for I := 0 to Header.Channels - 1 do
+      begin
+        // Now determine to which color channel of destination image we are going
+        // to write pixels.
+        if I <= 4 then
+        begin
+          // If PSD has alpha channel we need to switch current channel order -
+          // PSDs have alpha stored after blue channel but Imaging has alpha
+          // before red.
+          if Info.HasAlphaChannel and (Header.Mode <> cmCMYK) then
+          begin
+            if I = Info.ChannelCount - 1 then
+              CurrChannel := I
+            else
+              CurrChannel := Info.ChannelCount - 2 - I;
+          end
+          else
+            CurrChannel := Info.ChannelCount - 1 - I;
+        end
+        else
+        begin
+          // No valid channel remains
+          CurrChannel := -1;
+        end;
+
+        if CurrChannel >= 0 then
+        begin
+          for Y := 0 to Height - 1 do
+          begin
+            if Compression = CompressionRLE then
+            begin
+              // Read RLE line and decompress it
+              PackedSize := RLELineSizes[I * Height + Y];
+              Read(Handle, PackedLine, PackedSize);
+              DecodeRLE(PackedLine, LineBuffer, PackedSize, LineSize);
+            end
+            else
+            begin
+              // Just read uncompressed line
+              Read(Handle, LineBuffer, LineSize);
+            end;
+
+            // Swap endian if needed
+            if ChannelPixelSize = 4 then
+              SwapEndianLongWord(PLongWord(LineBuffer), Width)
+            else if ChannelPixelSize = 2 then
+              SwapEndianWord(PWordArray(LineBuffer), Width);
+
+            if Info.ChannelCount > 1 then
+            begin
+              // Copy each pixel fragment to its right place in destination image
+              for X := 0 to Width - 1 do
+              begin
+                Move(PByteArray(LineBuffer)[X * ChannelPixelSize],
+                  PByteArray(Bits)[Y * WidthBytes + X * Info.BytesPerPixel + CurrChannel * ChannelPixelSize],
+                  ChannelPixelSize);
+              end;
+            end
+            else
+            begin
+              // Just copy the line
+              Move(LineBuffer^, PByteArray(Bits)[Y * LineSize], LineSize);
+            end;
+          end;
+        end
+        else
+        begin
+          // Skip current color channel, not needed for image loading - just to
+          // get stream's position to the end of PSD
+          if Compression = CompressionRLE then
+          begin
+            for Y := 0 to Height - 1 do
+              Seek(Handle, RLELineSizes[I * Height + Y], smFromCurrent);
+          end
+          else
+            Seek(Handle, LineSize * Height, smFromCurrent);
+        end;
+      end;
+
+      if Header.Mode = cmCMYK then
+      begin
+        // Convert CMYK images to RGB (alpha is ignored here). PSD stores CMYK
+        // channels in the way that first requires substraction from max channel value
+        if ChannelPixelSize = 1 then
+        begin
+          PCol32 := Bits;
+          for X := 0 to Width * Height - 1 do
+          begin
+            Col32.A := 255 - PCol32.A;
+            Col32.R := 255 - PCol32.R;
+            Col32.G := 255 - PCol32.G;
+            Col32.B := 255 - PCol32.B;
+            CMYKToRGB(Col32.A, Col32.R, Col32.G, Col32.B, PCol32.R, PCol32.G, PCol32.B);
+            PCol32.A := 255;
+            Inc(PCol32);
+          end;
+        end
+        else
+        begin
+          PCol64 := Bits;
+          for X := 0 to Width * Height - 1 do
+          begin
+            Col64.A := 65535 - PCol64.A;
+            Col64.R := 65535 - PCol64.R;
+            Col64.G := 65535 - PCol64.G;
+            Col64.B := 65535 - PCol64.B;
+            CMYKToRGB16(Col64.A, Col64.R, Col64.G, Col64.B, PCol64.R, PCol64.G, PCol64.B);
+            PCol64.A := 65535;
+            Inc(PCol64);
+          end;
+        end;
+      end;
+
+      Result := True;
+    finally
+      FreeMem(LineBuffer);
+      FreeMem(PackedLine);
+    end;
+  end;
+end;
+
+function TPSDFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+type
+  TURect = packed record
+    Top, Left, Bottom, Right: LongWord;
+  end;
+const
+  BlendMode: TChar8 = '8BIMnorm';
+  LayerOptions: array[0..3] of Byte = (255, 0, 0, 0);
+  LayerName: array[0..7] of AnsiChar = #7'Layer 0';
+var
+  MustBeFreed: Boolean;
+  ImageToSave: TImageData;
+  Info: TImageFormatInfo;
+  Header: TPSDHeader;
+  I, CurrChannel, ChannelPixelSize: LongInt;
+  LayerBlockOffset, SaveOffset, ChannelInfoOffset: Integer;
+  ChannelInfo: TPSDChannelInfo;
+  R: TURect;
+  LongVal: LongWord;
+  WordVal, LayerCount: Word;
+  RawPal: array[0..767] of Byte;
+  ChannelDataSizes: array of Integer;
+
+  function PackLine(Src, Dest: PByteArray; Length: Integer): Integer;
+  var
+    I, Remaining: Integer;
+  begin
+    Remaining := Length;
+    Result := 0;
+    while Remaining > 0 do
+    begin
+      I := 0;
+      // Look for characters same as the first
+      while (I < 128) and (Remaining - I > 0) and (Src[0] = Src[I]) do
+        Inc(I);
+
+      if I > 2 then
+      begin
+        Dest[0] := Byte(-(I - 1));
+        Dest[1] := Src[0];
+        Dest := PByteArray(@Dest[2]);
+
+        Src := PByteArray(@Src[I]);
+        Dec(Remaining, I);
+        Inc(Result, 2);
+      end
+      else
+      begin
+        // Look for different characters
+        I := 0;
+        while (I < 128) and (Remaining - (I + 1) > 0) and
+          ((Src[I] <> Src[I + 1]) or (Remaining - (I + 2) <= 0) or
+          (Src[I] <> Src[I + 2])) do
+        begin
+          Inc(I);
+        end;
+        // If there's only 1 remaining, the previous WHILE doesn't catch it
+        if Remaining = 1 then
+          I := 1;
+
+        if I > 0 then
+        begin
+          // Some distinct ones found
+          Dest[0] := I - 1;
+          Move(Src[0], Dest[1], I);
+          Dest := PByteArray(@Dest[1 + I]);
+          Src := PByteArray(@Src[I]);
+          Dec(Remaining, I);
+          Inc(Result, I + 1);
+        end;
+      end;
+    end;
+  end;
+
+  procedure WriteChannelData(SeparateChannelStorage: Boolean);
+  var
+    I, X, Y, LineSize, WidthBytes, RLETableOffset, CurrentOffset, WrittenLineSize: Integer;
+    LineBuffer, RLEBuffer: PByteArray;
+    RLELengths: array of Word;
+    Compression: Word;
+  begin
+    LineSize := ImageToSave.Width * ChannelPixelSize;
+    WidthBytes := ImageToSave.Width * Info.BytesPerPixel;
+    GetMem(LineBuffer, LineSize);
+    GetMem(RLEBuffer, LineSize * 3);
+    SetLength(RLELengths, ImageToSave.Height * Info.ChannelCount);
+    RLETableOffset := 0;
+    // No compression for FP32, Photoshop won't open them
+    Compression := Iff(Info.IsFloatingPoint, CompressionNone, CompressionRLE);
+
+    if not SeparateChannelStorage then
+    begin
+      // This is for storing background merged image. There's only one
+      // compression flag and one RLE lenghts table for all channels
+      WordVal := Swap(Compression);
+      GetIO.Write(Handle, @WordVal, SizeOf(WordVal));
+      if Compression = CompressionRLE then
+      begin
+        RLETableOffset := GetIO.Tell(Handle);
+        GetIO.Write(Handle, @RLELengths[0], SizeOf(Word) * ImageToSave.Height * Info.ChannelCount);
+      end;
+    end;
+
+    for I := 0 to Info.ChannelCount - 1 do
+    begin
+      if SeparateChannelStorage then
+      begin
+        // Layer image data has compression flag and RLE lenghts table
+        // independent for each channel
+        WordVal := Swap(CompressionRLE);
+        GetIO.Write(Handle, @WordVal, SizeOf(WordVal));
+        if Compression = CompressionRLE then
+        begin
+          RLETableOffset := GetIO.Tell(Handle);
+          GetIO.Write(Handle, @RLELengths[0], SizeOf(Word) * ImageToSave.Height);
+          ChannelDataSizes[I] := 0;
+        end;
+      end;
+
+      // Now determine which color channel we are going to write to file.
+      if Info.HasAlphaChannel then
+      begin
+        if I = Info.ChannelCount - 1 then
+          CurrChannel := I
+        else
+          CurrChannel := Info.ChannelCount - 2 - I;
+      end
+      else
+        CurrChannel := Info.ChannelCount - 1 - I;
+
+      for Y := 0 to ImageToSave.Height - 1 do
+      begin
+        if Info.ChannelCount > 1 then
+        begin
+          // Copy each pixel fragment to its right place in destination image
+          for X := 0 to ImageToSave.Width - 1 do
+          begin
+            Move(PByteArray(ImageToSave.Bits)[Y * WidthBytes + X * Info.BytesPerPixel + CurrChannel * ChannelPixelSize],
+              PByteArray(LineBuffer)[X * ChannelPixelSize], ChannelPixelSize);
+          end;
+        end
+        else
+          Move(PByteArray(ImageToSave.Bits)[Y * LineSize], LineBuffer^, LineSize);
+
+        // Write current channel line to file (swap endian if needed first)
+        if ChannelPixelSize = 4 then
+          SwapEndianLongWord(PLongWord(LineBuffer), ImageToSave.Width)
+        else if ChannelPixelSize = 2 then
+          SwapEndianWord(PWordArray(LineBuffer), ImageToSave.Width);
+
+        if Compression = CompressionRLE then
+        begin
+          // Compress and write line
+          WrittenLineSize := PackLine(LineBuffer, RLEBuffer, LineSize);
+          RLELengths[ImageToSave.Height * I + Y] := SwapEndianWord(WrittenLineSize);
+          GetIO.Write(Handle, RLEBuffer, WrittenLineSize);
+        end
+        else
+        begin
+          WrittenLineSize := LineSize;
+          GetIO.Write(Handle, LineBuffer, WrittenLineSize);
+        end;
+
+        if SeparateChannelStorage then
+          Inc(ChannelDataSizes[I], WrittenLineSize);
+      end;
+
+      if SeparateChannelStorage and (Compression = CompressionRLE) then
+      begin
+        // Update channel RLE lengths
+        CurrentOffset := GetIO.Tell(Handle);
+        GetIO.Seek(Handle, RLETableOffset, smFromBeginning);
+        GetIO.Write(Handle, @RLELengths[ImageToSave.Height * I], SizeOf(Word) * ImageToSave.Height);
+        GetIO.Seek(Handle, CurrentOffset, smFromBeginning);
+        Inc(ChannelDataSizes[I], SizeOf(Word) * ImageToSave.Height);
+      end;
+    end;
+
+    if not SeparateChannelStorage and (Compression = CompressionRLE) then
+    begin
+      // Update channel RLE lengths
+      CurrentOffset := GetIO.Tell(Handle);
+      GetIO.Seek(Handle, RLETableOffset, smFromBeginning);
+      GetIO.Write(Handle, @RLELengths[0], SizeOf(Word) * ImageToSave.Height * Info.ChannelCount);
+      GetIO.Seek(Handle, CurrentOffset, smFromBeginning);
+    end;
+
+    FreeMem(LineBuffer);
+    FreeMem(RLEBuffer);
+  end;
+
+begin
+  Result := False;
+  if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
+  with GetIO, ImageToSave do
+  try
+    Info := GetFormatInfo(Format);
+    ChannelPixelSize := Info.BytesPerPixel div Info.ChannelCount;
+
+    // Fill header with proper info and save it
+    FillChar(Header, SizeOf(Header), 0);
+    Header.Signature := SPSDMagic;
+    Header.Version := 1;
+    Header.Channels := Info.ChannelCount;
+    Header.Rows := Height;
+    Header.Columns := Width;
+    Header.Depth := Info.BytesPerPixel div Info.ChannelCount * 8;
+    if Info.IsIndexed then
+      Header.Mode := cmIndexed
+    else if Info.HasGrayChannel or (Info.ChannelCount = 1) then
+      Header.Mode := cmGrayscale
+    else
+      Header.Mode := cmRGB;
+
+    SwapHeader(Header);
+    Write(Handle, @Header, SizeOf(Header));
+
+    // Write palette size and data
+    LongVal := SwapEndianLongWord(IffUnsigned(Info.IsIndexed, SizeOf(RawPal), 0));
+    Write(Handle, @LongVal, SizeOf(LongVal));
+    if Info.IsIndexed then
+    begin
+      for I := 0 to Info.PaletteEntries - 1 do
+      begin
+        RawPal[I] := Palette[I].R;
+        RawPal[I + 256] := Palette[I].G;
+        RawPal[I + 512] := Palette[I].B;
+      end;
+      Write(Handle, @RawPal, SizeOf(RawPal));
+    end;
+
+    // Write empty resource and layer block sizes
+    LongVal := 0;
+    Write(Handle, @LongVal, SizeOf(LongVal));
+    LayerBlockOffset := Tell(Handle);
+    Write(Handle, @LongVal, SizeOf(LongVal));
+
+    if FSaveAsLayer and (ChannelPixelSize < 4) then  // No Layers for FP32 images
+    begin
+      LayerCount := SwapEndianWord(Iff(Info.HasAlphaChannel, Word(-1), 1)); // Must be -1 to get transparency in Photoshop
+      R.Top := 0;
+      R.Left := 0;
+      R.Bottom := SwapEndianLongWord(Height);
+      R.Right := SwapEndianLongWord(Width);
+      WordVal := SwapEndianWord(Info.ChannelCount);
+      Write(Handle, @LongVal, SizeOf(LongVal));        // Layer section size, empty now
+      Write(Handle, @LayerCount, SizeOf(LayerCount));  // Layer count
+      Write(Handle, @R, SizeOf(R));                    // Bounds rect
+      Write(Handle, @WordVal, SizeOf(WordVal));        // Channel count
+
+      ChannelInfoOffset := Tell(Handle);
+      SetLength(ChannelDataSizes, Info.ChannelCount);  // Empty channel infos
+      FillChar(ChannelInfo, SizeOf(ChannelInfo), 0);
+      for I := 0 to Info.ChannelCount - 1 do
+        Write(Handle, @ChannelInfo, SizeOf(ChannelInfo));
+
+      Write(Handle, @BlendMode, SizeOf(BlendMode));    // Blend mode = normal
+      Write(Handle, @LayerOptions, SizeOf(LayerOptions)); // Predefined options
+      LongVal := SwapEndianLongWord(16);               // Extra data size (4 (mask size) + 4 (ranges size) + 8 (name))
+      Write(Handle, @LongVal, SizeOf(LongVal));
+      LongVal := 0;
+      Write(Handle, @LongVal, SizeOf(LongVal));        // Mask size = 0
+      LongVal := 0;
+      Write(Handle, @LongVal, SizeOf(LongVal));        // Blend ranges size
+      Write(Handle, @LayerName, SizeOf(LayerName));    // Layer name
+
+      WriteChannelData(True);                          // Write Layer image data
+
+      Write(Handle, @LongVal, SizeOf(LongVal));        // Global mask info size = 0
+
+      SaveOffset := Tell(Handle);
+      Seek(Handle, LayerBlockOffset, smFromBeginning);
+
+      // Update layer and mask section sizes
+      LongVal := SwapEndianLongWord(SaveOffset - LayerBlockOffset - 4);
+      Write(Handle, @LongVal, SizeOf(LongVal));
+      LongVal := SwapEndianLongWord(SaveOffset - LayerBlockOffset - 8);
+      Write(Handle, @LongVal, SizeOf(LongVal));
+
+      // Update layer channel info
+      Seek(Handle, ChannelInfoOffset, smFromBeginning);
+      for I := 0 to Info.ChannelCount - 1 do
+      begin
+        ChannelInfo.ChannelID := SwapEndianWord(I);
+        if (I = Info.ChannelCount - 1) and Info.HasAlphaChannel then
+          ChannelInfo.ChannelID := Swap(Word(-1));
+        ChannelInfo.Size := SwapEndianLongWord(ChannelDataSizes[I] + 2); // datasize (incl RLE table) + comp. flag
+        Write(Handle, @ChannelInfo, SizeOf(ChannelInfo));
+      end;
+
+      Seek(Handle, SaveOffset, smFromBeginning);
+    end;
+
+    // Write background merged image
+    WriteChannelData(False);
+
+    Result := True;
+  finally
+    if MustBeFreed then
+      FreeImage(ImageToSave);
+  end;
+end;
+
+procedure TPSDFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if Info.IsFloatingPoint then
+  begin
+    if Info.ChannelCount = 1 then
+      ConvFormat := ifR32F
+    else if Info.HasAlphaChannel then
+      ConvFormat := ifA32R32G32B32F
+    else
+      ConvFormat := ifR32G32B32F;
+  end
+  else if Info.HasGrayChannel then
+    ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray16)
+  else if Info.RBSwapFormat in GetSupportedFormats then
+    ConvFormat := Info.RBSwapFormat
+  else
+    ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8);
+
+  ConvertImage(Image, ConvFormat);
+end;
+
+function TPSDFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Header: TPSDHeader;
+  ReadCount: LongInt;
+begin
+  Result := False;
+  if Handle <> nil then
+  begin
+    ReadCount := GetIO.Read(Handle, @Header, SizeOf(Header));
+    SwapHeader(Header);
+    GetIO.Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (ReadCount >= SizeOf(Header)) and
+      (Header.Signature = SPSDMagic) and
+      (Header.Version = 1);
+  end;
+end;
+
+initialization
+  RegisterImageFileFormat(TPSDFileFormat);
+
+{
+  File Notes:
+
+  -- 0.77.1 ---------------------------------------------------
+    - 3 channel RGB float images are loaded and saved directly
+      as ifR32G32B32F.
+
+  -- 0.26.1 Changes/Bug Fixes ---------------------------------
+    - PSDs are now saved with RLE compression.
+    - Mask layer saving added to SaveData for images with alpha
+      (shows proper transparency when opened in Photoshop). Can be
+      enabled/disabled using option
+    - Fixed memory leak in SaveData.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Saving implemented.
+    - Loading implemented.
+    - Unit created with initial stuff!
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingRadiance.pas b/src/lib/vampimg/ImagingRadiance.pas
new file mode 100644 (file)
index 0000000..122e0c2
--- /dev/null
@@ -0,0 +1,497 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader/saver for Radiance HDR/RGBE images.}
+unit ImagingRadiance;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, Classes, Imaging, ImagingTypes, ImagingUtility;
+
+type
+  { Radiance is a suite of tools for performing lighting simulation. It's
+    development started in 1985 and it pioneered the concept of
+    high dynamic range imaging. Radiance defined an image format for storing
+    HDR images, now described as RGBE image format. Since it was the first
+    HDR image format, this format is supported by many other software packages.
+
+    Radiance image file consists of three sections: a header, resolution string,
+    followed by the pixel data. Each pixel is stored as 4 bytes, one byte
+    mantissa for each r, g, b and a shared one byte exponent.
+    The pixel data may be stored uncompressed or using run length encoding.
+
+    Imaging translates RGBE pixels to original float values and stores them
+    in ifR32G32B32F data format. It can read both compressed and uncompressed
+    files, and saves files as compressed.}
+  THdrFileFormat = class(TImageFileFormat)
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  end;
+
+implementation
+
+uses
+  Math, ImagingIO;
+
+const
+  SHdrFormatName = 'Radiance HDR/RGBE';
+  SHdrMasks      = '*.hdr';
+  HdrSupportedFormats: TImageFormats = [ifR32G32B32F];
+
+type
+  TSignature = array[0..9] of AnsiChar;
+  THdrFormat = (hfRgb, hfXyz);
+
+  THdrHeader = record
+    Format: THdrFormat;
+    Width: Integer;
+    Height: Integer;
+  end;
+
+  TRgbe = packed record
+    R, G, B, E: Byte;
+  end;
+  PRgbe = ^TRgbe;
+  TDynRgbeArray = array of TRgbe;
+
+const
+  RadianceSignature: TSignature = '#?RADIANCE';
+  RgbeSignature: TSignature = '#?RGBE';
+  MaxLineLength = 256;
+  SFmtRgbeRle = '32-bit_rle_rgbe';
+  SFmtXyzeRle = '32-bit_rle_xyze';
+
+resourcestring
+  SErrorBadHeader = 'Bad HDR/RGBE header format.';
+  SWrongScanLineWidth = 'Wrong scanline width.';
+  SXyzNotSupported = 'XYZ color space not supported.';
+
+{ THdrFileFormat }
+
+procedure THdrFileFormat.Define;
+begin
+  inherited;
+  FName := SHdrFormatName;
+  FFeatures := [ffLoad, ffSave];
+  FSupportedFormats := HdrSupportedFormats;
+
+  AddMasks(SHdrMasks);
+end;
+
+function THdrFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Header: THdrHeader;
+  IO: TIOFunctions;
+
+  function ReadHeader: Boolean;
+  const
+    CommentIds: TAnsiCharSet = ['#', '!'];
+  var
+    Line: AnsiString;
+    HasResolution: Boolean;
+    Count, Idx: Integer;
+    ValStr, NativeLine: string;
+    ValFloat: Double;
+  begin
+    Result := False;
+    HasResolution := False;
+    Count := 0;
+
+    repeat
+      if not ReadLine(IO, Handle, Line) then
+        Exit;
+
+      Inc(Count);
+      if Count > 16 then // Too long header for HDR
+        Exit;
+
+      if Length(Line) = 0 then
+        Continue;
+      if Line[1] in CommentIds then
+        Continue;
+
+      NativeLine := string(Line);
+
+      if StrMaskMatch(NativeLine, 'Format=*') then
+      begin
+        // Data format parsing
+        ValStr := Copy(NativeLine, 8, MaxInt);
+        if ValStr = SFmtRgbeRle then
+          Header.Format := hfRgb
+        else if ValStr = SFmtXyzeRle then
+          Header.Format := hfXyz
+        else
+          Exit;
+      end;
+
+      if StrMaskMatch(NativeLine, 'Gamma=*') then
+      begin
+        ValStr := Copy(NativeLine, 7, MaxInt);
+        if TryStrToFloat(ValStr, ValFloat, GetFormatSettingsForFloats) then
+          FMetadata.SetMetaItem(SMetaGamma, ValFloat);
+      end;
+
+      if StrMaskMatch(NativeLine, 'Exposure=*') then
+      begin
+        ValStr := Copy(NativeLine, 10, MaxInt);
+        if TryStrToFloat(ValStr, ValFloat, GetFormatSettingsForFloats) then
+          FMetadata.SetMetaItem(SMetaExposure, ValFloat);
+      end;
+
+      if StrMaskMatch(NativeLine, '?Y * ?X *') then
+      begin
+        Idx := Pos('X', NativeLine);
+        ValStr := SubString(NativeLine, 4, Idx - 2);
+        if not TryStrToInt(ValStr, Header.Height) then
+          Exit;
+        ValStr := Copy(NativeLine, Idx + 2, MaxInt);
+        if not TryStrToInt(ValStr, Header.Width) then
+          Exit;
+
+        if (NativeLine[1] = '-') then
+          Header.Height := -Header.Height;
+        if (NativeLine[Idx - 1] = '-') then
+          Header.Width := -Header.Width;
+
+        HasResolution := True;
+      end;
+
+    until HasResolution;
+    Result := True;
+  end;
+
+  procedure DecodeRgbe(const Src: TRgbe; Dest: PColor96FPRec); {$IFDEF USE_INLINE}inline;{$ENDIF}
+  var
+    Mult: Single;
+  begin
+    if Src.E > 0 then
+    begin
+      Mult := Math.Ldexp(1, Src.E - 128);
+      Dest.R := Src.R / 255 * Mult;
+      Dest.G := Src.G / 255 * Mult;
+      Dest.B := Src.B / 255 * Mult;
+    end
+    else
+    begin
+      Dest.R := 0;
+      Dest.G := 0;
+      Dest.B := 0;
+    end;
+  end;
+
+  procedure ReadCompressedLine(Width, Y: Integer; var DestBuffer: TDynRgbeArray);
+  var
+    Pos: Integer;
+    I, X, Count: Integer;
+    Code, Value: Byte;
+    LineBuff: TDynByteArray;
+    Rgbe: TRgbe;
+    Ptr: PByte;
+  begin
+    SetLength(LineBuff, Width);
+    IO.Read(Handle, @Rgbe, SizeOf(Rgbe));
+
+    if ((Rgbe.B shl 8) or Rgbe.E) <> Width  then
+      RaiseImaging(SWrongScanLineWidth);
+
+    for I := 0 to 3 do
+    begin
+      Pos := 0;
+      while Pos < Width do
+      begin
+        IO.Read(Handle, @Code, SizeOf(Byte));
+        if Code > 128 then
+        begin
+          Count := Code - 128;
+          IO.Read(Handle, @Value, SizeOf(Byte));
+          FillMemoryByte(@LineBuff[Pos], Count, Value);
+        end
+        else
+        begin
+          Count := Code;
+          IO.Read(Handle, @LineBuff[Pos], Count * SizeOf(Byte));
+        end;
+        Inc(Pos, Count);
+      end;
+
+      Ptr := @PByteArray(@DestBuffer[0])[I];
+      for X := 0 to Width - 1 do
+      begin
+        Ptr^ := LineBuff[X];
+        Inc(Ptr, 4);
+      end;
+    end;
+  end;
+
+  procedure ReadPixels(var Image: TImageData);
+  var
+    Y, X, SrcLineLen: Integer;
+    Dest: PColor96FPRec;
+    Compressed: Boolean;
+    Rgbe: TRgbe;
+    Buffer: TDynRgbeArray;
+  begin
+    Dest := Image.Bits;
+    Compressed := not ((Image.Width < 8) or (Image.Width > $7FFFF));
+    SrcLineLen := Image.Width * SizeOf(TRgbe);
+
+    IO.Read(Handle, @Rgbe, SizeOf(Rgbe));
+    IO.Seek(Handle, -SizeOf(Rgbe), smFromCurrent);
+
+    if (Rgbe.R <> 2) or (Rgbe.G <> 2) or ((Rgbe.B and 128) > 0) then
+      Compressed := False;
+
+    SetLength(Buffer, Image.Width);
+
+    for Y := 0 to Image.Height - 1 do
+    begin
+      if Compressed then
+        ReadCompressedLine(Image.Width, Y, Buffer)
+      else
+        IO.Read(Handle, @Buffer[0], SrcLineLen);
+
+      for X := 0 to Image.Width - 1 do
+      begin
+        DecodeRgbe(Buffer[X], Dest);
+        Inc(Dest);
+      end;
+    end;
+  end;
+
+begin
+  IO := GetIO;
+  SetLength(Images, 1);
+
+  // Read header, allocate new image and, then read and convert the pixels
+  if not ReadHeader then
+    RaiseImaging(SErrorBadHeader);
+  if (Header.Format = hfXyz) then
+    RaiseImaging(SXyzNotSupported);
+
+  NewImage(Abs(Header.Width), Abs(Header.Height), ifR32G32B32F, Images[0]);
+  ReadPixels(Images[0]);
+
+  // Flip/mirror the image as needed (height < 0 is default top-down)
+  if Header.Width < 0 then
+    MirrorImage(Images[0]);
+  if Header.Height > 0 then
+    FlipImage(Images[0]);
+
+  Result := True;
+end;
+
+function THdrFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: Integer): Boolean;
+const
+  LineEnd = #$0A;
+  SPrgComment = '#Made with Vampyre Imaging Library';
+  SSizeFmt = '-Y %d +X %d';
+var
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+  IO: TIOFunctions;
+
+  procedure SaveHeader;
+  begin
+    WriteLine(IO, Handle, RadianceSignature, LineEnd);
+    WriteLine(IO, Handle, SPrgComment, LineEnd);
+    WriteLine(IO, Handle, 'FORMAT=' + SFmtRgbeRle, LineEnd + LineEnd);
+    WriteLine(IO, Handle, AnsiString(Format(SSizeFmt, [ImageToSave.Height, ImageToSave.Width])), LineEnd);
+  end;
+
+  procedure EncodeRgbe(const Src: TColor96FPRec; var DestR, DestG, DestB, DestE: Byte); {$IFDEF USE_INLINE}inline;{$ENDIF}
+  var
+    V, M: {$IFDEF FPC}Float{$ELSE}Extended{$ENDIF};
+    E: Integer;
+  begin
+    V := Src.R;
+    if (Src.G > V) then
+      V := Src.G;
+    if (Src.B > V) then
+      V := Src.B;
+
+    if V < 1e-32 then
+    begin
+      DestR := 0;
+      DestG := 0;
+      DestB := 0;
+      DestE := 0;
+    end
+    else
+    begin
+      Frexp(V, M, E);
+      V := M * 256.0 / V;
+      DestR := ClampToByte(Round(Src.R * V));
+      DestG := ClampToByte(Round(Src.G * V));
+      DestB := ClampToByte(Round(Src.B * V));
+      DestE := ClampToByte(E + 128);
+    end;
+  end;
+
+  procedure WriteRleLine(const Line: array of Byte; Width: Integer);
+  const
+    MinRunLength = 4;
+  var
+    Cur, BeginRun, RunCount, OldRunCount, NonRunCount: Integer;
+    Buf: array[0..1] of Byte;
+  begin
+    Cur := 0;
+    while Cur < Width do
+    begin
+      BeginRun := Cur;
+      RunCount := 0;
+      OldRunCount := 0;
+      while (RunCount < MinRunLength) and (BeginRun < Width) do
+      begin
+        Inc(BeginRun, RunCount);
+        OldRunCount := RunCount;
+        RunCount := 1;
+        while (BeginRun + RunCount < Width) and (RunCount < 127) and (Line[BeginRun] = Line[BeginRun + RunCount]) do
+          Inc(RunCount);
+      end;
+      if (OldRunCount > 1) and (OldRunCount = BeginRun - Cur) then
+      begin
+        Buf[0] := 128 + OldRunCount;
+        Buf[1] := Line[Cur];
+        IO.Write(Handle, @Buf, 2);
+        Cur := BeginRun;
+      end;
+      while Cur < BeginRun do
+      begin
+        NonRunCount := Min(128, BeginRun - Cur);
+        Buf[0] := NonRunCount;
+        IO.Write(Handle, @Buf, 1);
+        IO.Write(Handle, @Line[Cur], NonRunCount);
+        Inc(Cur, NonRunCount);
+      end;
+      if RunCount >= MinRunLength then
+      begin
+        Buf[0] := 128 + RunCount;
+        Buf[1] := Line[BeginRun];
+        IO.Write(Handle, @Buf, 2);
+        Inc(Cur, RunCount);
+      end;
+    end;
+  end;
+
+  procedure SavePixels;
+  var
+    Y, X, I, Width: Integer;
+    SrcPtr: PColor96FPRecArray;
+    Components: array of array of Byte;
+    StartLine: array[0..3] of Byte;
+  begin
+    Width := ImageToSave.Width;
+    // Save using RLE, each component is compressed separately
+    SetLength(Components, 4, Width);
+
+    for Y := 0 to ImageToSave.Height - 1 do
+    begin
+      SrcPtr := @PColor96FPRecArray(ImageToSave.Bits)[ImageToSave.Width * Y];
+
+      // Identify line as using "new" RLE scheme (separate components)
+      StartLine[0] := 2;
+      StartLine[1] := 2;
+      StartLine[2] := Width shr 8;
+      StartLine[3] := Width and $FF;
+      IO.Write(Handle, @StartLine, SizeOf(StartLine));
+
+      for X := 0 to Width - 1 do
+      begin
+        EncodeRgbe(SrcPtr[X], Components[0, X], Components[1, X],
+          Components[2, X], Components[3, X]);
+      end;
+
+      for I := 0 to 3 do
+        WriteRleLine(Components[I], Width);
+    end;
+  end;
+
+begin
+  Result := False;
+  IO := GetIO;
+  // Makes image to save compatible with Jpeg saving capabilities
+  if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
+  with ImageToSave do
+  try
+    // Save header
+    SaveHeader;
+    // Save uncompressed pixels
+    SavePixels;
+  finally
+    if MustBeFreed then
+      FreeImage(ImageToSave);
+  end;
+end;
+
+procedure THdrFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+begin
+  ConvertImage(Image, ifR32G32B32F);
+end;
+
+function THdrFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  FileSig: TSignature;
+  ReadCount: Integer;
+begin
+  Result := False;
+  if Handle <> nil then
+  begin
+    ReadCount := GetIO.Read(Handle, @FileSig, SizeOf(FileSig));
+    GetIO.Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (ReadCount = SizeOf(FileSig)) and
+      ((FileSig = RadianceSignature) or CompareMem(@FileSig, @RgbeSignature, 6));
+  end;
+end;
+
+initialization
+  RegisterImageFileFormat(THdrFileFormat);
+
+{
+  File Notes:
+
+  -- 0.77.1 ---------------------------------------------------
+    - Added RLE compression to saving.
+    - Added image saving.
+    - Unit created with initial stuff (loading only).
+
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingTarga.pas b/src/lib/vampimg/ImagingTarga.pas
new file mode 100644 (file)
index 0000000..66af5f2
--- /dev/null
@@ -0,0 +1,619 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader/saver for Targa images.}
+unit ImagingTarga;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  ImagingTypes, Imaging, ImagingFormats, ImagingUtility;
+
+type
+  { Class for loading and saving Truevision Targa images.
+    It can load/save 8bit indexed or grayscale, 16 bit RGB or grayscale,
+    24 bit RGB and 32 bit ARGB images with or without RLE compression.}
+  TTargaFileFormat = class(TImageFileFormat)
+  protected
+    FUseRLE: LongBool;
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  published
+    { Controls that RLE compression is used during saving. Accessible trough
+      ImagingTargaRLE option.}
+    property UseRLE: LongBool read FUseRLE write FUseRLE;
+  end;
+
+implementation
+
+const
+  STargaFormatName = 'Truevision Targa Image';
+  STargaMasks      = '*.tga';
+  TargaSupportedFormats: TImageFormats = [ifIndex8, ifGray8, ifA1R5G5B5,
+    ifR8G8B8, ifA8R8G8B8];
+  TargaDefaultRLE = False;
+
+const
+  STargaSignature = 'TRUEVISION-XFILE';
+
+type
+  { Targa file header.}
+  TTargaHeader = packed record
+    IDLength: Byte;
+    ColorMapType: Byte;
+    ImageType: Byte;
+    ColorMapOff: Word;
+    ColorMapLength: Word;
+    ColorEntrySize: Byte;
+    XOrg: SmallInt;
+    YOrg: SmallInt;
+    Width: SmallInt;
+    Height: SmallInt;
+    PixelSize: Byte;
+    Desc: Byte;
+  end;
+
+  { Footer at the end of TGA file.}
+  TTargaFooter = packed record
+    ExtOff: LongWord;             // Extension Area Offset
+    DevDirOff: LongWord;          // Developer Directory Offset
+    Signature: TChar16;           // TRUEVISION-XFILE
+    Reserved: Byte;               // ASCII period '.'
+    NullChar: Byte;               // 0
+  end;
+
+
+{ TTargaFileFormat class implementation }
+
+procedure TTargaFileFormat.Define;
+begin
+  inherited;
+  FName := STargaFormatName;
+  FFeatures := [ffLoad, ffSave];
+  FSupportedFormats := TargaSupportedFormats;
+
+  FUseRLE := TargaDefaultRLE;
+
+  AddMasks(STargaMasks);
+  RegisterOption(ImagingTargaRLE, @FUseRLE);
+end;
+
+function TTargaFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Hdr: TTargaHeader;
+  Foo: TTargaFooter;
+  FooterFound, ExtFound: Boolean;
+  I, PSize, PalSize: LongWord;
+  Pal: Pointer;
+  FmtInfo: TImageFormatInfo;
+  WordValue: Word;
+
+  procedure LoadRLE;
+  var
+    I, CPixel, Cnt: LongInt;
+    Bpp, Rle: Byte;
+    Buffer, Dest, Src: PByte;
+    BufSize: LongInt;
+  begin
+    with GetIO, Images[0] do
+    begin
+      // Alocates buffer large enough to hold the worst case
+      // RLE compressed data and reads then from input
+      BufSize := Width * Height * FmtInfo.BytesPerPixel;
+      BufSize := BufSize + BufSize div 2 + 1;
+      GetMem(Buffer, BufSize);
+      Src := Buffer;
+      Dest := Bits;
+      BufSize := Read(Handle, Buffer, BufSize);
+
+      Cnt := Width * Height;
+      Bpp := FmtInfo.BytesPerPixel;
+      CPixel := 0;
+      while CPixel < Cnt do
+      begin
+        Rle := Src^;
+        Inc(Src);
+        if Rle < 128 then
+        begin
+          // Process uncompressed pixel
+          Rle := Rle + 1;
+          CPixel := CPixel + Rle;
+          for I := 0 to Rle - 1 do
+          begin
+            // Copy pixel from src to dest
+            case Bpp of
+              1: Dest^ := Src^;
+              2: PWord(Dest)^ := PWord(Src)^;
+              3: PColor24Rec(Dest)^ := PColor24Rec(Src)^;
+              4: PLongWord(Dest)^ := PLongWord(Src)^;
+            end;
+            Inc(Src, Bpp);
+            Inc(Dest, Bpp);
+          end;
+        end
+        else
+        begin
+          // Process compressed pixels
+          Rle := Rle - 127;
+          CPixel := CPixel + Rle;
+          // Copy one pixel from src to dest (many times there)
+          for I := 0 to Rle - 1 do
+          begin
+            case Bpp of
+              1: Dest^ := Src^;
+              2: PWord(Dest)^ := PWord(Src)^;
+              3: PColor24Rec(Dest)^ := PColor24Rec(Src)^;
+              4: PLongWord(Dest)^ := PLongWord(Src)^;
+            end;
+            Inc(Dest, Bpp);
+          end;
+          Inc(Src, Bpp);
+        end;
+      end;
+      // set position in source to real end of compressed data
+      Seek(Handle, -(BufSize - LongInt(LongWord(Src) - LongWord(Buffer))),
+        smFromCurrent);
+      FreeMem(Buffer);
+    end;
+  end;
+
+begin
+  SetLength(Images, 1);
+  with GetIO, Images[0] do
+  begin
+    // Read targa header
+    Read(Handle, @Hdr, SizeOf(Hdr));
+    // Skip image ID info
+    Seek(Handle, Hdr.IDLength, smFromCurrent);
+    // Determine image format
+    Format := ifUnknown;
+    case Hdr.ImageType of
+      1, 9: Format := ifIndex8;
+      2, 10: case Hdr.PixelSize of
+          15: Format := ifX1R5G5B5;
+          16: Format := ifA1R5G5B5;
+          24: Format := ifR8G8B8;
+          32: Format := ifA8R8G8B8;
+        end;
+      3, 11: Format := ifGray8;
+    end;
+    // Format was not assigned by previous testing (it should be in
+    // well formed targas), so formats which reflects bit dept are selected
+    if Format = ifUnknown then
+      case Hdr.PixelSize of
+        8: Format := ifGray8;
+        15: Format := ifX1R5G5B5;
+        16: Format := ifA1R5G5B5;
+        24: Format := ifR8G8B8;
+        32: Format := ifA8R8G8B8;
+      end;
+    NewImage(Hdr.Width, Hdr.Height, Format, Images[0]);
+    FmtInfo := GetFormatInfo(Format);
+
+    if (Hdr.ColorMapType = 1) and (Hdr.ImageType in [1, 9]) then
+    begin
+      // Read palette
+      PSize := Hdr.ColorMapLength * (Hdr.ColorEntrySize shr 3);
+      GetMem(Pal, PSize);
+      try
+        Read(Handle, Pal, PSize);
+        // Process palette
+        PalSize := Iff(Hdr.ColorMapLength > FmtInfo.PaletteEntries,
+          FmtInfo.PaletteEntries, Hdr.ColorMapLength);
+        for I := 0 to PalSize - 1 do
+          case Hdr.ColorEntrySize of
+            24:
+              with Palette[I] do
+              begin
+                A := $FF;
+                R := PPalette24(Pal)[I].R;
+                G := PPalette24(Pal)[I].G;
+                B := PPalette24(Pal)[I].B;
+              end;
+            // I've never seen tga with these palettes so they are untested
+            16:
+              with Palette[I] do
+              begin
+                A := (PWordArray(Pal)[I] and $8000) shr 12;
+                R := (PWordArray(Pal)[I] and $FC00) shr 7;
+                G := (PWordArray(Pal)[I] and $03E0) shr 2;
+                B := (PWordArray(Pal)[I] and $001F) shl 3;
+              end;
+            32:
+              with Palette[I] do
+              begin
+                A := PPalette32(Pal)[I].A;
+                R := PPalette32(Pal)[I].R;
+                G := PPalette32(Pal)[I].G;
+                B := PPalette32(Pal)[I].B;
+              end;
+          end;
+      finally
+        FreeMemNil(Pal);
+      end;
+    end;
+
+    case Hdr.ImageType of
+      0, 1, 2, 3:
+        // Load uncompressed mode images
+        Read(Handle, Bits, Size);
+      9, 10, 11:
+        // Load RLE compressed mode images
+        LoadRLE;
+    end;
+
+    // Check if there is alpha channel present in A1R5GB5 images, if it is not
+    // change format to X1R5G5B5
+    if Format = ifA1R5G5B5 then
+    begin
+      if not Has16BitImageAlpha(Width * Height, Bits) then
+        Format := ifX1R5G5B5;
+    end;
+
+    // We must find true end of file and set input' position to it
+    // paint programs appends extra info at the end of Targas
+    // some of them multiple times (PSP Pro 8)
+    repeat
+      ExtFound := False;
+      FooterFound := False;
+
+      if Read(Handle, @WordValue, 2) = 2 then
+      begin
+        // 495 = size of Extension Area
+        if WordValue = 495 then
+        begin
+          Seek(Handle, 493, smFromCurrent);
+          ExtFound := True;
+        end
+        else
+          Seek(Handle, -2, smFromCurrent);
+      end;
+
+      if Read(Handle, @Foo, SizeOf(Foo)) = SizeOf(Foo) then
+      begin
+        if Foo.Signature = STargaSignature then
+          FooterFound := True
+        else
+          Seek(Handle, -SizeOf(Foo), smFromCurrent);
+      end;
+    until (not ExtFound) and (not FooterFound);
+
+    // Some editors save targas flipped
+    if Hdr.Desc < 31 then
+      FlipImage(Images[0]);
+
+    Result := True;
+  end;
+end;
+
+function TTargaFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+var
+  I: LongInt;
+  Hdr: TTargaHeader;
+  FmtInfo: TImageFormatInfo;
+  Pal: PPalette24;
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+
+  procedure SaveRLE;
+  var
+    Dest: PByte;
+    WidthBytes, Written, I, Total, DestSize: LongInt;
+
+    function CountDiff(Data: PByte; Bpp, PixelCount: Longint): LongInt;
+    var
+      Pixel: LongWord;
+      NextPixel: LongWord;
+      N: LongInt;
+    begin
+      N := 0;
+      Pixel := 0;
+      NextPixel := 0;
+      if PixelCount = 1 then
+      begin
+        Result := PixelCount;
+        Exit;
+      end;
+      case Bpp of
+        1: Pixel := Data^;
+        2: Pixel := PWord(Data)^;
+        3: PColor24Rec(@Pixel)^ := PColor24Rec(Data)^;
+        4: Pixel := PLongWord(Data)^;
+      end;
+      while PixelCount > 1 do
+      begin
+        Inc(Data, Bpp);
+        case Bpp of
+          1: NextPixel := Data^;
+          2: NextPixel := PWord(Data)^;
+          3: PColor24Rec(@NextPixel)^ := PColor24Rec(Data)^;
+          4: NextPixel := PLongWord(Data)^;
+        end;
+        if NextPixel = Pixel then
+          Break;
+        Pixel := NextPixel;
+        N := N + 1;
+        PixelCount := PixelCount - 1;
+      end;
+      if NextPixel = Pixel then
+        Result := N
+      else
+        Result := N + 1;
+    end;
+
+    function CountSame(Data: PByte; Bpp, PixelCount: LongInt): LongInt;
+    var
+      Pixel: LongWord;
+      NextPixel: LongWord;
+      N: LongInt;
+    begin
+      N := 1;
+      Pixel := 0;
+      NextPixel := 0;
+      case Bpp of
+        1: Pixel := Data^;
+        2: Pixel := PWord(Data)^;
+        3: PColor24Rec(@Pixel)^ := PColor24Rec(Data)^;
+        4: Pixel := PLongWord(Data)^;
+      end;
+      PixelCount := PixelCount - 1;
+      while PixelCount > 0 do
+      begin
+        Inc(Data, Bpp);
+        case Bpp of
+          1: NextPixel := Data^;
+          2: NextPixel := PWord(Data)^;
+          3: PColor24Rec(@NextPixel)^ := PColor24Rec(Data)^;
+          4: NextPixel := PLongWord(Data)^;
+        end;
+        if NextPixel <> Pixel then
+          Break;
+        N := N + 1;
+        PixelCount := PixelCount - 1;
+      end;
+      Result := N;
+    end;
+
+    procedure RleCompressLine(Data: PByte; PixelCount, Bpp: LongInt; Dest:
+      PByte; var Written: LongInt);
+    const
+      MaxRun = 128;
+    var
+      DiffCount: LongInt;
+      SameCount: LongInt;
+      RleBufSize: LongInt;
+    begin
+      RleBufSize := 0;
+      while PixelCount > 0 do
+      begin
+        DiffCount := CountDiff(Data, Bpp, PixelCount);
+        SameCount := CountSame(Data, Bpp, PixelCount);
+        if (DiffCount > MaxRun) then
+          DiffCount := MaxRun;
+        if (SameCount > MaxRun) then
+          SameCount := MaxRun;
+        if (DiffCount > 0) then
+        begin
+          Dest^ := Byte(DiffCount - 1);
+          Inc(Dest);
+          PixelCount := PixelCount - DiffCount;
+          RleBufSize := RleBufSize + (DiffCount * Bpp) + 1;
+          Move(Data^, Dest^, DiffCount * Bpp);
+          Inc(Data, DiffCount * Bpp);
+          Inc(Dest, DiffCount * Bpp);
+        end;
+        if SameCount > 1 then
+        begin
+          Dest^ := Byte((SameCount - 1) or $80);
+          Inc(Dest);
+          PixelCount := PixelCount - SameCount;
+          RleBufSize := RleBufSize + Bpp + 1;
+          Inc(Data, (SameCount - 1) * Bpp);
+          case Bpp of
+            1: Dest^ := Data^;
+            2: PWord(Dest)^ := PWord(Data)^;
+            3: PColor24Rec(Dest)^ := PColor24Rec(Data)^;
+            4: PLongWord(Dest)^ := PLongWord(Data)^;
+          end;
+          Inc(Data, Bpp);
+          Inc(Dest, Bpp);
+        end;
+      end;
+      Written := RleBufSize;
+    end;
+
+  begin
+    with ImageToSave do
+    begin
+      // Allocate enough space to hold the worst case compression
+      // result and then compress source's scanlines
+      WidthBytes := Width * FmtInfo.BytesPerPixel;
+      DestSize := WidthBytes * Height;
+      DestSize := DestSize + DestSize div 2 + 1;
+      GetMem(Dest, DestSize);
+      Total := 0;
+      try
+        for I := 0 to Height - 1 do
+        begin
+          RleCompressLine(@PByteArray(Bits)[I * WidthBytes], Width,
+            FmtInfo.BytesPerPixel, @PByteArray(Dest)[Total], Written);
+          Total := Total + Written;
+        end;
+        GetIO.Write(Handle, Dest, Total);
+      finally
+        FreeMem(Dest);
+      end;
+    end;
+  end;
+
+begin
+  Result := False;
+  if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
+  with GetIO, ImageToSave do
+  try
+    FmtInfo := GetFormatInfo(Format);
+    // Fill targa header
+    FillChar(Hdr, SizeOf(Hdr), 0);
+    Hdr.IDLength := 0;
+    Hdr.ColorMapType := Iff(FmtInfo.PaletteEntries > 0, 1, 0);
+    Hdr.Width := Width;
+    Hdr.Height := Height;
+    Hdr.PixelSize := FmtInfo.BytesPerPixel * 8;
+    Hdr.ColorMapLength := FmtInfo.PaletteEntries;
+    Hdr.ColorEntrySize := Iff(FmtInfo.PaletteEntries > 0, 24, 0);
+    Hdr.ColorMapOff := 0;
+    // This indicates that targa is stored in top-left format
+    // as our images -> no flipping is needed.
+    Hdr.Desc := 32;
+    // Set alpha channel size in descriptor (mostly ignored by other software though)
+    if Format = ifA8R8G8B8 then
+      Hdr.Desc := Hdr.Desc or 8
+    else if Format = ifA1R5G5B5 then
+      Hdr.Desc := Hdr.Desc or 1;
+
+    // Choose image type
+    if FmtInfo.IsIndexed then
+      Hdr.ImageType := Iff(FUseRLE, 9, 1)
+    else
+      if FmtInfo.HasGrayChannel then
+        Hdr.ImageType := Iff(FUseRLE, 11, 3)
+      else
+        Hdr.ImageType := Iff(FUseRLE, 10, 2);
+
+    Write(Handle, @Hdr, SizeOf(Hdr));
+
+    // Write palette
+    if FmtInfo.PaletteEntries > 0 then
+    begin
+      GetMem(Pal, FmtInfo.PaletteEntries * SizeOf(TColor24Rec));
+      try
+        for I := 0 to FmtInfo.PaletteEntries - 1 do
+          with Pal[I] do
+          begin
+            R := Palette[I].R;
+            G := Palette[I].G;
+            B := Palette[I].B;
+          end;
+        Write(Handle, Pal, FmtInfo.PaletteEntries * SizeOf(TColor24Rec));
+      finally
+        FreeMemNil(Pal);
+      end;
+    end;
+
+    if FUseRLE then
+      // Save rle compressed mode images
+      SaveRLE
+    else
+      // Save uncompressed mode images
+      Write(Handle, Bits, Size);
+
+    Result := True;
+  finally
+    if MustBeFreed then
+      FreeImage(ImageToSave);
+  end;
+end;
+
+procedure TTargaFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+var
+  ConvFormat: TImageFormat;
+begin
+  if Info.HasGrayChannel then
+    // Convert all grayscale images to Gray8 (preserve alpha of AxGrayx formats)
+    ConvFormat := IffFormat(not Info.HasAlphaChannel, ifGray8, ifA8R8G8B8)
+  else if Info.IsIndexed then
+    // Convert all indexed images to Index8
+    ConvFormat := ifIndex8
+  else if Info.HasAlphaChannel then
+    // Convert images with alpha channel to A8R8G8B8
+    ConvFormat := ifA8R8G8B8
+  else if Info.UsePixelFormat then
+    // Convert 16bit images (without alpha channel) to A1R5G5B5
+    ConvFormat := ifA1R5G5B5
+  else
+    // Convert all other formats to R8G8B8
+    ConvFormat := ifR8G8B8;
+
+  ConvertImage(Image, ConvFormat);
+end;
+
+function TTargaFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Hdr: TTargaHeader;
+  ReadCount: LongInt;
+begin
+  Result := False;
+  if Handle <> nil then
+  begin
+    ReadCount := GetIO.Read(Handle, @Hdr, SizeOf(Hdr));
+    GetIO.Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (ReadCount >= SizeOf(Hdr)) and
+      (Hdr.ImageType in [0, 1, 2, 3, 9, 10, 11]) and
+      (Hdr.PixelSize in [1, 8, 15, 16, 24, 32]) and
+      (Hdr.ColorEntrySize in [0, 16, 24, 32]);
+  end;
+end;
+
+initialization
+  RegisterImageFileFormat(TTargaFileFormat);
+
+{
+  File Notes:
+
+ -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - MakeCompatible method moved to base class, put ConvertToSupported here.
+      GetSupportedFormats removed, it is now set in constructor.
+    - Made public properties for options registered to SetOption/GetOption
+      functions.
+    - Changed extensions to filename masks.
+    - Changed SaveData, LoadData, and MakeCompatible methods according
+      to changes in base class in Imaging unit.
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - 16 bit images are usually without alpha but some has alpha
+      channel and there is no indication of it - so I have added
+      a check: if all pixels of image are with alpha = 0 image is treated
+      as X1R5G5B5 otherwise as A1R5G5B5
+    - fixed problems with some nonstandard 15 bit images
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingTypes.pas b/src/lib/vampimg/ImagingTypes.pas
new file mode 100644 (file)
index 0000000..9c5e1f1
--- /dev/null
@@ -0,0 +1,564 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains basic types and constants used by Imaging library.}
+unit ImagingTypes;
+
+{$I ImagingOptions.inc}
+
+interface
+
+const
+  { Current Major version of Imaging.}
+  ImagingVersionMajor = 0;
+  { Current Minor version of Imaging.}
+  ImagingVersionMinor = 77;
+  { Current patch of Imaging.}
+  ImagingVersionPatch = 2;
+
+  { Imaging Option Ids whose values can be set/get by SetOption/
+    GetOption functions.}
+
+  { Defines Jpeg compression quality, ranges from 1 (ugly/small) to 100 (nice/large).
+    Default value is 90.}
+  ImagingJpegQuality           = 10;
+  { Specifies whether Jpeg images are saved in progressive format,
+    can be 0 or 1. Default value is 0.}
+  ImagingJpegProgressive       = 11;
+
+  { Specifies whether Windows Bitmaps are saved using RLE compression
+    (only for 1/4/8 bit images), can be 0 or 1. Default value is 1.}
+  ImagingBitmapRLE             = 12;
+
+  { Specifies whether Targa images are saved using RLE compression,
+    can be 0 or 1. Default value is 0.}
+  ImagingTargaRLE              = 13;
+
+  { Value of this option is non-zero if last loaded DDS file was cube map.}
+  ImagingDDSLoadedCubeMap      = 14;
+  { Value of this option is non-zero if last loaded DDS file was volume texture.}
+  ImagingDDSLoadedVolume       = 15;
+  { Value of this option is number of mipmap levels of last loaded DDS image.}
+  ImagingDDSLoadedMipMapCount  = 16;
+  { Value of this option is depth (slices of volume texture or faces of
+    cube map) of last loaded DDS image.}
+  ImagingDDSLoadedDepth        = 17;
+  { If it is non-zero next saved DDS file should be stored as cube map.}
+  ImagingDDSSaveCubeMap        = 18;
+  { If it is non-zero next saved DDS file should be stored as volume texture.}
+  ImagingDDSSaveVolume         = 19;
+  { Sets the number of mipmaps which should be stored in the next saved DDS file.
+    Only applies to cube maps and volumes, ordinary 2D textures save all
+    levels present in input.}
+  ImagingDDSSaveMipMapCount    = 20;
+  { Sets the depth (slices of volume texture or faces of cube map)
+    of the next saved DDS file.}
+  ImagingDDSSaveDepth          = 21;
+
+  { Sets precompression filter used when saving PNG images. Allowed values
+    are: 0 (none), 1 (sub), 2 (up), 3 (average), 4 (paeth),
+    5 (use 0 for indexed/gray images and 4 for RGB/ARGB images),
+    6 (adaptive filtering - use best filter for each scanline - very slow).
+    Note that filters 3 and 4 are much slower than filters 1 and 2.
+    Default value is 5.}
+  ImagingPNGPreFilter          = 25;
+  { Sets ZLib compression level used when saving PNG images.
+    Allowed values are in range 0 (no compresstion) to 9 (best compression).
+    Default value is 5.}
+  ImagingPNGCompressLevel      = 26;
+  { Boolean option that specifies whether PNG images with more frames (APNG format)
+    are animated by Imaging (according to frame disposal/blend methods) or just
+    raw frames are loaded and sent to user (if you want to animate APNG yourself).
+    Default value is 1.}
+  ImagingPNGLoadAnimated       = 27;
+  { Sets ZLib compression strategy used when saving PNG files (see deflateInit2()
+    in ZLib for details). Allowed values are: 0 (default), 1 (filtered),
+    2 (huffman only). Default value is 0.}
+  ImagingPNGZLibStrategy       = 28;
+
+  { Specifies whether MNG animation frames are saved with lossy or lossless
+    compression. Lossless frames are saved as PNG images and lossy frames are
+    saved as JNG images. Allowed values are 0 (False) and 1 (True).
+    Default value is 0.}
+  ImagingMNGLossyCompression   = 32;
+  { Defines whether alpha channel of lossy compressed MNG frames
+    (when ImagingMNGLossyCompression is 1) is lossy compressed too.
+    Allowed values are 0 (False) and 1 (True). Default value is 0.}
+  ImagingMNGLossyAlpha         = 33;
+  { Sets precompression filter used when saving MNG frames as PNG images.
+    For details look at ImagingPNGPreFilter.}
+  ImagingMNGPreFilter          = 34;
+  { Sets ZLib compression level used when saving MNG frames as PNG images.
+    For details look at ImagingPNGCompressLevel.}
+  ImagingMNGCompressLevel      = 35;
+  { Specifies compression quality used when saving MNG frames as JNG images.
+    For details look at ImagingJpegQuality.}
+  ImagingMNGQuality            = 36;
+  { Specifies whether images are saved in progressive format when saving MNG
+    frames as JNG images. For details look at ImagingJpegProgressive.}
+  ImagingMNGProgressive        = 37;
+
+  { Specifies whether alpha channels of JNG images are lossy compressed.
+    Allowed values are 0 (False) and 1 (True). Default value is 0.}
+  ImagingJNGLossyAlpha         = 40;
+  { Sets precompression filter used when saving lossless alpha channels.
+    For details look at ImagingPNGPreFilter.}
+  ImagingJNGAlphaPreFilter     = 41;
+  { Sets ZLib compression level used when saving lossless alpha channels.
+    For details look at ImagingPNGCompressLevel.}
+  ImagingJNGAlphaCompressLevel = 42;
+  { Defines compression quality used when saving JNG images (and lossy alpha channels).
+    For details look at ImagingJpegQuality.}
+  ImagingJNGQuality            = 43;
+  { Specifies whether JNG images are saved in progressive format.
+    For details look at ImagingJpegProgressive.}
+  ImagingJNGProgressive        = 44;
+
+  { Specifies whether PGM files are stored in text or in binary format.
+    Allowed values are 0 (store as text - very! large files) and 1 (save binary).
+    Default value is 1.}
+  ImagingPGMSaveBinary         = 50;
+
+  { Specifies whether PPM files are stored in text or in binary format.
+    Allowed values are 0 (store as text - very! large files) and 1 (save binary).
+    Default value is 1.}
+  ImagingPPMSaveBinary         = 51;
+
+  { Boolean option that specifies whether GIF images with more frames
+    are animated by Imaging (according to frame disposal methods) or just
+    raw frames are loaded and sent to user (if you want to animate GIF yourself).
+    Default value is 1.
+    Raw frames are 256 color indexed images (ifIndex8), whereas
+    animated frames are always in 32bit ifA8R8G8B8 format (simplifies animating).}
+  ImagingGIFLoadAnimated       = 56;
+
+  { This option is used when reducing number of colors used in
+    image (mainly when converting from ARGB image to indexed
+    format). Mask is 'anded' (bitwise AND) with every pixel's
+    channel value when creating color histogram. If $FF is used
+    all 8bits of color channels are used which can result in very
+    slow proccessing of large images with many colors so you can
+    use lower masks to speed it up (FC, F8 and F0 are good
+    choices). Allowed values are in range <0, $FF> and default is
+    $FE.                                                          }
+  ImagingColorReductionMask   = 128;
+  { This option can be used to override image data format during image
+    loading. If set to format different from ifUnknown all loaded images
+    are automaticaly converted to this format. Useful when you have
+    many files in various formats but you want them all in one format for
+    further proccessing. Allowed values are in
+    range <Ord(Low(TImageFormat)), Ord(High(TImageFormat))> and
+    default value is ifUnknown.}
+  ImagingLoadOverrideFormat   = 129;
+  { This option can be used to override image data format during image
+    saving. If set to format different from ifUnknown all images
+    to be saved are automaticaly internaly converted to this format.
+    Note that image file formats support only a subset of Imaging data formats
+    so final saved file may in different format than this override.
+    Allowed values are in range <Ord(Low(TImageFormat)), Ord(High(TImageFormat))>
+    and default value is ifUnknown.}
+  ImagingSaveOverrideFormat   = 130;
+  { Specifies resampling filter used when generating mipmaps. It is used
+    in GenerateMipMaps low level function and Direct3D and OpenGL extensions.
+    Allowed values are in range
+    <Ord(Low(ImagingFormats.TSamplingFilter)), Ord(High(ImagingFormats.TSamplingFilter))>
+    and default value is 1 (linear filter).}
+  ImagingMipMapFilter         = 131;
+  { Specifies treshold value used when automatically converting images to
+    ifBinary format. For adaptive tresholding see ImagingBinary.pas unit.
+    Default value is 128 and allowed range is 0..255.}
+  ImagingBinaryTreshold       = 132;
+
+  { Returned by GetOption if given Option Id is invalid.}
+  InvalidOption = -$7FFFFFFF;
+
+  { Indices that can be used to access channel values in array parts
+    of structures like TColor32Rec. Note that this order can be
+    used only for ARGB images. For ABGR image you must swap Red and Blue.}
+  ChannelBlue  = 0;
+  ChannelGreen = 1;
+  ChannelRed   = 2;
+  ChannelAlpha = 3;
+
+type
+  { Enum defining image data format. In formats with more channels,
+    first channel after "if" is stored in the most significant bits and channel
+    before end is stored in the least significant.}
+  TImageFormat = (
+    ifUnknown        = 0,
+    ifDefault        = 1,
+    { Indexed formats using palette }
+    ifIndex8         = 10,
+    { Grayscale/Luminance formats }
+    ifGray8          = 40,
+    ifA8Gray8        = 41,
+    ifGray16         = 42,
+    ifGray32         = 43,
+    ifGray64         = 44,
+    ifA16Gray16      = 45,
+    { ARGB formats }
+    ifX5R1G1B1       = 80,
+    ifR3G3B2         = 81,
+    ifR5G6B5         = 82,
+    ifA1R5G5B5       = 83,
+    ifA4R4G4B4       = 84,
+    ifX1R5G5B5       = 85,
+    ifX4R4G4B4       = 86,
+    ifR8G8B8         = 87,
+    ifA8R8G8B8       = 88,
+    ifX8R8G8B8       = 89,
+    ifR16G16B16      = 90,
+    ifA16R16G16B16   = 91,
+    ifB16G16R16      = 92,
+    ifA16B16G16R16   = 93,
+    { Floating point formats }
+    ifR32F           = 160,
+    ifA32R32G32B32F  = 161,
+    ifA32B32G32R32F  = 162,
+    ifR16F           = 163,
+    ifA16R16G16B16F  = 164,
+    ifA16B16G16R16F  = 165,
+    ifR32G32B32F     = 166,
+    ifB32G32R32F     = 167,
+    { Special formats }
+    ifDXT1           = 200,
+    ifDXT3           = 201,
+    ifDXT5           = 202,
+    ifBTC            = 203,
+    ifATI1N          = 204,
+    ifATI2N          = 205,
+    ifBinary         = 206
+    { Passtrough formats }
+    {ifETC1           = 220,
+    ifETC2RGB        = 221,
+    ifETC2RGBA       = 222,
+    ifETC2PA         = 223,
+    ifDXBC6          = 224,
+    ifDXBC7          = 225}
+  );
+
+  { Color value for 32 bit images.}
+  TColor32 = LongWord;
+  PColor32 = ^TColor32;
+
+  { Color value for 64 bit images.}
+  TColor64 = type Int64;
+  PColor64 = ^TColor64;
+
+  { Color record for 24 bit images, which allows access to individual color
+    channels.}
+  TColor24Rec = packed record
+    case LongInt of
+      0: (B, G, R: Byte);
+      1: (Channels: array[0..2] of Byte);
+  end;
+  PColor24Rec = ^TColor24Rec;
+  TColor24RecArray = array[0..MaxInt div SizeOf(TColor24Rec) - 1] of TColor24Rec;
+  PColor24RecArray = ^TColor24RecArray;
+
+  { Color record for 32 bit images, which allows access to individual color
+    channels.}
+  TColor32Rec = packed record
+    case LongInt of
+      0: (Color: TColor32);
+      1: (B, G, R, A: Byte);
+      2: (Channels: array[0..3] of Byte);
+      3: (Color24Rec: TColor24Rec);
+  end;
+  PColor32Rec = ^TColor32Rec;
+  TColor32RecArray = array[0..MaxInt div SizeOf(TColor32Rec) - 1] of TColor32Rec;
+  PColor32RecArray = ^TColor32RecArray;
+
+  { Color record for 48 bit images, which allows access to individual color
+    channels.}
+  TColor48Rec = packed record
+    case LongInt of
+      0: (B, G, R: Word);
+      1: (Channels: array[0..2] of Word);
+  end;
+  PColor48Rec = ^TColor48Rec;
+  TColor48RecArray = array[0..MaxInt div SizeOf(TColor48Rec) - 1] of TColor48Rec;
+  PColor48RecArray = ^TColor48RecArray;
+
+  { Color record for 64 bit images, which allows access to individual color
+    channels.}
+  TColor64Rec = packed record
+    case LongInt of
+      0: (Color: TColor64);
+      1: (B, G, R, A: Word);
+      2: (Channels: array[0..3] of Word);
+      3: (Color48Rec: TColor48Rec);
+  end;
+  PColor64Rec = ^TColor64Rec;
+  TColor64RecArray = array[0..MaxInt div SizeOf(TColor64Rec) - 1] of TColor64Rec;
+  PColor64RecArray = ^TColor64RecArray;
+
+  { Color record for 96 bit floating point images, which allows access to
+    individual color channels.}
+  TColor96FPRec = packed record
+    case Integer of
+      0: (B, G, R: Single);
+      1: (Channels: array[0..2] of Single);
+  end;
+  PColor96FPRec = ^TColor96FPRec;
+  TColor96FPRecArray = array[0..MaxInt div SizeOf(TColor96FPRec) - 1] of TColor96FPRec;
+  PColor96FPRecArray = ^TColor96FPRecArray;
+
+  { Color record for 128 bit floating point images, which allows access to
+    individual color channels.}
+  TColorFPRec = packed record
+    case LongInt of
+      0: (B, G, R, A: Single);
+      1: (Channels: array[0..3] of Single);
+      2: (Color96Rec: TColor96FPRec);
+  end;
+  PColorFPRec = ^TColorFPRec;
+  TColorFPRecArray = array[0..MaxInt div SizeOf(TColorFPRec) - 1] of TColorFPRec;
+  PColorFPRecArray = ^TColorFPRecArray;
+
+  { 16 bit floating-point value. It has 1 sign bit, 5 exponent bits,
+    and 10 mantissa bits.}
+  THalfFloat = type Word;
+  PHalfFloat = ^THalfFloat;
+
+  { Color record for 64 bit floating point images, which allows access to
+    individual color channels.}
+  TColorHFRec = packed record
+    case LongInt of
+      0: (B, G, R, A: THalfFloat);
+      1: (Channels: array[0..3] of THalfFloat);
+  end;
+  PColorHFRec = ^TColorHFRec;
+  TColorHFRecArray = array[0..MaxInt div SizeOf(TColorHFRec) - 1] of TColorHFRec;
+  PColorHFRecArray = ^TColorHFRecArray;
+
+  { Palette for indexed mode images with 32 bit colors.}
+  TPalette32 = TColor32RecArray;
+  TPalette32Size256 = array[0..255] of TColor32Rec;
+  PPalette32 = ^TPalette32;
+
+  { Palette for indexd mode images with 24 bit colors.}
+  TPalette24 = TColor24RecArray;
+  TPalette24Size256 = array[0..255] of TColor24Rec;
+  PPalette24 = ^TPalette24;
+
+  { Record that stores single image data and information describing it.}
+  TImageData = packed record
+    Width: LongInt;       // Width of image in pixels
+    Height: LongInt;      // Height of image in pixels
+    Format: TImageFormat; // Data format of image
+    Size: LongInt;        // Size of image bits in Bytes
+    Bits: Pointer;        // Pointer to memory containing image bits
+    Palette: PPalette32;  // Image palette for indexed images
+    Tag: Pointer;         // User data
+  end;
+  PImageData = ^TImageData;
+
+  { Pixel format information used in conversions to/from 16 and 8 bit ARGB
+    image formats.}
+  TPixelFormatInfo = packed record
+    ABitCount, RBitCount, GBitCount, BBitCount: Byte;
+    ABitMask, RBitMask, GBitMask, BBitMask: LongWord;
+    AShift, RShift, GShift, BShift: Byte;
+    ARecDiv, RRecDiv, GRecDiv, BRecDiv: Byte;
+  end;
+  PPixelFormatInfo = ^TPixelFormatInfo;
+
+  PImageFormatInfo = ^TImageFormatInfo;
+
+  { Look at TImageFormatInfo.GetPixelsSize for details.}
+  TFormatGetPixelsSizeFunc = function(Format: TImageFormat; Width,
+    Height: LongInt): LongInt;
+  { Look at TImageFormatInfo.CheckDimensions for details.}
+  TFormatCheckDimensionsProc = procedure(Format: TImageFormat; var Width,
+    Height: LongInt);
+  { Function for getting pixel colors. Native pixel is read from Image and
+    then translated to 32 bit ARGB.}
+  TGetPixel32Func = function(Bits: Pointer; Info: PImageFormatInfo;
+    Palette: PPalette32): TColor32Rec;
+  { Function for getting pixel colors. Native pixel is read from Image and
+    then translated to FP ARGB.}
+  TGetPixelFPFunc = function(Bits: Pointer; Info: PImageFormatInfo;
+    Palette: PPalette32): TColorFPRec;
+  { Procedure for setting pixel colors. Input 32 bit ARGB color is translated to
+    native format and then written to Image.}
+  TSetPixel32Proc = procedure(Bits: Pointer; Info: PImageFormatInfo;
+    Palette: PPalette32;const Color: TColor32Rec);
+  { Procedure for setting pixel colors. Input FP ARGB color is translated to
+    native format and then written to Image.}
+  TSetPixelFPProc = procedure(Bits: Pointer; Info: PImageFormatInfo;
+    Palette: PPalette32; const Color: TColorFPRec);
+
+  { Additional information for each TImageFormat value.}
+  TImageFormatInfo = packed record
+    Format: TImageFormat;             // Format described by this record
+    Name: array[0..15] of Char;       // Symbolic name of format
+    BytesPerPixel: LongInt;           // Number of bytes per pixel (note: it is
+                                      // 0 for formats where BitsPerPixel < 8 (e.g. DXT).
+                                      // Use GetPixelsSize function to get size of
+                                      // image data.
+    ChannelCount: LongInt;            // Number of image channels (R, G, B, A, Gray)
+    PaletteEntries: LongInt;          // Number of palette entries
+    HasGrayChannel: Boolean;          // True if image has grayscale channel
+    HasAlphaChannel: Boolean;         // True if image has alpha channel
+    IsFloatingPoint: Boolean;         // True if image has floating point pixels
+    UsePixelFormat: Boolean;          // True if image uses pixel format
+    IsRBSwapped: Boolean;             // True if Red and Blue channels are swapped
+                                      // e.g. A16B16G16R16 has IsRBSwapped True
+    RBSwapFormat: TImageFormat;       // Indicates supported format with swapped
+                                      // Red and Blue channels, ifUnknown if such
+                                      // format does not exist
+    IsIndexed: Boolean;               // True if image uses palette
+    IsSpecial: Boolean;               // True if image is in special format
+    IsPasstrough: Boolean;            // True if image is in passtrough program (Imaging
+                                      // iself doesn't know how to decode and encode it -
+                                      // complex texture compressions etc.)
+    PixelFormat: PPixelFormatInfo;    // Pixel format structure
+    GetPixelsSize: TFormatGetPixelsSizeFunc; // Returns size in bytes of
+                                      // Width * Height pixels of image
+    CheckDimensions: TFormatCheckDimensionsProc; // some formats have limited
+                                      // values of Width and Height. This
+                                      // procedure checks and changes dimensions
+                                      // to be valid for given format.
+    GetPixel32: TGetPixel32Func;      // 32bit ARGB pixel get function
+    GetPixelFP: TGetPixelFPFunc;      // FP ARGB pixel get function
+    SetPixel32: TSetPixel32Proc;      // 32bit ARGB pixel set procedure
+    SetPixelFP: TSetPixelFPProc;      // FP ARGB pixel set procedure
+    SpecialNearestFormat: TImageFormat; // Regular image format used when
+                                      // compressing/decompressing special images
+                                      // as source/target
+  end;
+
+  { Handle to list of image data records.}
+  TImageDataList = Pointer;
+  PImageDataList = ^TImageDataList;
+
+  { Handle to input/output.}
+  TImagingHandle = Pointer;
+
+  { Filters used in functions that resize images or their portions.}
+  TResizeFilter = (
+    rfNearest  = 0,
+    rfBilinear = 1,
+    rfBicubic  = 2,
+    rfLanczos  = 3);
+
+  { Seek origin mode for IO function Seek.}
+  TSeekMode = (
+   smFromBeginning = 0,
+   smFromCurrent   = 1,
+   smFromEnd       = 2);
+
+  TOpenMode = (
+    omReadOnly  = 0, // Opens file for reading only
+    omCreate    = 1, // Creates new file (overwriting any existing) and opens it for writing
+    omReadWrite = 2  // Opens for reading and writing. Non existing file is created.
+  );
+
+  { IO functions used for reading and writing images from/to input/output.}
+  TOpenProc = function(Source: PChar; Mode: TOpenMode): TImagingHandle; cdecl;
+  TCloseProc = procedure(Handle: TImagingHandle); cdecl;
+  TEofProc = function(Handle: TImagingHandle): Boolean; cdecl;
+  TSeekProc = function(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): LongInt; cdecl;
+  TTellProc = function(Handle: TImagingHandle): LongInt; cdecl;
+  TReadProc = function(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl;
+  TWriteProc = function(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl;
+
+{$IFNDEF FPC}
+type
+{$IF CompilerVersion <= 18.5}
+  PtrUInt = LongWord;
+{$ELSE}
+  PtrUInt = NativeUInt;
+{$IFEND}
+{$ENDIF}
+
+implementation
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - add lookup tables to pixel formats for fast conversions
+
+  -- 0.77.1 ---------------------------------------------------
+    - Added "Passtrough" image data formats.
+    - Added Tag to TImageData for storing user data.
+    - Added ImagingPNGZLibStrategy option.
+    - Changed IO functions. Merged open functions to one
+      and added third open mode R/W (for TIFF append etc.).
+    - Added new image data formats and related structures:
+      ifR32G32B32F, ifB32G32G32F.
+
+  -- 0.26.5 Changes/Bug Fixes ---------------------------------
+    - Added ifBinary image format and ImagingBinaryTreshold option.
+    - Lanczos filter added to TResizeFilter enum.
+
+  -- 0.24.3 Changes/Bug Fixes ---------------------------------
+    - Added ifATI1N and ifATI2N image data formats.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added ifBTC image format and SpecialNearestFormat field
+      to TImageFormatInfo.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Added option constants for PGM and PPM file formats.
+    - Added TPalette32Size256 and TPalette24Size256 types.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - added ImagingVersionPatch constant so bug fix only releases
+      can be distinguished from ordinary major/minor releases
+    - renamed TPixelFormat to TPixelFormatInfo to avoid name collisions
+      with Graphics.TPixelFormat
+    - added new image data formats:  ifR16F, ifA16R16G16B16F,
+      ifA16B16G16R16F
+    - added pixel get/set function pointers to TImageFormatInfo
+    - added 16bit half float type and color record
+    - renamed TColorFRec to TColorFPRec (and related types too)
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+    - added option ImagingMipMapFilter which now controls resampling filter
+      used when generating mipmaps
+    - added TResizeFilter type
+    - added ChannelCount to TImageFormatInfo
+    - added new option constants for MNG and JNG images
+
+  -- 0.15 Changes/Bug Fixes -----------------------------------
+    - added RBSwapFormat to TImageFormatInfo for faster conversions
+      between swapped formats (it just calls SwapChannels now if
+      RBSwapFormat is not ifUnknown)
+    - moved TImageFormatInfo and required types from Imaging unit
+      here, removed TImageFormatShortInfo
+    - added new options: ImagingLoadOverrideFormat, ImagingSaveOverrideFormat
+
+  -- 0.13 Changes/Bug Fixes -----------------------------------
+    - new ImagingColorReductionMask option added
+    - new image format added: ifA16Gray16
+
+}
+
+end.
diff --git a/src/lib/vampimg/ImagingUtility.pas b/src/lib/vampimg/ImagingUtility.pas
new file mode 100644 (file)
index 0000000..c137e1d
--- /dev/null
@@ -0,0 +1,1691 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains utility functions and types for Imaging library.}
+unit ImagingUtility;
+
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, Classes, Types;
+
+const
+  STrue = 'True';
+  SFalse = 'False';
+
+type
+  TByteArray = array[0..MaxInt - 1] of Byte;
+  PByteArray = ^TByteArray;
+  TWordArray = array[0..MaxInt div 2 - 1] of Word;
+  PWordArray = ^TWordArray;
+  TLongIntArray = array[0..MaxInt div 4 - 1] of LongInt;
+  PLongIntArray = ^TLongIntArray;
+  TLongWordArray = array[0..MaxInt div 4 - 1] of LongWord;
+  PLongWordArray = ^TLongWordArray;
+  TInt64Array = array[0..MaxInt div 8 - 1] of Int64;
+  PInt64Array = ^TInt64Array;
+  TSingleArray = array[0..MaxInt div 4 - 1] of Single;
+  PSingleArray = ^TSingleArray;
+  TBooleanArray = array[0..MaxInt - 1] of Boolean;
+  PBooleanArray = ^TBooleanArray;
+
+  TDynByteArray = array of Byte;
+  TDynIntegerArray = array of Integer;
+  TDynBooleanArray = array of Boolean;
+  TDynStringArray = array of string;
+
+  TWordRec = packed record
+    case Integer of
+      0: (WordValue: Word);
+      1: (Low, High: Byte);
+  end;
+  PWordRec = ^TWordRec;
+  TWordRecArray = array[0..MaxInt div 2 - 1] of TWordRec;
+  PWordRecArray = ^TWordRecArray;
+
+  TLongWordRec = packed record
+    case Integer of
+      0: (LongWordValue: LongWord);
+      1: (Low, High: Word);
+      { Array variants - Index 0 means lowest significant byte (word, ...).}
+      2: (Words: array[0..1] of Word);
+      3: (Bytes: array[0..3] of Byte);
+  end;
+  PLongWordRec = ^TLongWordRec;
+  TLongWordRecArray = array[0..MaxInt div 4 - 1] of TLongWordRec;
+  PLongWordRecArray = ^TLongWordRecArray;
+
+  TInt64Rec = packed record
+    case Integer of
+      0: (Int64Value: Int64);
+      1: (Low, High: LongWord);
+      { Array variants - Index 0 means lowest significant byte (word, ...).}
+      2: (Words: array[0..3] of Word);
+      3: (Bytes: array[0..7] of Byte);
+  end;
+  PInt64Rec = ^TInt64Rec;
+  TInt64RecArray = array[0..MaxInt div 8 - 1] of TInt64Rec;
+  PInt64RecArray = ^TInt64RecArray;
+
+  TFloatHelper = record
+    Data: Int64;
+    case Integer of
+      0: (Data64: Int64);
+      1: (Data32: LongWord);
+  end;
+  PFloatHelper = ^TFloatHelper;
+
+  TFloatRect = record
+    Left, Top, Right, Bottom: Single;
+  end;
+
+  TChar2 = array[0..1] of AnsiChar;
+  TChar3 = array[0..2] of AnsiChar;
+  TChar4 = array[0..3] of AnsiChar;
+  TChar8 = array[0..7] of AnsiChar;
+  TChar16 = array[0..15] of AnsiChar;
+  TAnsiCharSet = set of AnsiChar;
+
+  ENotImplemented = class(Exception)
+  public
+    constructor Create;
+  end;
+
+  { Options for BuildFileList function:
+    flFullNames - file names in result will have full path names
+                (ExtractFileDir(Path) + FileName)
+    flRelNames  - file names in result will have names relative to
+                ExtractFileDir(Path) dir
+    flRecursive - adds files in subdirectories found in Path.}
+  TFileListOption = (flFullNames, flRelNames, flRecursive);
+  TFileListOptions = set of TFileListOption;
+
+
+{ Frees class instance and sets its reference to nil.}
+procedure FreeAndNil(var Obj);
+{ Frees pointer and sets it to nil.}
+procedure FreeMemNil(var P); {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Replacement of standard System.FreeMem procedure which checks if P is nil
+  (this is only needed for Free Pascal, Delphi makes checks in its FreeMem).}
+procedure FreeMem(P: Pointer); {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns current exception object. Do not call outside exception handler.}
+function GetExceptObject: Exception; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns time value with microsecond resolution.}
+function GetTimeMicroseconds: Int64;
+{ Returns time value with milisecond resolution.}
+function GetTimeMilliseconds: Int64;
+
+{ Returns file extension (without "." dot)}
+function GetFileExt(const FileName: string): string;
+{ Returns file name of application's executable.}
+function GetAppExe: string;
+{ Returns directory where application's exceutable is located without
+  path delimiter at the end.}
+function GetAppDir: string;
+{ Works like SysUtils.ExtractFileName but supports '/' and '\' dir delimiters
+  at the same time (whereas ExtractFileName supports on default delimiter on current platform).}
+function GetFileName(const FileName: string): string;
+{ Works like SysUtils.ExtractFileDir but supports '/' and '\' dir delimiters
+  at the same time (whereas ExtractFileDir supports on default delimiter on current platform).}
+function GetFileDir(const FileName: string): string;
+{ Returns True if Subject matches given Mask with optional case sensitivity.
+  Mask can contain ? and * special characters: ? matches
+  one character, * matches zero or more characters.}
+function StrMaskMatch(const Subject, Mask: string; CaseSensitive: Boolean = False): Boolean;
+{ This function fills Files string list with names of files found
+  with FindFirst/FindNext functions (See details on Path/Atrr here).
+  - BuildFileList('c:\*.*', faAnyFile, List, [flRecursive]) returns
+    list of all files (only name.ext - no path) on C drive
+  - BuildFileList('d:\*.*', faDirectory, List, [flFullNames]) returns
+    list of all directories (d:\dirxxx) in root of D drive.}
+function BuildFileList(Path: string; Attr: LongInt; Files: TStrings;
+  Options: TFileListOptions = []): Boolean;
+{ Similar to RTL's Pos function but with optional Offset where search will start.
+  This function is in the RTL StrUtils unit but }
+function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt;
+{ Same as PosEx but without case sensitivity.}
+function PosNoCase(const SubStr, S: string; Offset: LongInt = 1): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns a sub-string from S which is followed by
+  Sep separator and deletes the sub-string from S including the separator.}
+function StrToken(var S: string; Sep: Char): string;
+{ Same as StrToken but searches from the end of S string.}
+function StrTokenEnd(var S: string; Sep: Char): string;
+{ Fills instance of TStrings with tokens from string S where tokens are separated by
+  one of Seps characters.}
+procedure StrTokensToList(const S: string; Sep: Char; Tokens: TStrings);
+{ Returns string representation of integer number (with digit grouping).
+  Uses current locale.}
+function IntToStrFmt(const I: Int64): string; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns string representation of float number (with digit grouping).
+  Uses current locale.}
+function FloatToStrFmt(const F: Double; Precision: Integer = 2): string; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns format settings for parsing floats (dot as decimal separator).
+  Useful when fomatting/parsing floats etc.}
+function GetFormatSettingsForFloats: TFormatSettings;
+{ Returns True if S contains at least one of the substrings in SubStrs array. Case sensitive.}
+function ContainsAnySubStr(const S: string; const SubStrs: array of string): Boolean;
+{ Extracts substring starting at IdxStart ending at IdxEnd.
+  S[IdxEnd] is not included in the result.}
+function SubString(const S: string; IdxStart, IdxEnd: Integer): string; {$IFDEF USE_INLINE}inline;{$ENDIF}
+
+{ Clamps integer value to range <Min, Max>}
+function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Clamps float value to range <Min, Max>}
+function ClampFloat(Number: Single; Min, Max: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Clamps integer value to Byte boundaries.}
+function ClampToByte(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Clamps integer value to Word boundaries.}
+function ClampToWord(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns True if Num is power of 2.}
+function IsPow2(Num: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns next power of 2 greater than or equal to Num
+  (if Num itself is power of 2 then it retuns Num).}
+function NextPow2(Num: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Raises 2 to the given integer power (in range [0, 30]).}
+function Pow2Int(Exponent: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Raises Base to any power.}
+function Power(const Base, Exponent: Single): Single;
+{ Returns log base 2 of integer X (max 2^30) or -1 if X is not power of 2.}
+function Log2Int(X: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns log base 2 of X.}
+function Log2(X: Single): Single;
+{ Returns log base 10 of X.}
+function Log10(X: Single): Single;
+{ Returns largest integer <= Val (for 5.9 returns 5).}
+function Floor(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns smallest integer >= Val (for 5.1 returns 6).}
+function Ceil(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns lesser of two integer numbers.}
+function Min(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns lesser of two float numbers.}
+function MinFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns greater of two integer numbers.}
+function Max(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns greater of two float numbers.}
+function MaxFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns result from multiplying Number by Numerator and then dividing by Denominator.
+  Denominator must be greater than 0.}
+function MulDiv(Number, Numerator, Denominator: Word): Word; {$IFDEF USE_INLINE}inline;{$ENDIF}
+
+{ Switches Boolean value.}
+procedure Switch(var Value: Boolean); {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function Iff(Condition, TruePart, FalsePart: Boolean): Boolean; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function Iff(Condition: Boolean; const TruePart, FalsePart: string): string; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ If Condition is True then TruePart is retured, otherwise
+  FalsePart is returned.}
+function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Swaps two Boolean values}
+procedure SwapValues(var A, B: Boolean); overload;
+{ Swaps two Byte values}
+procedure SwapValues(var A, B: Byte); overload;
+{ Swaps two Word values}
+procedure SwapValues(var A, B: Word); overload;
+{ Swaps two LongInt values}
+procedure SwapValues(var A, B: LongInt); overload;
+{ Swaps two Single values}
+procedure SwapValues(var A, B: Single); overload;
+{ Swaps two LongInt values if necessary to ensure that Min <= Max.}
+procedure SwapMin(var Min, Max: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ This function returns True if running on little endian machine.}
+function IsLittleEndian: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Swaps byte order of Word value.}
+function SwapEndianWord(Value: Word): Word; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Swaps byte order of multiple Word values.}
+procedure SwapEndianWord(P: PWordArray; Count: LongInt); overload;
+{ Swaps byte order of LongWord value.}
+function SwapEndianLongWord(Value: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Swaps byte order of multiple LongWord values.}
+procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); overload;
+
+{ Calculates CRC32 for the given data.}
+procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt);
+{ Fills given memory with given Byte value. Size is size of buffer in bytes.}
+procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte);
+{ Fills given memory with given Word value. Size is size of buffer in bytes.}
+procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word);
+{ Fills given memory with given LongWord value. Size is size of buffer in bytes.}
+procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord);
+{ Fills given memory zeroes.}
+{$EXTERNALSYM ZeroMemory} // Conflicts with WinAPI ZeroMemory in C++ Builder
+procedure ZeroMemory(Data: Pointer; Size: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
+
+{ Returns how many mipmap levels can be created for image of given size.}
+function GetNumMipMapLevels(Width, Height: LongInt): LongInt;
+{ Returns total number of levels of volume texture with given depth and
+  mipmap count (this is not depth * mipmaps!).}
+function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt;
+{ Returns rectangle (X, Y, X + Width, Y + Height).}
+function BoundsToRect(X, Y, Width, Height: LongInt): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns rectangle (R.Left, R.Top, R.Left + R.Right, R.Top + R.Bottom).}
+function BoundsToRect(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Returns rectangle (R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top).}
+function RectToBounds(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF}
+{ Clips given bounds to Clip rectangle.}
+procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect);
+{ Clips given source bounds and dest position. It is used by various CopyRect
+  functions that copy rect from one image to another. It handles clipping the same way
+  as Win32 BitBlt function. }
+procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt;
+  SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
+{ Clips given source bounds and dest bounds. It is used by various StretchRect
+  functions that stretch rectangle of pixels from one image to another.
+  It handles clipping the same way as Win32 StretchBlt function. }
+procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY,
+  DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
+{ Scales one rectangle to fit into another. Proportions are preserved so
+  it could be used for 'Stretch To Fit Window' image drawing for instance.}
+function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect;
+{ Scales given size to fit into max size while keeping the original ascpect ration.
+  Useful for calculating thumbnail dimensions etc.}
+function ScaleSizeToFit(const CurrentSize, MaxSize: TSize): TSize;
+{ Returns width of given rect. Part of RTL in newer Delphi.}
+function RectWidth(const Rect: TRect): Integer;
+{ Returns height of given rect. Part of RTL in newer Delphi.}
+function RectHeight(const Rect: TRect): Integer;
+{ Returns True if R1 fits into R2.}
+function RectInRect(const R1, R2: TRect): Boolean;
+{ Returns True if R1 and R2 intersects.}
+function RectIntersects(const R1, R2: TRect): Boolean;
+
+{ Converts pixel size in micrometers to corrensponding DPI.}
+function PixelSizeToDpi(SizeInMicroMeters: Single): Single;
+{ Converts DPI to corrensponding pixel size in micrometers.}
+function DpiToPixelSize(Dpi: Single): Single;
+
+function FloatRect(ALeft, ATop, ARight, ABottom: Single): TFloatRect;
+function FloatRectWidth(const R: TFloatRect): Single;
+function FloatRectHeight(const R: TFloatRect): Single;
+
+{ Formats given message for usage in Exception.Create(..). Use only
+  in except block - returned message contains message of last raised exception.}
+function FormatExceptMsg(const Msg: string; const Args: array of const): string;
+{ Outputs debug message - shows message dialog in Windows and writes to console
+  in Linux/Unix.}
+procedure DebugMsg(const Msg: string; const Args: array of const);
+
+implementation
+
+uses
+{$IF Defined(MSWINDOWS)}
+  Windows;
+{$ELSEIF Defined(FPC)}
+  Dos, BaseUnix, Unix;
+{$ELSEIF Defined(DELPHI)}
+  Posix.SysTime;
+{$IFEND}
+
+var
+  FloatFormatSettings: TFormatSettings;
+
+constructor ENotImplemented.Create;
+begin
+  inherited Create('Not implemented');
+end;
+
+procedure FreeAndNil(var Obj);
+var
+  Temp: TObject;
+begin
+  Temp := TObject(Obj);
+  Pointer(Obj) := nil;
+  Temp.Free;
+end;
+
+procedure FreeMemNil(var P);
+begin
+  FreeMem(Pointer(P));
+  Pointer(P) := nil;
+end;
+
+procedure FreeMem(P: Pointer);
+begin
+  if P <> nil then
+    System.FreeMem(P);
+end;
+
+function GetExceptObject: Exception;
+begin
+  Result := Exception(ExceptObject);
+end;
+
+{$IF Defined(MSWINDOWS)}
+var
+  PerfFrequency: Int64;
+  InvPerfFrequency: Single;
+
+function GetTimeMicroseconds: Int64;
+var
+  Time: Int64;
+begin
+  QueryPerformanceCounter(Time);
+  Result := Round(1000000 * InvPerfFrequency * Time);
+end;
+{$ELSEIF Defined(DELPHI)}
+function GetTimeMicroseconds: Int64;
+var
+  Time: TimeVal;
+begin
+  Posix.SysTime.GetTimeOfDay(Time, nil);
+  Result := Int64(Time.tv_sec) * 1000000 + Time.tv_usec;
+end;
+{$ELSEIF Defined(FPC)}
+function GetTimeMicroseconds: Int64;
+var
+  TimeVal: TTimeVal;
+begin
+  fpGetTimeOfDay(@TimeVal, nil);
+  Result := Int64(TimeVal.tv_sec) * 1000000 + TimeVal.tv_usec;
+end;
+{$IFEND}
+
+function GetTimeMilliseconds: Int64;
+begin
+  Result := GetTimeMicroseconds div 1000;
+end;
+
+function GetFileExt(const FileName: string): string;
+begin
+  Result := ExtractFileExt(FileName);
+  if Length(Result) > 1 then
+    Delete(Result, 1, 1);
+end;
+
+function GetAppExe: string;
+{$IF Defined(MSWINDOWS)}
+var
+  FileName: array[0..MAX_PATH] of Char;
+begin
+  SetString(Result, FileName,
+    Windows.GetModuleFileName(MainInstance, FileName, SizeOf(FileName)));
+{$ELSEIF Defined(DELPHI)} // Delphi non Win targets
+var
+  FileName: array[0..1024] of Char;
+begin
+  SetString(Result, FileName,
+    System.GetModuleFileName(MainInstance, FileName, SizeOf(FileName)));
+{$ELSE}
+begin
+  Result := ParamStr(0);
+{$IFEND}
+end;
+
+function GetAppDir: string;
+begin
+  Result := ExtractFileDir(GetAppExe);
+end;
+
+function GetFileName(const FileName: string): string;
+var
+  I: Integer;
+begin
+  I := LastDelimiter('\/' + DriveDelim, FileName);
+  Result := Copy(FileName, I + 1, MaxInt);
+end;
+
+function GetFileDir(const FileName: string): string;
+const
+  Delims = '\/' + DriveDelim;
+var
+  I: Integer;
+begin
+  I := LastDelimiter(Delims, Filename);
+  if (I > 1) and
+    ((FileName[I] = Delims[1]) or (FileName[I] = Delims[2])) and
+    (not IsDelimiter(Delims, FileName, I - 1)) then Dec(I);
+  Result := Copy(FileName, 1, I);
+end;
+
+function StrMaskMatch(const Subject, Mask: string; CaseSensitive: Boolean): Boolean;
+var
+  MaskLen, KeyLen : LongInt;
+
+  function CharMatch(A, B: Char): Boolean;
+  begin
+    if CaseSensitive then
+      Result := A = B
+    else
+      Result := AnsiUpperCase (A) = AnsiUpperCase (B);
+  end;
+
+  function MatchAt(MaskPos, KeyPos: LongInt): Boolean;
+  begin
+    while (MaskPos <= MaskLen) and (KeyPos <= KeyLen) do
+    begin
+      case Mask[MaskPos] of
+        '?' :
+          begin
+            Inc(MaskPos);
+            Inc(KeyPos);
+          end;
+        '*' :
+          begin
+            while (MaskPos <= MaskLen) and (Mask[MaskPos] = '*') do
+              Inc(MaskPos);
+            if MaskPos > MaskLen then
+            begin
+              Result := True;
+              Exit;
+            end;
+            repeat
+              if MatchAt(MaskPos, KeyPos) then
+              begin
+                Result := True;
+                Exit;
+              end;
+              Inc(KeyPos);
+            until KeyPos > KeyLen;
+            Result := False;
+            Exit;
+          end;
+        else
+          if not CharMatch(Mask[MaskPos], Subject[KeyPos]) then
+          begin
+            Result := False;
+            Exit;
+          end
+          else
+          begin
+            Inc(MaskPos);
+            Inc(KeyPos);
+          end;
+      end;
+    end;
+
+    while (MaskPos <= MaskLen) and (AnsiChar(Mask[MaskPos]) in ['?', '*']) do
+      Inc(MaskPos);
+    if (MaskPos <= MaskLen) or (KeyPos <= KeyLen) then
+    begin
+      Result := False;
+      Exit;
+    end;
+
+    Result := True;
+  end;
+
+begin
+  MaskLen := Length(Mask);
+  KeyLen := Length(Subject);
+  if MaskLen = 0 then
+  begin
+    Result := True;
+    Exit;
+  end;
+  Result := MatchAt(1, 1);
+end;
+
+function BuildFileList(Path: string; Attr: LongInt;
+  Files: TStrings; Options: TFileListOptions): Boolean;
+var
+  FileMask: string;
+  RootDir: string;
+  Folders: TStringList;
+  CurrentItem: LongInt;
+  Counter: LongInt;
+  LocAttr: LongInt;
+
+  procedure BuildFolderList;
+  var
+    FindInfo: TSearchRec;
+    Rslt: LongInt;
+  begin
+    Counter := Folders.Count - 1;
+    CurrentItem := 0;
+    while CurrentItem <= Counter do
+    begin
+      // Searching for subfolders
+      Rslt := SysUtils.FindFirst(Folders[CurrentItem] + '*', faDirectory, FindInfo);
+      try
+        while Rslt = 0 do
+        begin
+          if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') and
+            (FindInfo.Attr and faDirectory = faDirectory) then
+            Folders.Add(Folders[CurrentItem] + FindInfo.Name + PathDelim);
+          Rslt := SysUtils.FindNext(FindInfo);
+        end;
+      finally
+        SysUtils.FindClose(FindInfo);
+      end;
+      Counter := Folders.Count - 1;
+      Inc(CurrentItem);
+    end;
+  end;
+
+  procedure FillFileList(CurrentCounter: LongInt);
+  var
+    FindInfo: TSearchRec;
+    Res: LongInt;
+    CurrentFolder: string;
+  begin
+    CurrentFolder := Folders[CurrentCounter];
+    Res := SysUtils.FindFirst(CurrentFolder + FileMask, LocAttr, FindInfo);
+    if flRelNames in Options then
+      CurrentFolder := ExtractRelativePath(RootDir, CurrentFolder);
+    try
+      while Res = 0 do
+      begin
+        if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') then
+        begin
+          if (flFullNames in Options) or (flRelNames in Options) then
+            Files.Add(CurrentFolder + FindInfo.Name)
+          else
+            Files.Add(FindInfo.Name);
+        end;
+        Res := SysUtils.FindNext(FindInfo);
+      end;
+    finally
+      SysUtils.FindClose(FindInfo);
+    end;
+  end;
+
+begin
+  FileMask := ExtractFileName(Path);
+  RootDir := ExtractFilePath(Path);
+  Folders := TStringList.Create;
+  Folders.Add(RootDir);
+  Files.Clear;
+{$IFDEF DCC}
+  {$WARN SYMBOL_PLATFORM OFF}
+{$ENDIF}
+  if Attr = faAnyFile then
+    LocAttr := faSysFile or faHidden or faArchive or faReadOnly
+  else
+    LocAttr := Attr;
+{$IFDEF DCC}
+  {$WARN SYMBOL_PLATFORM ON}
+{$ENDIF}
+  // Here's the recursive search for nested folders
+  if flRecursive in Options then
+    BuildFolderList;
+  if Attr <> faDirectory then
+    for Counter := 0 to Folders.Count - 1 do
+      FillFileList(Counter)
+  else
+    Files.AddStrings(Folders);
+  Folders.Free;
+  Result := True;
+end;
+
+function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt;
+var
+  I, X: LongInt;
+  Len, LenSubStr: LongInt;
+begin
+  I := Offset;
+  LenSubStr := Length(SubStr);
+  Len := Length(S) - LenSubStr + 1;
+  while I <= Len do
+  begin
+    if S[I] = SubStr[1] then
+    begin
+      X := 1;
+      while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do
+        Inc(X);
+      if (X = LenSubStr) then
+      begin
+        Result := I;
+        Exit;
+      end;
+    end;
+    Inc(I);
+  end;
+  Result := 0;
+end;
+
+function PosNoCase(const SubStr, S: string; Offset: LongInt): LongInt;
+begin
+  Result := PosEx(AnsiLowerCase(SubStr), AnsiLowerCase(S), Offset);
+end;
+
+function StrToken(var S: string; Sep: Char): string;
+var
+  I: LongInt;
+begin
+  I := Pos(Sep, S);
+  if I <> 0 then
+  begin
+    Result := Copy(S, 1, I - 1);
+    Delete(S, 1, I);
+  end
+  else
+  begin
+    Result := S;
+    S := '';
+  end;
+end;
+
+function StrTokenEnd(var S: string; Sep: Char): string;
+var
+  I, J: LongInt;
+begin
+  J := 0;
+  I := Pos(Sep, S);
+  while I <> 0 do
+  begin
+    J := I;
+    I := PosEx(Sep, S, J + 1);
+  end;
+  if J <> 0 then
+  begin
+    Result := Copy(S, J + 1, MaxInt);
+    Delete(S, J, MaxInt);
+  end
+  else
+  begin
+    Result := S;
+    S := '';
+  end;
+end;
+
+procedure StrTokensToList(const S: string; Sep: Char; Tokens: TStrings);
+var
+  Token, Str: string;
+begin
+  Tokens.Clear;
+  Str := S;
+  while Str <> '' do
+  begin
+    Token := StrToken(Str, Sep);
+    Tokens.Add(Token);
+  end;
+end;
+
+function IntToStrFmt(const I: Int64): string;
+begin
+  Result := Format('%.0n', [I * 1.0]);
+end;
+
+function FloatToStrFmt(const F: Double; Precision: Integer): string;
+begin
+  Result := Format('%.' + IntToStr(Precision) + 'n', [F]);
+end;
+
+function GetFormatSettingsForFloats: TFormatSettings;
+begin
+  Result := FloatFormatSettings;
+end;
+
+function ContainsAnySubStr(const S: string; const SubStrs: array of string): Boolean;
+var
+  I: Integer;
+begin
+  Result := False;
+  for I := 0 to High(SubStrs) do
+  begin
+    Result := Pos(SubStrs[I], S) > 0;
+    if Result then
+      Exit;
+  end;
+end;
+
+function SubString(const S: string; IdxStart, IdxEnd: Integer): string;
+begin
+  Result := Copy(S, IdxStart, IdxEnd - IdxStart);
+end;
+
+function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt;
+begin
+  Result := Number;
+  if Result < Min then
+    Result := Min
+  else if Result > Max then
+    Result := Max;
+end;
+
+function ClampFloat(Number: Single; Min, Max: Single): Single;
+begin
+  Result := Number;
+  if Result < Min then
+    Result := Min
+  else if Result > Max then
+    Result := Max;
+end;
+
+function ClampToByte(Value: LongInt): LongInt;
+begin
+  Result := Value;
+  if Result > 255 then
+    Result := 255
+  else if Result < 0 then
+    Result := 0;
+end;
+
+function ClampToWord(Value: LongInt): LongInt;
+begin
+  Result := Value;
+  if Result > 65535 then
+    Result := 65535
+  else if Result < 0 then
+    Result := 0;
+end;
+
+function IsPow2(Num: LongInt): Boolean;
+begin
+  Result := (Num and -Num) = Num;
+end;
+
+function NextPow2(Num: LongInt): LongInt;
+begin
+  Result := Num and -Num;
+  while Result < Num do
+    Result := Result shl 1;
+end;
+
+function Pow2Int(Exponent: LongInt): LongInt;
+begin
+  Result := 1 shl Exponent;
+end;
+
+function Power(const Base, Exponent: Single): Single;
+begin
+  if Exponent = 0.0 then
+    Result := 1.0
+  else if (Base = 0.0) and (Exponent > 0.0) then
+    Result := 0.0
+  else
+    Result := Exp(Exponent * Ln(Base));
+end;
+
+function Log2Int(X: LongInt): LongInt;
+begin
+  case X of
+    1: Result := 0;
+    2: Result := 1;
+    4: Result := 2;
+    8: Result := 3;
+    16: Result := 4;
+    32: Result := 5;
+    64: Result := 6;
+    128: Result := 7;
+    256: Result := 8;
+    512: Result := 9;
+    1024: Result := 10;
+    2048: Result := 11;
+    4096: Result := 12;
+    8192: Result := 13;
+    16384: Result := 14;
+    32768: Result := 15;
+    65536: Result := 16;
+    131072: Result := 17;
+    262144: Result := 18;
+    524288: Result := 19;
+    1048576: Result := 20;
+    2097152: Result := 21;
+    4194304: Result := 22;
+    8388608: Result := 23;
+    16777216: Result := 24;
+    33554432: Result := 25;
+    67108864: Result := 26;
+    134217728: Result := 27;
+    268435456: Result := 28;
+    536870912: Result := 29;
+    1073741824: Result := 30;
+  else
+    Result := -1;
+  end;
+end;
+
+function Log2(X: Single): Single;
+{$IFDEF USE_ASM}
+asm
+  FLD1
+  FLD     X
+  FYL2X
+  FWAIT
+end;
+{$ELSE}
+const
+  Ln2: Single = 0.6931471;
+begin
+  Result := Ln(X) / Ln2;
+end;
+{$ENDIF}
+
+function Log10(X: Single): Single;
+{$IFDEF USE_ASM}
+asm
+  FLDLG2
+  FLD     X
+  FYL2X
+  FWAIT
+end;
+{$ELSE}
+const
+  Ln10: Single = 2.30258509299405;
+begin
+  Result := Ln(X) / Ln10;
+end;
+{$ENDIF}
+
+function Floor(Value: Single): LongInt;
+begin
+  Result := Trunc(Value);
+  if Frac(Value) < 0.0 then
+    Dec(Result);
+end;
+
+function Ceil(Value: Single): LongInt;
+begin
+  Result := Trunc(Value);
+  if Frac(Value) > 0.0 then
+    Inc(Result);
+end;
+
+procedure Switch(var Value: Boolean);
+begin
+  Value := not Value;
+end;
+
+function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+function Iff(Condition, TruePart, FalsePart: Boolean): Boolean;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+function Iff(Condition: Boolean; const TruePart, FalsePart: string): string;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single;
+begin
+  if Condition then
+    Result := TruePart
+  else
+    Result := FalsePart;
+end;
+
+procedure SwapValues(var A, B: Boolean);
+var
+  Tmp: Boolean;
+begin
+  Tmp := A;
+  A := B;
+  B := Tmp;
+end;
+
+procedure SwapValues(var A, B: Byte);
+var
+  Tmp: Byte;
+begin
+  Tmp := A;
+  A := B;
+  B := Tmp;
+end;
+
+procedure SwapValues(var A, B: Word);
+var
+  Tmp: Word;
+begin
+  Tmp := A;
+  A := B;
+  B := Tmp;
+end;
+
+procedure SwapValues(var A, B: LongInt);
+var
+  Tmp: LongInt;
+begin
+  Tmp := A;
+  A := B;
+  B := Tmp;
+end;
+
+procedure SwapValues(var A, B: Single);
+var
+  Tmp: Single;
+begin
+  Tmp := A;
+  A := B;
+  B := Tmp;
+end;
+
+procedure SwapMin(var Min, Max: LongInt);
+var
+  Tmp: LongInt;
+begin
+  if Min > Max then
+  begin
+    Tmp := Min;
+    Min := Max;
+    Max := Tmp;
+  end;
+end;
+
+function Min(A, B: LongInt): LongInt;
+begin
+  if A < B then
+    Result := A
+  else
+    Result := B;
+end;
+
+function MinFloat(A, B: Single): Single;
+begin
+  if A < B then
+    Result := A
+  else
+    Result := B;
+end;
+
+function Max(A, B: LongInt): LongInt;
+begin
+  if A > B then
+    Result := A
+  else
+    Result := B;
+end;
+
+function MaxFloat(A, B: Single): Single;
+begin
+  if A > B then
+    Result := A
+  else
+    Result := B;
+end;
+
+function MulDiv(Number, Numerator, Denominator: Word): Word;
+{$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
+asm
+         MUL DX
+         DIV CX
+end;
+{$ELSE}
+begin
+  Result := Number * Numerator div Denominator;
+end;
+{$IFEND}
+
+function IsLittleEndian: Boolean;
+var
+  W: Word;
+begin
+  W := $00FF;
+  Result := PByte(@W)^ = $FF;
+end;
+
+function SwapEndianWord(Value: Word): Word;
+{$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
+asm
+  XCHG   AH, AL
+end;
+{$ELSE}
+begin
+  TWordRec(Result).Low := TWordRec(Value).High;
+  TWordRec(Result).High := TWordRec(Value).Low;
+end;
+{$IFEND}
+
+procedure SwapEndianWord(P: PWordArray; Count: LongInt);
+{$IFDEF USE_ASM}
+asm
+@Loop:
+  MOV    CX, [EAX]
+  XCHG   CH, CL
+  MOV    [EAX], CX
+  ADD    EAX, 2
+  DEC    EDX
+  JNZ    @Loop
+end;
+{$ELSE}
+var
+  I: LongInt;
+  Temp: Word;
+begin
+  for I := 0 to Count - 1 do
+  begin
+    Temp := P[I];
+    TWordRec(P[I]).Low := TWordRec(Temp).High;
+    TWordRec(P[I]).High := TWordRec(Temp).Low;
+  end;
+end;
+{$ENDIF}
+
+function SwapEndianLongWord(Value: LongWord): LongWord;
+{$IF Defined(USE_ASM) and (not Defined(USE_INLINE))}
+asm
+  BSWAP   EAX
+end;
+{$ELSE}
+begin
+  TLongWordRec(Result).Bytes[0] := TLongWordRec(Value).Bytes[3];
+  TLongWordRec(Result).Bytes[1] := TLongWordRec(Value).Bytes[2];
+  TLongWordRec(Result).Bytes[2] := TLongWordRec(Value).Bytes[1];
+  TLongWordRec(Result).Bytes[3] := TLongWordRec(Value).Bytes[0];
+end;
+{$IFEND}
+
+procedure SwapEndianLongWord(P: PLongWord; Count: LongInt);
+{$IFDEF USE_ASM}
+asm
+@Loop:
+  MOV    ECX, [EAX]
+  BSWAP  ECX
+  MOV    [EAX], ECX
+  ADD    EAX, 4
+  DEC    EDX
+  JNZ    @Loop
+end;
+{$ELSE}
+var
+  I: LongInt;
+  Temp: LongWord;
+begin
+  for I := 0 to Count - 1 do
+  begin
+    Temp := PLongWordArray(P)[I];
+    TLongWordRec(PLongWordArray(P)[I]).Bytes[0] := TLongWordRec(Temp).Bytes[3];
+    TLongWordRec(PLongWordArray(P)[I]).Bytes[1] := TLongWordRec(Temp).Bytes[2];
+    TLongWordRec(PLongWordArray(P)[I]).Bytes[2] := TLongWordRec(Temp).Bytes[1];
+    TLongWordRec(PLongWordArray(P)[I]).Bytes[3] := TLongWordRec(Temp).Bytes[0];
+  end;
+end;
+{$ENDIF}
+
+type
+  TCrcTable = array[Byte] of LongWord;
+var
+  CrcTable: TCrcTable;
+
+procedure InitCrcTable;
+const
+  Polynom = $EDB88320;
+var
+  I, J: LongInt;
+  C: LongWord;
+begin
+  for I := 0 to 255 do
+  begin
+    C := I;
+    for J := 0 to 7 do
+    begin
+      if (C and $01) <> 0 then
+        C := Polynom xor (C shr 1)
+      else
+        C := C shr 1;
+    end;
+    CrcTable[I] := C;
+  end;
+end;
+
+procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt);
+var
+  I: LongInt;
+  B: PByte;
+begin
+  B := Data;
+  for I := 0 to Size - 1 do
+  begin
+    Crc := (Crc shr 8) xor CrcTable[B^ xor Byte(Crc)];
+    Inc(B);
+  end
+end;
+
+procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte);
+{$IFDEF USE_ASM}
+asm
+  PUSH   EDI
+  MOV    EDI, EAX
+  MOV    EAX, ECX
+  MOV    AH, AL
+  MOV    CX, AX
+  SHL    EAX, 16
+  MOV    AX, CX
+  MOV    ECX, EDX
+  SAR    ECX, 2
+  JS     @Exit
+  REP    STOSD
+  MOV    ECX, EDX
+  AND    ECX, 3
+  REP    STOSB
+  POP    EDI
+@Exit:
+end;
+{$ELSE}
+begin
+  FillChar(Data^, Size, Value);
+end;
+{$ENDIF}
+
+procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word);
+{$IFDEF USE_ASM}
+asm
+  PUSH   EDI
+  PUSH   EBX
+  MOV    EBX, EDX
+  MOV    EDI, EAX
+  MOV    EAX, ECX
+  MOV    CX, AX
+  SHL    EAX, 16
+  MOV    AX, CX
+  MOV    ECX, EDX
+  SHR    ECX, 2
+  JZ     @Word
+  REP    STOSD
+@Word:
+  MOV    ECX, EBX
+  AND    ECX, 2
+  JZ     @Byte
+  MOV    [EDI], AX
+  ADD    EDI, 2
+@Byte:
+  MOV    ECX, EBX
+  AND    ECX, 1
+  JZ     @Exit
+  MOV    [EDI], AL
+@Exit:
+  POP    EBX
+  POP    EDI
+end;
+{$ELSE}
+var
+  I, V: LongWord;
+begin
+  V := Value * $10000 + Value;
+  for I := 0 to Size div 4 - 1 do
+    PLongWordArray(Data)[I] := V;
+  case Size mod 4 of
+    1: PByteArray(Data)[Size - 1] := Lo(Value);
+    2: PWordArray(Data)[Size div 2] := Value;
+    3:
+      begin
+        PWordArray(Data)[Size  div 2 - 1] := Value;
+        PByteArray(Data)[Size - 1] := Lo(Value);
+      end;
+  end;
+end;
+{$ENDIF}
+
+procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord);
+{$IFDEF USE_ASM}
+asm
+  PUSH   EDI
+  PUSH   EBX
+  MOV    EBX, EDX
+  MOV    EDI, EAX
+  MOV    EAX, ECX
+  MOV    ECX, EDX
+  SHR    ECX, 2
+  JZ     @Word
+  REP    STOSD
+@Word:
+  MOV    ECX, EBX
+  AND    ECX, 2
+  JZ     @Byte
+  MOV    [EDI], AX
+  ADD    EDI, 2
+@Byte:
+  MOV    ECX, EBX
+  AND    ECX, 1
+  JZ     @Exit
+  MOV    [EDI], AL
+@Exit:
+  POP    EBX
+  POP    EDI
+end;
+{$ELSE}
+var
+  I: LongInt;
+begin
+  for I := 0 to Size div 4 - 1 do
+    PLongWordArray(Data)[I] := Value;
+  case Size mod 4 of
+    1: PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0];
+    2: PWordArray(Data)[Size div 2] := TLongWordRec(Value).Words[0];
+    3:
+      begin
+        PWordArray(Data)[Size div 2 - 1] := TLongWordRec(Value).Words[0];
+        PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0];
+      end;
+  end;
+end;
+{$ENDIF}
+
+procedure ZeroMemory(Data: Pointer; Size: Integer);
+begin
+  FillMemoryByte(Data, Size, 0);
+end;
+
+function GetNumMipMapLevels(Width, Height: LongInt): LongInt;
+begin
+  Result := 0;
+  if (Width > 0) and (Height > 0) then
+  begin
+    Result := 1;
+    while (Width <> 1) or (Height <> 1) do
+    begin
+      Width := Width div 2;
+      Height := Height div 2;
+      if Width < 1 then Width := 1;
+      if Height < 1 then Height := 1;
+      Inc(Result);
+    end;
+  end;
+end;
+
+function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt;
+var
+  I: LongInt;
+begin
+  Result := Depth;
+  for I := 1 to MipMaps - 1 do
+    Inc(Result, ClampInt(Depth shr I, 1, Depth));
+end;
+
+function BoundsToRect(X, Y, Width, Height: LongInt): TRect;
+begin
+  Result.Left := X;
+  Result.Top := Y;
+  Result.Right := X + Width;
+  Result.Bottom := Y + Height;
+end;
+
+function BoundsToRect(const R: TRect): TRect;
+begin
+  Result.Left := R.Left;
+  Result.Top := R.Top;
+  Result.Right := R.Left + R.Right;
+  Result.Bottom := R.Top + R.Bottom;
+end;
+
+function RectToBounds(const R: TRect): TRect;
+begin
+  Result.Left := R.Left;
+  Result.Top := R.Top;
+  Result.Right := R.Right - R.Left;
+  Result.Bottom := R.Bottom - R.Top;
+end;
+
+procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect);
+
+  procedure ClipDim(var AStart, ALength: LongInt; ClipMin, ClipMax: LongInt);
+  begin
+    if AStart < ClipMin then
+    begin
+      ALength := ALength - (ClipMin - AStart);
+      AStart := ClipMin;
+    end;
+    if AStart + ALength > ClipMax then ALength := Max(0, ClipMax - AStart);
+  end;
+
+begin
+  ClipDim(X, Width, Clip.Left, Clip.Right);
+  ClipDim(Y, Height, Clip.Top, Clip.Bottom);
+end;
+
+procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
+
+  procedure ClipDim(var SrcPos, DstPos, Size: LongInt; SrcClipMax,
+    DstClipMin, DstClipMax: LongInt);
+  var
+    OldDstPos: LongInt;
+    Diff: LongInt;
+  begin
+    OldDstPos := Iff(DstPos < 0, DstPos, 0);
+    if DstPos < DstClipMin then
+    begin
+      Diff := DstClipMin - DstPos;
+      Size := Size - Diff;
+      SrcPos := SrcPos + Diff;
+      DstPos := DstClipMin;
+    end;
+    if SrcPos < 0 then
+    begin
+      Size := Size + SrcPos - OldDstPos;
+      DstPos := DstPos - SrcPos + OldDstPos;
+      SrcPos := 0;
+    end;
+    if SrcPos + Size > SrcClipMax then Size := SrcClipMax - SrcPos;
+    if DstPos + Size > DstClipMax then Size := DstClipMax - DstPos;
+  end;
+
+begin
+  ClipDim(SrcX, DstX, Width, SrcImageWidth, DstClip.Left, DstClip.Right);
+  ClipDim(SrcY, DstY, Height, SrcImageHeight, DstClip.Top, DstClip.Bottom);
+end;
+
+procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY,
+  DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect);
+
+  procedure ClipDim(var SrcPos, DstPos, SrcSize, DstSize: LongInt; SrcClipMax,
+    DstClipMin, DstClipMax: LongInt);
+  var
+    OldSize: LongInt;
+    Diff: LongInt;
+    Scale: Single;
+  begin
+    Scale := DstSize / SrcSize;
+    if DstPos < DstClipMin then
+    begin
+      Diff := DstClipMin - DstPos;
+      DstSize := DstSize - Diff;
+      SrcPos := SrcPos + Round(Diff / Scale);
+      SrcSize := SrcSize - Round(Diff / Scale);
+      DstPos := DstClipMin;
+    end;
+    if SrcPos < 0 then
+    begin
+      SrcSize := SrcSize + SrcPos;
+      DstPos := DstPos - Round(SrcPos * Scale);
+      DstSize := DstSize + Round(SrcPos * Scale);
+      SrcPos := 0;
+    end;
+    if SrcPos + SrcSize > SrcClipMax then
+    begin
+      OldSize := SrcSize;
+      SrcSize := SrcClipMax - SrcPos;
+      DstSize := Round(DstSize * (SrcSize / OldSize));
+    end;
+    if DstPos + DstSize > DstClipMax then
+    begin
+      OldSize := DstSize;
+      DstSize := DstClipMax - DstPos;
+      SrcSize := Round(SrcSize * (DstSize / OldSize));
+    end;
+  end;
+
+begin
+  ClipDim(SrcX, DstX, SrcWidth, DstWidth, SrcImageWidth, DstClip.Left, DstClip.Right);
+  ClipDim(SrcY, DstY, SrcHeight, DstHeight, SrcImageHeight, DstClip.Top, DstClip.Bottom);
+end;
+
+function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect;
+var
+  SourceWidth: LongInt;
+  SourceHeight: LongInt;
+  TargetWidth: LongInt;
+  TargetHeight: LongInt;
+  ScaledWidth: LongInt;
+  ScaledHeight: LongInt;
+begin
+  SourceWidth := SourceRect.Right - SourceRect.Left;
+  SourceHeight := SourceRect.Bottom - SourceRect.Top;
+  TargetWidth := TargetRect.Right - TargetRect.Left;
+  TargetHeight := TargetRect.Bottom - TargetRect.Top;
+
+  if SourceWidth * TargetHeight < SourceHeight * TargetWidth then
+  begin
+    ScaledWidth := (SourceWidth * TargetHeight) div SourceHeight;
+    Result := BoundsToRect(TargetRect.Left + ((TargetWidth - ScaledWidth) div 2),
+      TargetRect.Top, ScaledWidth, TargetHeight);
+  end
+  else
+  begin
+    ScaledHeight := (SourceHeight * TargetWidth) div SourceWidth;
+    Result := BoundsToRect(TargetRect.Left, TargetRect.Top + ((TargetHeight - ScaledHeight) div 2),
+      TargetWidth, ScaledHeight);
+  end;
+end;
+
+function ScaleSizeToFit(const CurrentSize, MaxSize: Types.TSize): Types.TSize;
+var
+  SR, TR, ScaledRect: TRect;
+begin
+  SR := Types.Rect(0, 0, CurrentSize.CX, CurrentSize.CY);
+  TR := Types.Rect(0, 0, MaxSize.CX, MaxSize.CY);
+  ScaledRect := ScaleRectToRect(SR, TR);
+  Result.CX := ScaledRect.Right - ScaledRect.Left;
+  Result.CY := ScaledRect.Bottom - ScaledRect.Top;
+end;
+
+function RectWidth(const Rect: TRect): Integer;
+begin
+  Result := Rect.Right - Rect.Left;
+end;
+
+function RectHeight(const Rect: TRect): Integer;
+begin
+  Result := Rect.Bottom - Rect.Top;
+end;
+
+function RectInRect(const R1, R2: TRect): Boolean;
+begin
+  Result:=
+    (R1.Left >= R2.Left) and
+    (R1.Top >= R2.Top) and
+    (R1.Right <= R2.Right) and
+    (R1.Bottom <= R2.Bottom);
+end;
+
+function RectIntersects(const R1, R2: TRect): Boolean;
+begin
+  Result :=
+    not (R1.Left > R2.Right) and
+    not (R1.Top > R2.Bottom) and
+    not (R1.Right < R2.Left) and
+    not (R1.Bottom < R2.Top);
+end;
+
+function PixelSizeToDpi(SizeInMicroMeters: Single): Single;
+begin
+  Result := 25400 / SizeInMicroMeters;
+end;
+
+function DpiToPixelSize(Dpi: Single): Single;
+begin
+  Result := 1e03 / (Dpi / 25.4);
+end;
+
+function FloatRect(ALeft, ATop, ARight, ABottom: Single): TFloatRect;
+begin
+  with Result do
+  begin
+    Left := ALeft;
+    Top := ATop;
+    Right := ARight;
+    Bottom := ABottom;
+  end;
+end;
+
+function FloatRectWidth(const R: TFloatRect): Single;
+begin
+  Result := R.Right - R.Left;
+end;
+
+function FloatRectHeight(const R: TFloatRect): Single;
+begin
+  Result := R.Bottom - R.Top;
+end;
+
+function FormatExceptMsg(const Msg: string; const Args: array of const): string;
+begin
+  Result := Format(Msg + SLineBreak + 'Message: ' + GetExceptObject.Message, Args);
+end;
+
+procedure DebugMsg(const Msg: string; const Args: array of const);
+var
+  FmtMsg: string;
+begin
+  FmtMsg := Format(Msg, Args);
+{$IFDEF MSWINDOWS}
+  if IsConsole then
+    WriteLn('DebugMsg: ' + FmtMsg)
+  else
+    MessageBox(GetActiveWindow, PChar(FmtMsg), 'DebugMsg', MB_OK);
+{$ENDIF}
+{$IFDEF UNIX}
+  WriteLn('DebugMsg: ' + FmtMsg);
+{$ENDIF}
+{$IFDEF MSDOS}
+  WriteLn('DebugMsg: ' + FmtMsg);
+{$ENDIF}
+end;
+
+initialization
+  InitCrcTable;
+{$IFDEF MSWINDOWS}
+  QueryPerformanceFrequency(PerfFrequency);
+  InvPerfFrequency := 1.0 / PerfFrequency;
+{$ENDIF}
+
+{$IF Defined(DELPHI)}
+  {$IF CompilerVersion >= 23}
+  FloatFormatSettings := TFormatSettings.Create('en-US');
+  {$ELSE}
+  GetLocaleFormatSettings(1033, FloatFormatSettings);
+  {$IFEND}
+{$ELSE FPC}
+  FloatFormatSettings := DefaultFormatSettings;
+  FloatFormatSettings.DecimalSeparator := '.';
+{$IFEND}
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+    - nothing now
+
+  -- 0.77.1 ----------------------------------------------------
+    - Added GetFileName, GetFileDir, RectWidth, RectHeight function.
+    - Added ScaleSizeToFit function.
+    - Added ZeroMemory and SwapValues for Booleans.
+    - Added Substring function.
+    - Renamed MatchFileNameMask to StrMaskMatch (it's for general use not
+      just filenames).
+    - Delphi XE2 new targets (Win64, OSX32) compatibility changes.
+    - Added GetFormatSettingsForFloats function.
+
+  -- 0.26.5 Changes/Bug Fixes -----------------------------------
+    - Added Log10 function.
+    - Added TFloatRect type and helper functions FloatRect, FloatRectWidth,
+      FloatRectHeight.
+    - Added string function ContainsAnySubStr.
+    - Added functions PixelSizeToDpi, DpiToPixelSize.
+
+  -- 0.26.1 Changes/Bug Fixes -----------------------------------
+    - Some formatting changes.
+    - Changed some string functions to work with localized strings.
+    - ASM version of PosEx had bugs, removed it.
+    - Added StrTokensToList function.
+
+  -- 0.25.0 Changes/Bug Fixes -----------------------------------
+    - Fixed error in ClipCopyBounds which was causing ... bad clipping!
+
+  -- 0.24.3 Changes/Bug Fixes -----------------------------------
+    - Added GetTimeMilliseconds function.
+    - Added IntToStrFmt and FloatToStrFmt helper functions.
+
+  -- 0.23 Changes/Bug Fixes -----------------------------------
+    - Added RectInRect and RectIntersects functions
+    - Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase.
+    - Moved BuildFileList here from DemoUtils.
+
+  -- 0.21 Changes/Bug Fixes -----------------------------------
+    - Moved GetVolumeLevelCount from ImagingDds here.
+    - Renamed FillMemory to FillMemoryByte to avoid name collision in C++ Builder.
+    - Added Iff function for Char, Pointer, and Int64 types.
+    - Added IsLittleEndian function.
+    - Added array types for TWordRec, TLongWordRec, and TInt64Rec.
+    - Added MatchFileNameMask function.
+
+  -- 0.19 Changes/Bug Fixes -----------------------------------
+    - added ScaleRectToRect (thanks to Paul Michell)
+    - added BoundsToRect, ClipBounds, ClipCopyBounds, ClipStretchBounds functions
+    - added MulDiv function
+    - FreeAndNil is not inline anymore - caused AV in one program
+
+  -- 0.17 Changes/Bug Fixes -----------------------------------
+
+    - GetAppExe didn't return absolute path in FreeBSD, fixed
+    - added debug message output
+    - fixed Unix compatibility issues (thanks to Ales Katona).
+      Imaging now compiles in FreeBSD and maybe in other Unixes as well.
+
+  -- 0.15 Changes/Bug Fixes -----------------------------------
+    - added some new utility functions
+
+  -- 0.13 Changes/Bug Fixes -----------------------------------
+    - added many new utility functions
+    - minor change in SwapEndian to avoid range check error
+
+}
+end.
diff --git a/src/lib/vampimg/ImagingXpm.pas b/src/lib/vampimg/ImagingXpm.pas
new file mode 100644 (file)
index 0000000..2e10dc2
--- /dev/null
@@ -0,0 +1,580 @@
+{
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  The contents of this file are used with permission, subject to the Mozilla
+  Public License Version 1.1 (the "License"); you may not use this file except
+  in compliance with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/MPL-1.1.html
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  GNU Lesser General Public License (the  "LGPL License"), in which case the
+  provisions of the LGPL License are applicable instead of those above.
+  If you wish to allow use of your version of this file only under the terms
+  of the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting  the provisions above and
+  replace  them with the notice and other provisions required by the LGPL
+  License.  If you do not delete the provisions above, a recipient may use
+  your version of this file under either the MPL or the LGPL License.
+
+  For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
+}
+
+{ This unit contains image format loader for X Window Pixmap images. }
+unit ImagingXpm;
+{$I ImagingOptions.inc}
+
+interface
+
+uses
+  SysUtils, Classes, Contnrs, ImagingTypes, Imaging, ImagingUtility,
+  ImagingFormats, ImagingIO, ImagingCanvases;
+
+type
+  { Class for loading X Window Pixmap images known as XPM.
+    It is ASCII-text-based format, basicaly a fragment of C code
+    declaring static array. Loaded image is in ifA8R8G8B8 data format.
+    Loading as well as saving is supported now. }
+  TXPMFileFormat = class(TImageFileFormat)
+  protected
+    procedure Define; override;
+    function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray;
+      OnlyFirstLevel: Boolean): Boolean; override;
+    function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray;
+      Index: LongInt): Boolean; override;
+    procedure ConvertToSupported(var Image: TImageData;
+      const Info: TImageFormatInfo); override;
+  public
+    function TestFormat(Handle: TImagingHandle): Boolean; override;
+  end;
+
+implementation
+
+const
+  SXPMFormatName = 'X Window Pixmap';
+  SXPMMasks = '*.xpm';
+  XPMSupportedFormats: TImageFormats = [ifA8R8G8B8];
+
+const
+  SXPMId = '/* XPM */';
+  WhiteSpaces = [#9, #10, #13, #32];
+
+const
+  BucketCount = 257;
+
+type
+  TColorHolder = class
+  public
+    Color: TColor32;
+  end;
+
+  TBucketItem = record
+    Key: TColor32;
+    Data: string[8];
+  end;
+
+  TBucketItemArray = array of TBucketItem;
+
+  TBucket = record
+    Count: Integer;
+    ItemIdxStart: Integer;
+    Items: TBucketItemArray;
+  end;
+
+  TBucketArray = array of TBucket;
+
+  { Simple color-string hash table for faster than linear searches
+    during XPM saving. }
+  TSimpleBucketList = class
+  private
+    FBuckets: TBucketArray;
+    FItemCount: Integer;
+    FABucket, FAIndex: Integer;
+    function GetData(AKey: TColor32): string;
+    procedure SetData(AKey: TColor32; const AData: string);
+    function FindItem(AKey: TColor32; out ABucket, AIndex: Integer): Boolean;
+  public
+    constructor Create;
+    procedure Add(AKey: TColor32; const AData: string);
+    function Exists(AKey: TColor32): Boolean;
+    function EnumNext(out AData: string): TColor32;
+    property Data[AKey: TColor32]: string read GetData write SetData; default;
+    property ItemCount: Integer read FItemCount;
+  end;
+
+  { TSimpleBucketList }
+
+constructor TSimpleBucketList.Create;
+begin
+  SetLength(FBuckets, BucketCount);
+end;
+
+function TSimpleBucketList.GetData(AKey: TColor32): string;
+var
+  Bucket, Index: Integer;
+begin
+  Result := '';
+  if FindItem(AKey, Bucket, Index) then
+    Result := string(FBuckets[Bucket].Items[Index].Data);
+end;
+
+procedure TSimpleBucketList.SetData(AKey: TColor32; const AData: string);
+var
+  Bucket, Index: Integer;
+begin
+  if FindItem(AKey, Bucket, Index) then
+    FBuckets[Bucket].Items[Index].Data := ShortString(AData);
+end;
+
+function TSimpleBucketList.EnumNext(out AData: string): TColor32;
+begin
+  // Skip empty buckets
+  while FAIndex >= FBuckets[FABucket].Count do
+  begin
+    Inc(FABucket);
+    if FABucket >= Length(FBuckets) then
+      FABucket := 0;
+    FAIndex := 0;
+  end;
+
+  Result := FBuckets[FABucket].Items[FAIndex].Key;
+  AData := string(FBuckets[FABucket].Items[FAIndex].Data);
+  Inc(FAIndex);
+end;
+
+function TSimpleBucketList.FindItem(AKey: TColor32; out ABucket,
+  AIndex: Integer): Boolean;
+var
+  I: Integer;
+  Col: TColor32Rec;
+begin
+  Result := False;
+  Col := TColor32Rec(AKey);
+  ABucket := (Col.A + 11 * Col.B + 59 * Col.R + 119 * Col.G) mod BucketCount;
+  with FBuckets[ABucket] do
+  for I := 0 to Count - 1 do
+    if Items[I].Key = AKey then
+    begin
+      AIndex := I;
+      Result := True;
+      Break;
+    end;
+end;
+
+procedure TSimpleBucketList.Add(AKey: TColor32; const AData: string);
+var
+  Bucket, Index, Delta, Size: Integer;
+begin
+  if not FindItem(AKey, Bucket, Index) then
+  with FBuckets[Bucket] do
+  begin
+    Size := Length(Items);
+    if Count = Size then
+    begin
+      if Size > 64 then
+        Delta := Size div 4
+      else
+        Delta := 16;
+      SetLength(Items, Size + Delta);
+    end;
+
+    with Items[Count] do
+    begin
+      Key := AKey;
+      Data := ShortString(AData);
+    end;
+    Inc(Count);
+    Inc(FItemCount);
+  end;
+end;
+
+function TSimpleBucketList.Exists(AKey: TColor32): Boolean;
+var
+  Bucket, Index: Integer;
+begin
+  Result := FindItem(AKey, Bucket, Index);
+end;
+
+{
+  TXPMFileFormat implementation
+}
+
+procedure TXPMFileFormat.Define;
+begin
+  inherited;
+  FName := SXPMFormatName;
+  FFeatures := [ffLoad, ffSave];
+  FSupportedFormats := XPMSupportedFormats;
+
+  AddMasks(SXPMMasks);
+end;
+
+function TXPMFileFormat.LoadData(Handle: TImagingHandle;
+  var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean;
+var
+  Contents, PalLookup: TStringList;
+  S: AnsiString;
+  I, J, NumColors, Cpp, Line: Integer;
+
+  procedure SkipWhiteSpace(var Line: string);
+  begin
+    while (Length(Line) > 0) and (AnsiChar(Line[1]) in WhiteSpaces) do
+      Delete(Line, 1, 1);
+  end;
+
+  function ReadString(var Line: string): string;
+  begin
+    Result := '';
+    SkipWhiteSpace(Line);
+    while (Length(Line) > 0) and not (AnsiChar(Line[1]) in WhiteSpaces) do
+    begin
+      SetLength(Result, Length(Result) + 1);
+      Result[Length(Result)] := Line[1];
+      Delete(Line, 1, 1);
+    end;
+  end;
+
+  function ReadInt(var Line: string): Integer;
+  begin
+    Result := StrToInt(ReadString(Line));
+  end;
+
+  function ParseHeader: Boolean;
+  var
+    S: string;
+  begin
+    S := Contents[0];
+    try
+      Images[0].Width := ReadInt(S);
+      Images[0].Height := ReadInt(S);
+      NumColors := ReadInt(S);
+      Cpp := ReadInt(S);
+      Line := 1;
+      Result := True;
+    except
+      Result := False;
+    end;
+  end;
+
+  function NamedToColor(const ColStr: string): TColor32;
+  var
+    S: string;
+  begin
+    S := LowerCase(ColStr);
+    if (S = 'transparent') or (S = 'none') then
+      Result := pcClear
+    else if S = 'black' then
+      Result := pcBlack
+    else if S = 'blue' then
+      Result := pcBlue
+    else if S = 'green' then
+      Result := pcGreen
+    else if S = 'cyan' then
+      Result := pcAqua
+    else if S = 'red' then
+      Result := pcRed
+    else if S = 'magenta' then
+      Result := pcFuchsia
+    else if S = 'yellow' then
+      Result := pcYellow
+    else if S = 'white' then
+      Result := pcWhite
+    else if S = 'gray' then
+      Result := pcLtGray
+    else if S = 'dkblue' then
+      Result := pcNavy
+    else if S = 'dkgreen' then
+      Result := pcGreen
+    else if S = 'dkcyan' then
+      Result := pcTeal
+    else if S = 'dkred' then
+      Result := pcMaroon
+    else if S = 'dkmagenta' then
+      Result := pcPurple
+    else if S = 'dkyellow' then
+      Result := pcOlive
+    else if S = 'maroon' then
+      Result := pcMaroon
+    else if S = 'olive' then
+      Result := pcOlive
+    else if S = 'navy' then
+      Result := pcNavy
+    else if S = 'purple' then
+      Result := pcPurple
+    else if S = 'teal' then
+      Result := pcTeal
+    else if S = 'silver' then
+      Result := pcSilver
+    else if S = 'lime' then
+      Result := pcLime
+    else if S = 'fuchsia' then
+      Result := pcFuchsia
+    else if S = 'aqua' then
+      Result := pcAqua
+    else
+      Result := pcClear;
+  end;
+
+  procedure ParsePalette;
+  var
+    I: Integer;
+    S, ColType, ColStr, Code: string;
+    Color: TColor32;
+    Holder: TColorHolder;
+  begin
+    for I := 0 to NumColors - 1 do
+    begin
+      Holder := TColorHolder.Create;
+      // Parse pixel code and color
+      S := Contents[Line + I];
+      Code := Copy(S, 1, Cpp);
+      Delete(S, 1, Cpp);
+      ColType := ReadString(S);
+      ColStr := ReadString(S);
+      // Convert color from hex number or named constant
+      if ColStr[1] = '#' then
+      begin
+        Delete(ColStr, 1, 1);
+        Color := LongWord(StrToInt('$' + Trim(ColStr))) or $FF000000;
+      end
+      else
+        Color := NamedToColor(ColStr);
+      // Store code and color in table for later lookup
+      Holder.Color := Color;
+      PalLookup.AddObject(Code, Holder);
+    end;
+    Inc(Line, NumColors);
+  end;
+
+  procedure ParsePixels;
+  var
+    X, Y, Idx: Integer;
+    S, Code: string;
+    Pix: PColor32;
+  begin
+    Pix := Images[0].Bits;
+    for Y := 0 to Images[0].Height - 1 do
+    begin
+      S := Contents[Line + Y];
+      for X := 0 to Images[0].Width - 1 do
+      begin
+        // Read code and look up color in the palette
+        Code := Copy(S, X * Cpp + 1, Cpp);
+        if PalLookup.Find(Code, Idx) then
+          Pix^ := TColorHolder(PalLookup.Objects[Idx]).Color
+        else
+          Pix^ := pcClear;
+        Inc(Pix);
+      end;
+    end;
+  end;
+
+begin
+  Result := False;
+  SetLength(Images, 1);
+  with GetIO, Images[0] do
+  begin
+    // Look up table for XPM palette entries
+    PalLookup := TStringList.Create;
+    PalLookup.Sorted := True;
+    PalLookup.CaseSensitive := True;
+    // Read whole file and assign it to string list
+    Contents := TStringList.Create;
+    SetLength(S, GetInputSize(GetIO, Handle));
+    Read(Handle, @S[1], Length(S));
+    Contents.Text := string(S);
+    // Remove quotes and other stuff
+    for I := Contents.Count - 1 downto 0 do
+    begin
+      J := Pos('"', Contents[I]);
+      if J > 0 then
+        Contents[I] := Copy(Contents[I], J + 1, LastDelimiter('"', Contents[I]) - J - 1)
+      else
+        Contents.Delete(I);
+    end;
+    // Parse header and create new image
+    if not ParseHeader then
+      Exit;
+    NewImage(Width, Height, ifA8R8G8B8, Images[0]);
+    // Read palette entries and assign colors to pixels
+    ParsePalette;
+    ParsePixels;
+
+    Contents.Free;
+    for I := 0 to PalLookup.Count - 1 do
+      PalLookup.Objects[I].Free;
+    PalLookup.Free;
+    Result := True;
+  end;
+end;
+
+function TXPMFileFormat.SaveData(Handle: TImagingHandle;
+  const Images: TDynImageDataArray; Index: LongInt): Boolean;
+const
+  ColorCharsCount = 92;
+  ColorChars = ' .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`''][{}|';
+var
+  X, Y: Integer;
+  ImageToSave: TImageData;
+  MustBeFreed: Boolean;
+  StrFile: TStringList;
+  ColTable: TSimpleBucketList;
+  Stream: TMemoryStream;
+  Line, Id: string;
+  CharsPerPixel: Integer;
+  Ptr: PColor32Rec;
+  ColRec: TColor32Rec;
+
+  procedure BuildColorTables(const Img: TImageData);
+  var
+    I: Integer;
+  begin
+    Ptr := Img.Bits;
+    for I := 0 to Img.Width * Img.Height - 1 do
+    begin
+      if not ColTable.Exists(Ptr.Color) then
+        ColTable.Add(Ptr.Color, '');
+      Inc(Ptr);
+    end;
+  end;
+
+  procedure MakeStrIdsForColors;
+  var
+    I, J, K: Integer;
+    Id, Data: string;
+  begin
+    SetLength(Id, CharsPerPixel);
+    for I := 0 to ColTable.ItemCount - 1 do
+    begin
+      ColRec.Color := ColTable.EnumNext(Data);
+      K := I;
+      for J := 0 to CharsPerPixel - 1 do
+      begin
+        Id[J + 1] := ColorChars[K mod ColorCharsCount + 1];
+        K := K div ColorCharsCount;
+      end;
+      ColTable.Data[ColRec.Color] := Id;
+    end;
+  end;
+
+begin
+  Result := False;
+
+  StrFile := TStringList.Create;
+  ColTable := TSimpleBucketList.Create;
+  Stream := TMemoryStream.Create;
+
+  if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then
+  try
+    // Put all unique colors of image to table
+    BuildColorTables(ImageToSave);
+    // Compute the character per pixel
+    CharsPerPixel := 1;
+    X := ColorCharsCount;
+    while ColTable.ItemCount > X do
+    begin
+      X := X * ColorCharsCount;
+      Inc(CharsPerPixel);
+    end;
+    // Assign char id to each color
+    MakeStrIdsForColors;
+
+    // Start writing XPM file
+    StrFile.Add(SXPMId);
+    StrFile.Add('static char *graphic[] = {');
+    StrFile.Add('/* width height num_colors chars_per_pixel */');
+    StrFile.Add(SysUtils.Format('"%d %d %d %d", ', [ImageToSave.Width,
+        ImageToSave.Height, ColTable.ItemCount, CharsPerPixel]));
+    StrFile.Add('/* colors */');
+
+    // Write 'colors' part of XPM file
+    for X := 0 to ColTable.ItemCount - 1 do
+    begin
+      ColRec.Color := ColTable.EnumNext(Id);
+      if ColRec.A >= 128 then
+        StrFile.Add(Format('"%s c #%.2x%.2x%.2x",', [Id, ColRec.R, ColRec.G, ColRec.B]))
+      else
+        StrFile.Add(Format('"%s c None",', [Id]));
+    end;
+
+    StrFile.Add('/* pixels */');
+
+    // Write pixels - for aech pixel of image find its char id
+    // and append it to line
+    Ptr := ImageToSave.Bits;
+    for Y := 0 to ImageToSave.Height - 1 do
+    begin
+      Line := '';
+      for X := 0 to ImageToSave.Width - 1 do
+      begin
+        Line := Line + ColTable.Data[Ptr.Color];
+        Inc(Ptr);
+      end;
+      Line := '"' + Line + '"';
+      if Y < ImageToSave.Height - 1 then
+        Line := Line + ',';
+      StrFile.Add(Line);
+    end;
+
+    StrFile.Add('};');
+
+    // Finally save strings to stream and write stream's data to output
+    // (we could directly write lines from list to output, but stream method
+    // takes care of D2009+ Unicode strings).
+    StrFile.SaveToStream(Stream);
+    GetIO.Write(Handle, Stream.Memory, Stream.Size);
+
+    Result := True;
+  finally
+    StrFile.Free;
+    ColTable.Free;
+    Stream.Free;
+    if MustBeFreed then
+      FreeImage(ImageToSave);
+  end;
+end;
+
+procedure TXPMFileFormat.ConvertToSupported(var Image: TImageData;
+  const Info: TImageFormatInfo);
+begin
+  ConvertImage(Image, ifA8R8G8B8)
+end;
+
+function TXPMFileFormat.TestFormat(Handle: TImagingHandle): Boolean;
+var
+  Id: array[0 .. 8] of AnsiChar;
+  ReadCount: Integer;
+begin
+  Result := False;
+  if Handle <> nil then
+  begin
+    ReadCount := GetIO.Read(Handle, @Id, SizeOf(Id));
+    GetIO.Seek(Handle, -ReadCount, smFromCurrent);
+    Result := (Id = SXPMId) and (ReadCount = SizeOf(Id));
+  end;
+end;
+
+initialization
+
+RegisterImageFileFormat(TXPMFileFormat);
+
+{
+  File Notes:
+
+  -- TODOS ----------------------------------------------------
+  - nothing now
+
+  -- 0.26.3 Changes/Bug Fixes -----------------------------------
+  - Added XPM saving.
+
+  -- 0.25.0 Changes/Bug Fixes -----------------------------------
+  - Added XPM loading.
+  - Unit created.
+}
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcapimin.pas b/src/lib/vampimg/JpegLib/imjcapimin.pas
new file mode 100644 (file)
index 0000000..d16c2ae
--- /dev/null
@@ -0,0 +1,401 @@
+unit imjcapimin;
+{$N+}
+{  This file contains application interface code for the compression half
+  of the JPEG library.  These are the "minimum" API routines that may be
+  needed in either the normal full-compression case or the transcoding-only
+  case.
+
+  Most of the routines intended to be called directly by an application
+  are in this file or in jcapistd.c.  But also see jcparam.c for
+  parameter-setup helper routines, jcomapi.c for routines shared by
+  compression and decompression, and jctrans.c for the transcoding case. }
+
+{ jcapimin.c ;  Copyright (C) 1994-1998, Thomas G. Lane. }
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib,
+  imjcomapi,
+  imjmemmgr,
+  imjcmarker;
+
+{ Initialization of JPEG compression objects.
+  Nomssi: This is a macro in the original code.
+
+  jpeg_create_compress() and jpeg_create_decompress() are the exported
+  names that applications should call.  These expand to calls on
+  jpeg_CreateCompress and jpeg_CreateDecompress with additional information
+  passed for version mismatch checking.
+  NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. }
+
+procedure jpeg_create_compress(cinfo : j_compress_ptr);
+
+
+{ Initialization of a JPEG compression object.
+  The error manager must already be set up (in case memory manager fails). }
+
+{GLOBAL}
+procedure jpeg_CreateCompress (cinfo : j_compress_ptr;
+                               version : int;
+                               structsize : size_t);
+
+{ Destruction of a JPEG compression object }
+
+{GLOBAL}
+procedure jpeg_destroy_compress (cinfo : j_compress_ptr);
+
+
+{ Abort processing of a JPEG compression operation,
+  but don't destroy the object itself. }
+
+{GLOBAL}
+procedure jpeg_abort_compress (cinfo : j_compress_ptr);
+
+
+{ Forcibly suppress or un-suppress all quantization and Huffman tables.
+  Marks all currently defined tables as already written (if suppress)
+  or not written (if !suppress).  This will control whether they get emitted
+  by a subsequent jpeg_start_compress call.
+
+  This routine is exported for use by applications that want to produce
+  abbreviated JPEG datastreams.  It logically belongs in jcparam.c, but
+  since it is called by jpeg_start_compress, we put it here --- otherwise
+  jcparam.o would be linked whether the application used it or not. }
+
+{GLOBAL}
+procedure jpeg_suppress_tables (cinfo : j_compress_ptr;
+                                suppress : boolean);
+
+
+{ Finish JPEG compression.
+
+  If a multipass operating mode was selected, this may do a great deal of
+  work including most of the actual output. }
+
+{GLOBAL}
+procedure jpeg_finish_compress (cinfo : j_compress_ptr);
+
+{ Write a special marker.
+  This is only recommended for writing COM or APPn markers.
+  Must be called after jpeg_start_compress() and before
+  first call to jpeg_write_scanlines() or jpeg_write_raw_data(). }
+
+{GLOBAL}
+procedure jpeg_write_marker (cinfo : j_compress_ptr;
+                             marker : int;
+                 dataptr : JOCTETptr;
+                             datalen : uInt);
+
+{GLOBAL}
+procedure jpeg_write_m_header (cinfo : j_compress_ptr;
+                               marker : int;
+                               datalen : uint);
+{GLOBAL}
+procedure jpeg_write_m_byte (cinfo : j_compress_ptr; val : int);
+
+{ Alternate compression function: just write an abbreviated table file.
+  Before calling this, all parameters and a data destination must be set up.
+
+  To produce a pair of files containing abbreviated tables and abbreviated
+  image data, one would proceed as follows:
+
+    initialize JPEG object
+    set JPEG parameters
+    set destination to table file
+    jpeg_write_tables(cinfo);
+    set destination to image file
+    jpeg_start_compress(cinfo, FALSE);
+    write data...
+    jpeg_finish_compress(cinfo);
+
+  jpeg_write_tables has the side effect of marking all tables written
+  (same as jpeg_suppress_tables(..., TRUE)).  Thus a subsequent start_compress
+  will not re-emit the tables unless it is passed write_all_tables=TRUE. }
+
+
+
+{GLOBAL}
+procedure jpeg_write_tables (cinfo : j_compress_ptr);
+
+implementation
+
+procedure jpeg_create_compress(cinfo : j_compress_ptr);
+begin
+  jpeg_CreateCompress(cinfo, JPEG_LIB_VERSION,
+                      size_t(sizeof(jpeg_compress_struct)));
+end;
+
+{ Initialization of a JPEG compression object.
+  The error manager must already be set up (in case memory manager fails). }
+
+{GLOBAL}
+procedure jpeg_CreateCompress (cinfo : j_compress_ptr;
+                               version : int;
+                               structsize : size_t);
+var
+  i : int;
+var
+  err : jpeg_error_mgr_ptr;
+  client_data : voidp;
+begin
+
+  { Guard against version mismatches between library and caller. }
+  cinfo^.mem := NIL;    { so jpeg_destroy knows mem mgr not called }
+  if (version <> JPEG_LIB_VERSION) then
+    ERREXIT2(j_common_ptr(cinfo), JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+  if (structsize <> SIZEOF(jpeg_compress_struct)) then
+    ERREXIT2(j_common_ptr(cinfo), JERR_BAD_STRUCT_SIZE,
+       int(SIZEOF(jpeg_compress_struct)), int(structsize));
+
+  { For debugging purposes, we zero the whole master structure.
+    But the application has already set the err pointer, and may have set
+    client_data, so we have to save and restore those fields.
+    Note: if application hasn't set client_data, tools like Purify may
+    complain here. }
+
+  err := cinfo^.err;
+  client_data := cinfo^.client_data; { ignore Purify complaint here }
+  MEMZERO(cinfo, SIZEOF(jpeg_compress_struct));
+  cinfo^.err := err;
+  cinfo^.is_decompressor := FALSE;
+
+  { Initialize a memory manager instance for this object }
+  jinit_memory_mgr(j_common_ptr(cinfo));
+
+  { Zero out pointers to permanent structures. }
+  cinfo^.progress := NIL;
+  cinfo^.dest := NIL;
+
+  cinfo^.comp_info := NIL;
+
+  for i := 0 to pred(NUM_QUANT_TBLS) do
+    cinfo^.quant_tbl_ptrs[i] := NIL;
+
+  for i := 0 to pred(NUM_HUFF_TBLS) do
+  begin
+    cinfo^.dc_huff_tbl_ptrs[i] := NIL;
+    cinfo^.ac_huff_tbl_ptrs[i] := NIL;
+  end;
+
+  cinfo^.script_space := NIL;
+
+  cinfo^.input_gamma := 1.0;  { in case application forgets }
+
+  { OK, I'm ready }
+  cinfo^.global_state := CSTATE_START;
+end;
+
+
+{ Destruction of a JPEG compression object }
+
+{GLOBAL}
+procedure jpeg_destroy_compress (cinfo : j_compress_ptr);
+begin
+  jpeg_destroy(j_common_ptr(cinfo)); { use common routine }
+end;
+
+
+{ Abort processing of a JPEG compression operation,
+  but don't destroy the object itself. }
+
+{GLOBAL}
+procedure jpeg_abort_compress (cinfo : j_compress_ptr);
+begin
+  jpeg_abort(j_common_ptr(cinfo)); { use common routine }
+end;
+
+
+{ Forcibly suppress or un-suppress all quantization and Huffman tables.
+  Marks all currently defined tables as already written (if suppress)
+  or not written (if !suppress).  This will control whether they get emitted
+  by a subsequent jpeg_start_compress call.
+
+  This routine is exported for use by applications that want to produce
+  abbreviated JPEG datastreams.  It logically belongs in jcparam.c, but
+  since it is called by jpeg_start_compress, we put it here --- otherwise
+  jcparam.o would be linked whether the application used it or not. }
+
+{GLOBAL}
+procedure jpeg_suppress_tables (cinfo : j_compress_ptr;
+                                suppress : boolean);
+var
+  i : int;
+  qtbl : JQUANT_TBL_PTR;
+  htbl : JHUFF_TBL_PTR;
+begin
+  for i := 0 to pred(NUM_QUANT_TBLS) do
+  begin
+    qtbl := cinfo^.quant_tbl_ptrs[i];
+    if (qtbl <> NIL) then
+      qtbl^.sent_table := suppress;
+  end;
+
+  for i := 0 to pred(NUM_HUFF_TBLS) do
+  begin
+    htbl := cinfo^.dc_huff_tbl_ptrs[i];
+    if (htbl <> NIL) then
+      htbl^.sent_table := suppress;
+    htbl := cinfo^.ac_huff_tbl_ptrs[i];
+    if (htbl <> NIL) then
+      htbl^.sent_table := suppress;
+  end;
+end;
+
+
+{ Finish JPEG compression.
+
+  If a multipass operating mode was selected, this may do a great deal of
+  work including most of the actual output. }
+
+{GLOBAL}
+procedure jpeg_finish_compress (cinfo : j_compress_ptr);
+var
+  iMCU_row : JDIMENSION;
+begin
+  if (cinfo^.global_state = CSTATE_SCANNING) or
+     (cinfo^.global_state = CSTATE_RAW_OK) then
+  begin
+    { Terminate first pass }
+    if (cinfo^.next_scanline < cinfo^.image_height) then
+      ERREXIT(j_common_ptr(cinfo), JERR_TOO_LITTLE_DATA);
+    cinfo^.master^.finish_pass (cinfo);
+  end
+  else
+    if (cinfo^.global_state <> CSTATE_WRCOEFS) then
+      ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  { Perform any remaining passes }
+  while (not cinfo^.master^.is_last_pass) do
+  begin
+    cinfo^.master^.prepare_for_pass (cinfo);
+    for iMCU_row := 0 to pred(cinfo^.total_iMCU_rows) do
+    begin
+      if (cinfo^.progress <> NIL) then
+      begin
+        cinfo^.progress^.pass_counter := long (iMCU_row);
+        cinfo^.progress^.pass_limit := long (cinfo^.total_iMCU_rows);
+        cinfo^.progress^.progress_monitor (j_common_ptr(cinfo));
+      end;
+      { We bypass the main controller and invoke coef controller directly;
+        all work is being done from the coefficient buffer. }
+
+      if (not cinfo^.coef^.compress_data (cinfo, JSAMPIMAGE(NIL))) then
+        ERREXIT(j_common_ptr(cinfo), JERR_CANT_SUSPEND);
+    end;
+    cinfo^.master^.finish_pass (cinfo);
+  end;
+  { Write EOI, do final cleanup }
+  cinfo^.marker^.write_file_trailer (cinfo);
+  cinfo^.dest^.term_destination (cinfo);
+  { We can use jpeg_abort to release memory and reset global_state }
+  jpeg_abort(j_common_ptr(cinfo));
+end;
+
+
+{ Write a special marker.
+  This is only recommended for writing COM or APPn markers.
+  Must be called after jpeg_start_compress() and before
+  first call to jpeg_write_scanlines() or jpeg_write_raw_data(). }
+
+{GLOBAL}
+procedure jpeg_write_marker (cinfo : j_compress_ptr;
+                             marker : int;
+                 dataptr : JOCTETptr;
+                             datalen : uInt);
+var
+  write_marker_byte : procedure(info : j_compress_ptr; val : int);
+begin
+  if (cinfo^.next_scanline <> 0) or
+     ((cinfo^.global_state <> CSTATE_SCANNING) and
+      (cinfo^.global_state <> CSTATE_RAW_OK) and
+      (cinfo^.global_state <> CSTATE_WRCOEFS)) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  cinfo^.marker^.write_marker_header (cinfo, marker, datalen);
+  write_marker_byte := cinfo^.marker^.write_marker_byte; { copy for speed }
+  while (datalen <> 0) do
+  begin
+    Dec(datalen);
+    write_marker_byte (cinfo, dataptr^);
+    Inc(dataptr);
+  end;
+end;
+
+{ Same, but piecemeal. }
+
+{GLOBAL}
+procedure jpeg_write_m_header (cinfo : j_compress_ptr;
+                               marker : int;
+                               datalen : uint);
+begin
+  if (cinfo^.next_scanline <> 0) or
+     ((cinfo^.global_state <> CSTATE_SCANNING) and
+      (cinfo^.global_state <> CSTATE_RAW_OK) and
+      (cinfo^.global_state <> CSTATE_WRCOEFS)) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  cinfo^.marker^.write_marker_header (cinfo, marker, datalen);
+end;
+
+{GLOBAL}
+procedure jpeg_write_m_byte (cinfo : j_compress_ptr; val : int);
+begin
+  cinfo^.marker^.write_marker_byte (cinfo, val);
+end;
+
+
+{ Alternate compression function: just write an abbreviated table file.
+  Before calling this, all parameters and a data destination must be set up.
+
+  To produce a pair of files containing abbreviated tables and abbreviated
+  image data, one would proceed as follows:
+
+    initialize JPEG object
+    set JPEG parameters
+    set destination to table file
+    jpeg_write_tables(cinfo);
+    set destination to image file
+    jpeg_start_compress(cinfo, FALSE);
+    write data...
+    jpeg_finish_compress(cinfo);
+
+  jpeg_write_tables has the side effect of marking all tables written
+  (same as jpeg_suppress_tables(..., TRUE)).  Thus a subsequent start_compress
+  will not re-emit the tables unless it is passed write_all_tables=TRUE. }
+
+{GLOBAL}
+procedure jpeg_write_tables (cinfo : j_compress_ptr);
+begin
+  if (cinfo^.global_state <> CSTATE_START) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  { (Re)initialize error mgr and destination modules }
+  cinfo^.err^.reset_error_mgr (j_common_ptr(cinfo));
+  cinfo^.dest^.init_destination (cinfo);
+  { Initialize the marker writer ... bit of a crock to do it here. }
+  jinit_marker_writer(cinfo);
+  { Write them tables! }
+  cinfo^.marker^.write_tables_only (cinfo);
+  { And clean up. }
+  cinfo^.dest^.term_destination (cinfo);
+
+  { In library releases up through v6a, we called jpeg_abort() here to free
+    any working memory allocated by the destination manager and marker
+    writer.  Some applications had a problem with that: they allocated space
+    of their own from the library memory manager, and didn't want it to go
+    away during write_tables.  So now we do nothing.  This will cause a
+    memory leak if an app calls write_tables repeatedly without doing a full
+    compression cycle or otherwise resetting the JPEG object.  However, that
+    seems less bad than unexpectedly freeing memory in the normal case.
+    An app that prefers the old behavior can call jpeg_abort for itself after
+    each call to jpeg_write_tables(). }
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcapistd.pas b/src/lib/vampimg/JpegLib/imjcapistd.pas
new file mode 100644 (file)
index 0000000..bc487a7
--- /dev/null
@@ -0,0 +1,222 @@
+unit imjcapistd;
+
+{ Original : jcapistd.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+{ This file is part of the Independent JPEG Group's software.
+  For conditions of distribution and use, see the accompanying README file.
+
+  This file contains application interface code for the compression half
+  of the JPEG library.  These are the "standard" API routines that are
+  used in the normal full-compression case.  They are not used by a
+  transcoding-only application.  Note that if an application links in
+  jpeg_start_compress, it will end up linking in the entire compressor.
+  We thus must separate this file from jcapimin.c to avoid linking the
+  whole compression library into a transcoder. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib,
+  imjcapimin, imjcinit;
+
+
+
+{ Compression initialization.
+  Before calling this, all parameters and a data destination must be set up.
+
+  We require a write_all_tables parameter as a failsafe check when writing
+  multiple datastreams from the same compression object.  Since prior runs
+  will have left all the tables marked sent_table=TRUE, a subsequent run
+  would emit an abbreviated stream (no tables) by default.  This may be what
+  is wanted, but for safety's sake it should not be the default behavior:
+  programmers should have to make a deliberate choice to emit abbreviated
+  images.  Therefore the documentation and examples should encourage people
+  to pass write_all_tables=TRUE; then it will take active thought to do the
+  wrong thing. }
+
+{GLOBAL}
+procedure jpeg_start_compress (cinfo : j_compress_ptr;
+                               write_all_tables : boolean);
+
+
+{ Write some scanlines of data to the JPEG compressor.
+
+  The return value will be the number of lines actually written.
+  This should be less than the supplied num_lines only in case that
+  the data destination module has requested suspension of the compressor,
+  or if more than image_height scanlines are passed in.
+
+  Note: we warn about excess calls to jpeg_write_scanlines() since
+  this likely signals an application programmer error.  However,
+  excess scanlines passed in the last valid call are *silently* ignored,
+  so that the application need not adjust num_lines for end-of-image
+  when using a multiple-scanline buffer. }
+
+{GLOBAL}
+function jpeg_write_scanlines (cinfo : j_compress_ptr;
+                              scanlines : JSAMPARRAY;
+                  num_lines : JDIMENSION) : JDIMENSION;
+
+{ Alternate entry point to write raw data.
+  Processes exactly one iMCU row per call, unless suspended. }
+
+{GLOBAL}
+function jpeg_write_raw_data (cinfo : j_compress_ptr;
+                              data : JSAMPIMAGE;
+                  num_lines : JDIMENSION) : JDIMENSION;
+
+implementation
+
+{ Compression initialization.
+  Before calling this, all parameters and a data destination must be set up.
+
+  We require a write_all_tables parameter as a failsafe check when writing
+  multiple datastreams from the same compression object.  Since prior runs
+  will have left all the tables marked sent_table=TRUE, a subsequent run
+  would emit an abbreviated stream (no tables) by default.  This may be what
+  is wanted, but for safety's sake it should not be the default behavior:
+  programmers should have to make a deliberate choice to emit abbreviated
+  images.  Therefore the documentation and examples should encourage people
+  to pass write_all_tables=TRUE; then it will take active thought to do the
+  wrong thing. }
+
+{GLOBAL}
+procedure jpeg_start_compress (cinfo : j_compress_ptr;
+                               write_all_tables : boolean);
+begin
+  if (cinfo^.global_state <> CSTATE_START) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  if (write_all_tables) then
+    jpeg_suppress_tables(cinfo, FALSE); { mark all tables to be written }
+
+  { (Re)initialize error mgr and destination modules }
+  cinfo^.err^.reset_error_mgr (j_common_ptr(cinfo));
+  cinfo^.dest^.init_destination (cinfo);
+  { Perform master selection of active modules }
+  jinit_compress_master(cinfo);
+  { Set up for the first pass }
+  cinfo^.master^.prepare_for_pass (cinfo);
+  { Ready for application to drive first pass through jpeg_write_scanlines
+    or jpeg_write_raw_data. }
+
+  cinfo^.next_scanline := 0;
+  if cinfo^.raw_data_in then
+    cinfo^.global_state := CSTATE_RAW_OK
+  else
+    cinfo^.global_state := CSTATE_SCANNING;
+end;
+
+
+{ Write some scanlines of data to the JPEG compressor.
+
+  The return value will be the number of lines actually written.
+  This should be less than the supplied num_lines only in case that
+  the data destination module has requested suspension of the compressor,
+  or if more than image_height scanlines are passed in.
+
+  Note: we warn about excess calls to jpeg_write_scanlines() since
+  this likely signals an application programmer error.  However,
+  excess scanlines passed in the last valid call are *silently* ignored,
+  so that the application need not adjust num_lines for end-of-image
+  when using a multiple-scanline buffer. }
+
+{GLOBAL}
+function jpeg_write_scanlines (cinfo : j_compress_ptr;
+                              scanlines : JSAMPARRAY;
+                  num_lines : JDIMENSION) : JDIMENSION;
+var
+  row_ctr, rows_left : JDIMENSION;
+begin
+  if (cinfo^.global_state <> CSTATE_SCANNING) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  if (cinfo^.next_scanline >= cinfo^.image_height) then
+    WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA);
+
+  { Call progress monitor hook if present }
+  if (cinfo^.progress <> NIL) then
+  begin
+    cinfo^.progress^.pass_counter := long (cinfo^.next_scanline);
+    cinfo^.progress^.pass_limit := long (cinfo^.image_height);
+    cinfo^.progress^.progress_monitor (j_common_ptr(cinfo));
+  end;
+
+  { Give master control module another chance if this is first call to
+    jpeg_write_scanlines.  This lets output of the frame/scan headers be
+    delayed so that application can write COM, etc, markers between
+    jpeg_start_compress and jpeg_write_scanlines. }
+  if (cinfo^.master^.call_pass_startup) then
+    cinfo^.master^.pass_startup (cinfo);
+
+  { Ignore any extra scanlines at bottom of image. }
+  rows_left := cinfo^.image_height - cinfo^.next_scanline;
+  if (num_lines > rows_left) then
+    num_lines := rows_left;
+
+  row_ctr := 0;
+  cinfo^.main^.process_data (cinfo, scanlines, {var}row_ctr, num_lines);
+  Inc(cinfo^.next_scanline, row_ctr);
+  jpeg_write_scanlines := row_ctr;
+end;
+
+
+{ Alternate entry point to write raw data.
+  Processes exactly one iMCU row per call, unless suspended. }
+
+{GLOBAL}
+function jpeg_write_raw_data (cinfo : j_compress_ptr;
+                              data : JSAMPIMAGE;
+                  num_lines : JDIMENSION) : JDIMENSION;
+var
+  lines_per_iMCU_row : JDIMENSION;
+begin
+  if (cinfo^.global_state <> CSTATE_RAW_OK) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  if (cinfo^.next_scanline >= cinfo^.image_height) then
+  begin
+    WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA);
+    jpeg_write_raw_data := 0;
+    exit;
+  end;
+
+  { Call progress monitor hook if present }
+  if (cinfo^.progress <> NIL) then
+  begin
+    cinfo^.progress^.pass_counter := long(cinfo^.next_scanline);
+    cinfo^.progress^.pass_limit := long(cinfo^.image_height);
+    cinfo^.progress^.progress_monitor (j_common_ptr(cinfo));
+  end;
+
+  { Give master control module another chance if this is first call to
+    jpeg_write_raw_data.  This lets output of the frame/scan headers be
+    delayed so that application can write COM, etc, markers between
+    jpeg_start_compress and jpeg_write_raw_data. }
+
+  if (cinfo^.master^.call_pass_startup) then
+    cinfo^.master^.pass_startup (cinfo);
+
+  { Verify that at least one iMCU row has been passed. }
+  lines_per_iMCU_row := cinfo^.max_v_samp_factor * DCTSIZE;
+  if (num_lines < lines_per_iMCU_row) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BUFFER_SIZE);
+
+  { Directly compress the row. }
+  if (not cinfo^.coef^.compress_data (cinfo, data)) then
+  begin
+    { If compressor did not consume the whole row, suspend processing. }
+    jpeg_write_raw_data := 0;
+    exit;
+  end;
+
+  { OK, we processed one iMCU row. }
+  Inc(cinfo^.next_scanline, lines_per_iMCU_row);
+  jpeg_write_raw_data := lines_per_iMCU_row;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjccoefct.pas b/src/lib/vampimg/JpegLib/imjccoefct.pas
new file mode 100644 (file)
index 0000000..7d6ee6f
--- /dev/null
@@ -0,0 +1,521 @@
+unit imjccoefct;
+
+{ This file contains the coefficient buffer controller for compression.
+  This controller is the top level of the JPEG compressor proper.
+  The coefficient buffer lies between forward-DCT and entropy encoding steps.}
+
+{ Original: jccoefct.c; Copyright (C) 1994-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjerror,
+  imjdeferr,
+  imjutils,
+  imjpeglib;
+
+{ We use a full-image coefficient buffer when doing Huffman optimization,
+  and also for writing multiple-scan JPEG files.  In all cases, the DCT
+  step is run during the first pass, and subsequent passes need only read
+  the buffered coefficients. }
+{$ifdef ENTROPY_OPT_SUPPORTED}
+  {$define FULL_COEF_BUFFER_SUPPORTED}
+{$else}
+  {$ifdef C_MULTISCAN_FILES_SUPPORTED}
+    {$define FULL_COEF_BUFFER_SUPPORTED}
+  {$endif}
+{$endif}
+
+{ Initialize coefficient buffer controller. }
+
+{GLOBAL}
+procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
+                                   need_full_buffer : boolean);
+
+implementation
+
+{ Private buffer controller object }
+
+type
+  my_coef_ptr = ^my_coef_controller;
+  my_coef_controller = record
+    pub : jpeg_c_coef_controller; { public fields }
+
+    iMCU_row_num : JDIMENSION;  { iMCU row # within image }
+    mcu_ctr : JDIMENSION; { counts MCUs processed in current row }
+    MCU_vert_offset : int;  { counts MCU rows within iMCU row }
+    MCU_rows_per_iMCU_row : int;  { number of such rows needed }
+
+    { For single-pass compression, it's sufficient to buffer just one MCU
+      (although this may prove a bit slow in practice).  We allocate a
+      workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
+      MCU constructed and sent.  (On 80x86, the workspace is FAR even though
+      it's not really very big; this is to keep the module interfaces unchanged
+      when a large coefficient buffer is necessary.)
+      In multi-pass modes, this array points to the current MCU's blocks
+      within the virtual arrays. }
+
+    MCU_buffer : array[0..C_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW;
+
+    { In multi-pass modes, we need a virtual block array for each component. }
+    whole_image : array[0..MAX_COMPONENTS-1] of jvirt_barray_ptr;
+  end;
+
+
+{ Forward declarations }
+{METHODDEF}
+function compress_data(cinfo : j_compress_ptr;
+                       input_buf : JSAMPIMAGE) : boolean; forward;
+{$ifdef FULL_COEF_BUFFER_SUPPORTED}
+{METHODDEF}
+function compress_first_pass(cinfo : j_compress_ptr;
+                             input_buf : JSAMPIMAGE) : boolean;  forward;
+{METHODDEF}
+function compress_output(cinfo : j_compress_ptr;
+                         input_buf : JSAMPIMAGE) : boolean;  forward;
+{$endif}
+
+
+{LOCAL}
+procedure start_iMCU_row (cinfo : j_compress_ptr);
+{ Reset within-iMCU-row counters for a new row }
+var
+  coef : my_coef_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+
+  { In an interleaved scan, an MCU row is the same as an iMCU row.
+    In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+    But at the bottom of the image, process only what's left. }
+  if (cinfo^.comps_in_scan > 1) then
+  begin
+    coef^.MCU_rows_per_iMCU_row := 1;
+  end
+  else
+  begin
+    if (coef^.iMCU_row_num < (cinfo^.total_iMCU_rows-1)) then
+      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor
+    else
+      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height;
+  end;
+
+  coef^.mcu_ctr := 0;
+  coef^.MCU_vert_offset := 0;
+end;
+
+
+{ Initialize for a processing pass. }
+
+{METHODDEF}
+procedure start_pass_coef (cinfo : j_compress_ptr;
+                           pass_mode : J_BUF_MODE);
+var
+  coef : my_coef_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+
+  coef^.iMCU_row_num := 0;
+  start_iMCU_row(cinfo);
+
+  case (pass_mode) of
+  JBUF_PASS_THRU:
+    begin
+      if (coef^.whole_image[0] <> NIL) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+      coef^.pub.compress_data := compress_data;
+    end;
+{$ifdef FULL_COEF_BUFFER_SUPPORTED}
+  JBUF_SAVE_AND_PASS:
+    begin
+      if (coef^.whole_image[0] = NIL) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+      coef^.pub.compress_data := compress_first_pass;
+    end;
+  JBUF_CRANK_DEST:
+    begin
+      if (coef^.whole_image[0] = NIL) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+      coef^.pub.compress_data := compress_output;
+    end;
+{$endif}
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+  end;
+end;
+
+
+{ Process some data in the single-pass case.
+  We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+  per call, ie, v_samp_factor block rows for each component in the image.
+  Returns TRUE if the iMCU row is completed, FALSE if suspended.
+
+  NB: input_buf contains a plane for each component in image,
+  which we index according to the component's SOF position. }
+
+
+{METHODDEF}
+function compress_data (cinfo : j_compress_ptr;
+                        input_buf : JSAMPIMAGE) : boolean;
+var
+  coef : my_coef_ptr;
+  MCU_col_num : JDIMENSION; { index of current MCU within row }
+  last_MCU_col : JDIMENSION;
+  last_iMCU_row : JDIMENSION;
+  blkn, bi, ci, yindex, yoffset, blockcnt : int;
+  ypos, xpos : JDIMENSION;
+  compptr : jpeg_component_info_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+  last_MCU_col := cinfo^.MCUs_per_row - 1;
+  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
+
+  { Loop to write as much as one whole iMCU row }
+  for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
+  begin
+    for MCU_col_num := coef^.mcu_ctr to last_MCU_col do
+    begin
+      { Determine where data comes from in input_buf and do the DCT thing.
+        Each call on forward_DCT processes a horizontal row of DCT blocks
+        as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
+        sequentially.  Dummy blocks at the right or bottom edge are filled in
+        specially.  The data in them does not matter for image reconstruction,
+        so we fill them with values that will encode to the smallest amount of
+        data, viz: all zeroes in the AC entries, DC entries equal to previous
+        block's DC value.  (Thanks to Thomas Kinsman for this idea.) }
+
+      blkn := 0;
+      for ci := 0 to pred(cinfo^.comps_in_scan) do
+      begin
+  compptr := cinfo^.cur_comp_info[ci];
+        if (MCU_col_num < last_MCU_col)  then
+          blockcnt := compptr^.MCU_width
+        else
+          blockcnt := compptr^.last_col_width;
+  xpos := MCU_col_num * JDIMENSION(compptr^.MCU_sample_width);
+  ypos := yoffset * DCTSIZE;      { ypos = (yoffset+yindex) * DCTSIZE }
+  for yindex := 0 to pred(compptr^.MCU_height) do
+        begin
+    if (coef^.iMCU_row_num < last_iMCU_row) or
+       (yoffset+yindex < compptr^.last_row_height) then
+          begin
+      cinfo^.fdct^.forward_DCT (cinfo, compptr,
+              input_buf^[compptr^.component_index],
+              coef^.MCU_buffer[blkn],
+              ypos, xpos, JDIMENSION (blockcnt));
+
+      if (blockcnt < compptr^.MCU_width) then
+            begin
+        { Create some dummy blocks at the right edge of the image. }
+        jzero_far({FAR}pointer(coef^.MCU_buffer[blkn + blockcnt]),
+      (compptr^.MCU_width - blockcnt) * SIZEOF(JBLOCK));
+        for bi := blockcnt to pred(compptr^.MCU_width) do
+              begin
+    coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn+bi-1]^[0][0];
+        end;
+      end;
+    end
+          else
+          begin
+      { Create a row of dummy blocks at the bottom of the image. }
+      jzero_far({FAR}pointer(coef^.MCU_buffer[blkn]),
+          compptr^.MCU_width * SIZEOF(JBLOCK));
+      for bi := 0 to pred(compptr^.MCU_width) do
+            begin
+        coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn-1]^[0][0];
+      end;
+    end;
+    Inc(blkn, compptr^.MCU_width);
+    Inc(ypos, DCTSIZE);
+  end;
+      end;
+      { Try to write the MCU.  In event of a suspension failure, we will
+        re-DCT the MCU on restart (a bit inefficient, could be fixed...) }
+
+      if (not cinfo^.entropy^.encode_mcu (cinfo, JBLOCKARRAY(@coef^.MCU_buffer)^)) then
+      begin
+  { Suspension forced; update state counters and exit }
+  coef^.MCU_vert_offset := yoffset;
+  coef^.mcu_ctr := MCU_col_num;
+  compress_data := FALSE;
+        exit;
+      end;
+    end;
+    { Completed an MCU row, but perhaps not an iMCU row }
+    coef^.mcu_ctr := 0;
+  end;
+  { Completed the iMCU row, advance counters for next one }
+  Inc(coef^.iMCU_row_num);
+  start_iMCU_row(cinfo);
+  compress_data := TRUE;
+end;
+
+
+{$ifdef FULL_COEF_BUFFER_SUPPORTED}
+
+{ Process some data in the first pass of a multi-pass case.
+  We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+  per call, ie, v_samp_factor block rows for each component in the image.
+  This amount of data is read from the source buffer, DCT'd and quantized,
+  and saved into the virtual arrays.  We also generate suitable dummy blocks
+  as needed at the right and lower edges.  (The dummy blocks are constructed
+  in the virtual arrays, which have been padded appropriately.)  This makes
+  it possible for subsequent passes not to worry about real vs. dummy blocks.
+
+  We must also emit the data to the entropy encoder.  This is conveniently
+  done by calling compress_output() after we've loaded the current strip
+  of the virtual arrays.
+
+  NB: input_buf contains a plane for each component in image.  All
+  components are DCT'd and loaded into the virtual arrays in this pass.
+  However, it may be that only a subset of the components are emitted to
+  the entropy encoder during this first pass; be careful about looking
+  at the scan-dependent variables (MCU dimensions, etc). }
+
+{METHODDEF}
+function compress_first_pass (cinfo : j_compress_ptr;
+                              input_buf : JSAMPIMAGE) : boolean;
+var
+  coef : my_coef_ptr;
+  last_iMCU_row : JDIMENSION;
+  blocks_across, MCUs_across, MCUindex : JDIMENSION;
+  bi, ci, h_samp_factor, block_row, block_rows, ndummy : int;
+  lastDC : JCOEF;
+  compptr : jpeg_component_info_ptr;
+  buffer : JBLOCKARRAY;
+  thisblockrow, lastblockrow : JBLOCKROW;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Align the virtual buffer for this component. }
+    buffer := cinfo^.mem^.access_virt_barray
+      (j_common_ptr(cinfo), coef^.whole_image[ci],
+       coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor),
+       JDIMENSION (compptr^.v_samp_factor), TRUE);
+    { Count non-dummy DCT block rows in this iMCU row. }
+    if (coef^.iMCU_row_num < last_iMCU_row) then
+      block_rows := compptr^.v_samp_factor
+    else
+    begin
+      { NB: can't use last_row_height here, since may not be set! }
+      block_rows := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor;
+      if (block_rows = 0) then
+        block_rows := compptr^.v_samp_factor;
+    end;
+    blocks_across := compptr^.width_in_blocks;
+    h_samp_factor := compptr^.h_samp_factor;
+    { Count number of dummy blocks to be added at the right margin. }
+    ndummy := int (blocks_across) mod h_samp_factor;
+    if (ndummy > 0) then
+      ndummy := h_samp_factor - ndummy;
+    { Perform DCT for all non-dummy blocks in this iMCU row.  Each call
+      on forward_DCT processes a complete horizontal row of DCT blocks. }
+
+    for block_row := 0 to pred(block_rows) do
+    begin
+      thisblockrow := buffer^[block_row];
+      cinfo^.fdct^.forward_DCT (cinfo, compptr,
+                          input_buf^[ci],
+                                thisblockrow,
+        JDIMENSION (block_row * DCTSIZE),
+        JDIMENSION (0),
+                                blocks_across);
+      if (ndummy > 0) then
+      begin
+  { Create dummy blocks at the right edge of the image. }
+  Inc(JBLOCK_PTR(thisblockrow), blocks_across); { => first dummy block }
+  jzero_far({FAR}pointer(thisblockrow), ndummy * SIZEOF(JBLOCK));
+  {lastDC := thisblockrow^[-1][0];}
+        { work around Range Checking }
+        Dec(JBLOCK_PTR(thisblockrow));
+        lastDC := thisblockrow^[0][0];
+        Inc(JBLOCK_PTR(thisblockrow));
+
+  for bi := 0 to pred(ndummy) do
+        begin
+    thisblockrow^[bi][0] := lastDC;
+  end;
+      end;
+    end;
+    { If at end of image, create dummy block rows as needed.
+      The tricky part here is that within each MCU, we want the DC values
+      of the dummy blocks to match the last real block's DC value.
+      This squeezes a few more bytes out of the resulting file... }
+
+    if (coef^.iMCU_row_num = last_iMCU_row) then
+    begin
+      Inc(blocks_across, ndummy);       { include lower right corner }
+      MCUs_across := blocks_across div JDIMENSION(h_samp_factor);
+      for block_row := block_rows to pred(compptr^.v_samp_factor) do
+      begin
+  thisblockrow := buffer^[block_row];
+  lastblockrow := buffer^[block_row-1];
+  jzero_far({FAR} pointer(thisblockrow),
+      size_t(blocks_across * SIZEOF(JBLOCK)));
+  for MCUindex := 0 to pred(MCUs_across) do
+        begin
+    lastDC := lastblockrow^[h_samp_factor-1][0];
+    for bi := 0 to pred(h_samp_factor) do
+          begin
+      thisblockrow^[bi][0] := lastDC;
+    end;
+    Inc(JBLOCK_PTR(thisblockrow), h_samp_factor); { advance to next MCU in row }
+    Inc(JBLOCK_PTR(lastblockrow), h_samp_factor);
+  end;
+      end;
+    end;
+    Inc(compptr);
+  end;
+  { NB: compress_output will increment iMCU_row_num if successful.
+    A suspension return will result in redoing all the work above next time.}
+
+
+  { Emit data to the entropy encoder, sharing code with subsequent passes }
+  compress_first_pass := compress_output(cinfo, input_buf);
+end;
+
+
+{ Process some data in subsequent passes of a multi-pass case.
+  We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+  per call, ie, v_samp_factor block rows for each component in the scan.
+  The data is obtained from the virtual arrays and fed to the entropy coder.
+  Returns TRUE if the iMCU row is completed, FALSE if suspended.
+
+  NB: input_buf is ignored; it is likely to be a NIL pointer. }
+
+{METHODDEF}
+function compress_output (cinfo : j_compress_ptr;
+                          input_buf : JSAMPIMAGE) : boolean;
+var
+  coef : my_coef_ptr;
+  MCU_col_num : JDIMENSION; { index of current MCU within row }
+  blkn, ci, xindex, yindex, yoffset : int;
+  start_col : JDIMENSION;
+  buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY;
+  buffer_ptr : JBLOCKROW;
+  compptr : jpeg_component_info_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+
+  { Align the virtual buffers for the components used in this scan.
+    NB: during first pass, this is safe only because the buffers will
+    already be aligned properly, so jmemmgr.c won't need to do any I/O. }
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    buffer[ci] := cinfo^.mem^.access_virt_barray (
+       j_common_ptr(cinfo), coef^.whole_image[compptr^.component_index],
+       coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor),
+       JDIMENSION (compptr^.v_samp_factor), FALSE);
+  end;
+
+  { Loop to process one whole iMCU row }
+  for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
+  begin
+    for MCU_col_num := coef^.mcu_ctr to pred(cinfo^.MCUs_per_row) do
+    begin
+      { Construct list of pointers to DCT blocks belonging to this MCU }
+      blkn := 0;      { index of current DCT block within MCU }
+      for ci := 0 to pred(cinfo^.comps_in_scan) do
+      begin
+  compptr := cinfo^.cur_comp_info[ci];
+  start_col := MCU_col_num * JDIMENSION(compptr^.MCU_width);
+  for yindex := 0 to pred(compptr^.MCU_height) do
+        begin
+    buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]);
+    for xindex := 0 to pred(compptr^.MCU_width) do
+          begin
+      coef^.MCU_buffer[blkn] := buffer_ptr;
+      Inc(blkn);
+            Inc(JBLOCK_PTR(buffer_ptr));
+    end;
+  end;
+      end;
+      { Try to write the MCU. }
+      if (not cinfo^.entropy^.encode_mcu (cinfo, coef^.MCU_buffer)) then
+      begin
+  { Suspension forced; update state counters and exit }
+  coef^.MCU_vert_offset := yoffset;
+  coef^.mcu_ctr := MCU_col_num;
+  compress_output := FALSE;
+        exit;
+      end;
+    end;
+    { Completed an MCU row, but perhaps not an iMCU row }
+    coef^.mcu_ctr := 0;
+  end;
+  { Completed the iMCU row, advance counters for next one }
+  Inc(coef^.iMCU_row_num);
+  start_iMCU_row(cinfo);
+  compress_output := TRUE;
+end;
+
+{$endif} { FULL_COEF_BUFFER_SUPPORTED }
+
+
+{ Initialize coefficient buffer controller. }
+
+{GLOBAL}
+procedure jinit_c_coef_controller (cinfo : j_compress_ptr;
+                                   need_full_buffer : boolean);
+var
+  coef : my_coef_ptr;
+var
+  buffer : JBLOCKROW;
+  i : int;
+var
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  coef := my_coef_ptr (
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_coef_controller)) );
+  cinfo^.coef := jpeg_c_coef_controller_ptr(coef);
+  coef^.pub.start_pass := start_pass_coef;
+
+  { Create the coefficient buffer. }
+  if (need_full_buffer) then
+  begin
+{$ifdef FULL_COEF_BUFFER_SUPPORTED}
+    { Allocate a full-image virtual array for each component, }
+    { padded to a multiple of samp_factor DCT blocks in each direction. }
+
+    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      coef^.whole_image[ci] := cinfo^.mem^.request_virt_barray
+  (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
+   JDIMENSION (jround_up( long (compptr^.width_in_blocks),
+        long (compptr^.h_samp_factor) )),
+   JDIMENSION (jround_up(long (compptr^.height_in_blocks),
+        long (compptr^.v_samp_factor))),
+   JDIMENSION (compptr^.v_samp_factor));
+      Inc(compptr);
+    end;
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+{$endif}
+  end
+  else
+  begin
+    { We only need a single-MCU buffer. }
+    buffer := JBLOCKROW (
+      cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE,
+          C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) );
+    for i := 0 to pred(C_MAX_BLOCKS_IN_MCU) do
+    begin
+      coef^.MCU_buffer[i] := JBLOCKROW(@ buffer^[i]);
+    end;
+    coef^.whole_image[0] := NIL; { flag for no virtual arrays }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjccolor.pas b/src/lib/vampimg/JpegLib/imjccolor.pas
new file mode 100644 (file)
index 0000000..09fb8af
--- /dev/null
@@ -0,0 +1,530 @@
+unit imjccolor;
+
+{  This file contains input colorspace conversion routines. }
+
+{ Original : jccolor.c ;  Copyright (C) 1991-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib;
+
+{ Module initialization routine for input colorspace conversion. }
+
+{GLOBAL}
+procedure jinit_color_converter (cinfo : j_compress_ptr);
+
+implementation
+
+{ Private subobject }
+type
+  INT32_FIELD = array[0..MaxInt div SizeOf(INT32) - 1] of INT32;
+  INT32_FIELD_PTR = ^INT32_FIELD;
+
+type
+  my_cconvert_ptr = ^my_color_converter;
+  my_color_converter = record
+    pub : jpeg_color_converter; { public fields }
+
+    { Private state for RGB -> YCC conversion }
+    rgb_ycc_tab : INT32_FIELD_PTR;  { => table for RGB to YCbCr conversion }
+  end; {my_color_converter;}
+
+
+{*************** RGB -> YCbCr conversion: most common case *************}
+
+{
+  YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+  normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+  The conversion equations to be implemented are therefore
+  Y  =  0.29900 * R + 0.58700 * G + 0.11400 * B
+  Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B  + CENTERJSAMPLE
+  Cr =  0.50000 * R - 0.41869 * G - 0.08131 * B  + CENTERJSAMPLE
+  (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+  Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
+  rather than CENTERJSAMPLE, for Cb and Cr.  This gave equal positive and
+  negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
+  were not represented exactly.  Now we sacrifice exact representation of
+  maximum red and maximum blue in order to get exact grayscales.
+
+  To avoid floating-point arithmetic, we represent the fractional constants
+  as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+  the products by 2^16, with appropriate rounding, to get the correct answer.
+
+  For even more speed, we avoid doing any multiplications in the inner loop
+  by precalculating the constants times R,G,B for all possible values.
+  For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+  for 12-bit samples it is still acceptable.  It's not very reasonable for
+  16-bit samples, but if you want lossless storage you shouldn't be changing
+  colorspace anyway.
+  The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
+  in the tables to save adding them separately in the inner loop. }
+const
+  SCALEBITS   =  16;  { speediest right-shift on some machines }
+  CBCR_OFFSET = INT32(CENTERJSAMPLE shl SCALEBITS);
+  ONE_HALF    = INT32(1) shl (SCALEBITS-1);
+
+
+{ We allocate one big table and divide it up into eight parts, instead of
+  doing eight alloc_small requests.  This lets us use a single table base
+  address, which can be held in a register in the inner loops on many
+  machines (more than can hold all eight addresses, anyway). }
+
+  R_Y_OFF     = 0;                              { offset to R => Y section }
+  G_Y_OFF     = 1*(MAXJSAMPLE+1);               { offset to G => Y section }
+  B_Y_OFF     = 2*(MAXJSAMPLE+1);               { etc. }
+  R_CB_OFF    = 3*(MAXJSAMPLE+1);
+  G_CB_OFF    = 4*(MAXJSAMPLE+1);
+  B_CB_OFF    = 5*(MAXJSAMPLE+1);
+  R_CR_OFF    = B_CB_OFF;                       { B=>Cb, R=>Cr are the same }
+  G_CR_OFF    = 6*(MAXJSAMPLE+1);
+  B_CR_OFF    = 7*(MAXJSAMPLE+1);
+  TABLE_SIZE  = 8*(MAXJSAMPLE+1);
+
+
+{ Initialize for RGB->YCC colorspace conversion. }
+
+{METHODDEF}
+procedure rgb_ycc_start (cinfo : j_compress_ptr);
+const
+  FIX_0_29900 = INT32(Round(0.29900 * (1 shl SCALEBITS)));
+  FIX_0_58700 = INT32(Round(0.58700 * (1 shl SCALEBITS)));
+  FIX_0_11400 = INT32(Round(0.11400 * (1 shl SCALEBITS)));
+  FIX_0_16874 = INT32(Round(0.16874 * (1 shl SCALEBITS)));
+  FIX_0_33126 = INT32(Round(0.33126 * (1 shl SCALEBITS)));
+  FIX_0_50000 = INT32(Round(0.50000 * (1 shl SCALEBITS)));
+  FIX_0_41869 = INT32(Round(0.41869 * (1 shl SCALEBITS)));
+  FIX_0_08131 = INT32(Round(0.08131 * (1 shl SCALEBITS)));
+var
+  cconvert : my_cconvert_ptr;
+  rgb_ycc_tab : INT32_FIELD_PTR;
+  i : INT32;
+begin
+  cconvert := my_cconvert_ptr (cinfo^.cconvert);
+
+  { Allocate and fill in the conversion tables. }
+  rgb_ycc_tab := INT32_FIELD_PTR(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        (TABLE_SIZE * SIZEOF(INT32))) );
+  cconvert^.rgb_ycc_tab := rgb_ycc_tab;
+
+  for i := 0 to MAXJSAMPLE do
+  begin
+    rgb_ycc_tab^[i+R_Y_OFF] := FIX_0_29900 * i;
+    rgb_ycc_tab^[i+G_Y_OFF] := FIX_0_58700 * i;
+    rgb_ycc_tab^[i+B_Y_OFF] := FIX_0_11400 * i     + ONE_HALF;
+    rgb_ycc_tab^[i+R_CB_OFF] := (-FIX_0_16874) * i;
+    rgb_ycc_tab^[i+G_CB_OFF] := (-FIX_0_33126) * i;
+    { We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
+      This ensures that the maximum output will round to MAXJSAMPLE
+      not MAXJSAMPLE+1, and thus that we don't have to range-limit. }
+
+    rgb_ycc_tab^[i+B_CB_OFF] := FIX_0_50000 * i    + CBCR_OFFSET + ONE_HALF-1;
+{  B=>Cb and R=>Cr tables are the same
+    rgb_ycc_tab^[i+R_CR_OFF] := FIX_0_50000 * i    + CBCR_OFFSET + ONE_HALF-1;
+}
+    rgb_ycc_tab^[i+G_CR_OFF] := (-FIX_0_41869) * i;
+    rgb_ycc_tab^[i+B_CR_OFF] := (-FIX_0_08131) * i;
+  end;
+end;
+
+
+{ Convert some rows of samples to the JPEG colorspace.
+
+  Note that we change from the application's interleaved-pixel format
+  to our internal noninterleaved, one-plane-per-component format.
+  The input buffer is therefore three times as wide as the output buffer.
+
+  A starting row offset is provided only for the output buffer.  The caller
+  can easily adjust the passed input_buf value to accommodate any row
+  offset required on that side. }
+
+{METHODDEF}
+procedure rgb_ycc_convert (cinfo : j_compress_ptr;
+               input_buf : JSAMPARRAY;
+                           output_buf :  JSAMPIMAGE;
+               output_row : JDIMENSION;
+                           num_rows : int);
+var
+  cconvert : my_cconvert_ptr;
+  {register} r, g, b : int;
+  {register} ctab : INT32_FIELD_PTR;
+  {register} inptr : JSAMPROW;
+  {register} outptr0, outptr1, outptr2 : JSAMPROW;
+  {register} col : JDIMENSION;
+  num_cols : JDIMENSION;
+begin
+  cconvert := my_cconvert_ptr (cinfo^.cconvert);
+  ctab := cconvert^.rgb_ycc_tab;
+  num_cols := cinfo^.image_width;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    inptr := input_buf^[0];
+    Inc(JSAMPROW_PTR(input_buf));
+    outptr0 := output_buf^[0]^[output_row];
+    outptr1 := output_buf^[1]^[output_row];
+    outptr2 := output_buf^[2]^[output_row];
+    Inc(output_row);
+    for col := 0 to pred(num_cols) do
+    begin
+      r := GETJSAMPLE(inptr^[RGB_RED]);
+      g := GETJSAMPLE(inptr^[RGB_GREEN]);
+      b := GETJSAMPLE(inptr^[RGB_BLUE]);
+      Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE);
+      { If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+        must be too; we do not need an explicit range-limiting operation.
+        Hence the value being shifted is never negative, and we don't
+        need the general RIGHT_SHIFT macro. }
+
+      { Y }
+      outptr0^[col] := JSAMPLE(
+    ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF])
+     shr SCALEBITS) );
+      { Cb }
+      outptr1^[col] := JSAMPLE(
+    ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF])
+     shr SCALEBITS) );
+      { Cr }
+      outptr2^[col] := JSAMPLE(
+    ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF])
+     shr SCALEBITS) );
+    end;
+  end;
+end;
+
+
+{*************** Cases other than RGB -> YCbCr *************}
+
+
+{ Convert some rows of samples to the JPEG colorspace.
+  This version handles RGB -> grayscale conversion, which is the same
+  as the RGB -> Y portion of RGB -> YCbCr.
+  We assume rgb_ycc_start has been called (we only use the Y tables). }
+
+{METHODDEF}
+procedure rgb_gray_convert (cinfo : j_compress_ptr;
+                input_buf : JSAMPARRAY;
+                            output_buf : JSAMPIMAGE;
+                output_row : JDIMENSION;
+                            num_rows : int);
+var
+  cconvert : my_cconvert_ptr;
+  {register} r, g, b : int;
+  {register} ctab :INT32_FIELD_PTR;
+  {register} inptr : JSAMPROW;
+  {register} outptr : JSAMPROW;
+  {register} col : JDIMENSION;
+  num_cols : JDIMENSION;
+begin
+  cconvert := my_cconvert_ptr (cinfo^.cconvert);
+  ctab := cconvert^.rgb_ycc_tab;
+  num_cols := cinfo^.image_width;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    inptr := input_buf[0];
+    Inc(JSAMPROW_PTR(input_buf));
+    outptr := output_buf[0][output_row];
+    Inc(output_row);
+    for col := 0 to num_cols - 1 do
+    begin
+      r := GETJSAMPLE(inptr[RGB_RED]);
+      g := GETJSAMPLE(inptr[RGB_GREEN]);
+      b := GETJSAMPLE(inptr[RGB_BLUE]);
+      Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE);
+      (* Y *)
+      // kylix 3 compiler crashes on this
+      // it also crashes Delphi OSX compiler 9 years later :(
+      {$IF not (Defined(DCC) and not Defined(MSWINDOWS))}
+      outptr[col] := JSAMPLE(((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) shr SCALEBITS));
+      {$IFEND}
+    end;
+  end;
+end;
+
+
+{ Convert some rows of samples to the JPEG colorspace.
+  This version handles Adobe-style CMYK -> YCCK conversion,
+  where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
+  conversion as above, while passing K (black) unchanged.
+  We assume rgb_ycc_start has been called. }
+
+{METHODDEF}
+procedure cmyk_ycck_convert (cinfo : j_compress_ptr;
+                 input_buf : JSAMPARRAY;
+                             output_buf : JSAMPIMAGE;
+                 output_row : JDIMENSION;
+                             num_rows : int);
+var
+  cconvert : my_cconvert_ptr;
+  {register} r, g, b : int;
+  {register} ctab : INT32_FIELD_PTR;
+  {register} inptr : JSAMPROW;
+  {register} outptr0, outptr1, outptr2, outptr3 : JSAMPROW;
+  {register} col : JDIMENSION;
+  num_cols : JDIMENSION;
+begin
+  cconvert := my_cconvert_ptr (cinfo^.cconvert);
+  ctab := cconvert^.rgb_ycc_tab;
+  num_cols := cinfo^.image_width;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    inptr := input_buf^[0];
+    Inc(JSAMPROW_PTR(input_buf));
+    outptr0 := output_buf^[0]^[output_row];
+    outptr1 := output_buf^[1]^[output_row];
+    outptr2 := output_buf^[2]^[output_row];
+    outptr3 := output_buf^[3]^[output_row];
+    Inc(output_row);
+    for col := 0 to pred(num_cols) do
+    begin
+      r := MAXJSAMPLE - GETJSAMPLE(inptr^[0]);
+      g := MAXJSAMPLE - GETJSAMPLE(inptr^[1]);
+      b := MAXJSAMPLE - GETJSAMPLE(inptr^[2]);
+      { K passes through as-is }
+      outptr3^[col] := inptr^[3]; { don't need GETJSAMPLE here }
+      Inc(JSAMPLE_PTR(inptr), 4);
+      { If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+        must be too; we do not need an explicit range-limiting operation.
+        Hence the value being shifted is never negative, and we don't
+        need the general RIGHT_SHIFT macro. }
+
+      { Y }
+      outptr0^[col] := JSAMPLE (
+    ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF])
+     shr SCALEBITS) );
+      { Cb }
+      outptr1^[col] := JSAMPLE(
+    ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF])
+     shr SCALEBITS) );
+      { Cr }
+      outptr2^[col] := JSAMPLE (
+    ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF])
+     shr SCALEBITS) );
+    end;
+  end;
+end;
+
+
+{ Convert some rows of samples to the JPEG colorspace.
+  This version handles grayscale output with no conversion.
+  The source can be either plain grayscale or YCbCr (since Y = gray). }
+
+{METHODDEF}
+procedure grayscale_convert (cinfo : j_compress_ptr;
+                            input_buf : JSAMPARRAY;
+                            output_buf : JSAMPIMAGE;
+                            output_row : JDIMENSION;
+                            num_rows: int);
+var
+  {register} inptr : JSAMPROW;
+  {register} outptr : JSAMPROW;
+  {register} col : JDIMENSION;
+  num_cols :JDIMENSION;
+  instride : int;
+begin
+  num_cols := cinfo^.image_width;
+  instride := cinfo^.input_components;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    inptr := input_buf^[0];
+    Inc(JSAMPROW_PTR(input_buf));
+    outptr := output_buf^[0]^[output_row];
+    Inc(output_row);
+    for col := 0 to pred(num_cols) do
+    begin
+      outptr^[col] := inptr^[0];  { don't need GETJSAMPLE() here }
+      Inc(JSAMPLE_PTR(inptr), instride);
+    end;
+  end;
+end;
+
+
+{ Convert some rows of samples to the JPEG colorspace.
+  This version handles multi-component colorspaces without conversion.
+  We assume input_components = num_components. }
+
+{METHODDEF}
+procedure null_convert (cinfo : j_compress_ptr;
+                  input_buf : JSAMPARRAY;
+                        output_buf : JSAMPIMAGE;
+                        output_row : JDIMENSION;
+                        num_rows : int);
+var
+  {register} inptr : JSAMPROW;
+  {register} outptr : JSAMPROW;
+  {register} col : JDIMENSION;
+  {register} ci : int;
+  nc : int;
+  num_cols : JDIMENSION;
+begin
+  nc := cinfo^.num_components;
+  num_cols := cinfo^.image_width;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    { It seems fastest to make a separate pass for each component. }
+    for ci := 0 to pred(nc) do
+    begin
+      inptr := input_buf^[0];
+      outptr := output_buf^[ci]^[output_row];
+      for col := 0 to pred(num_cols) do
+      begin
+  outptr^[col] := inptr^[ci]; { don't need GETJSAMPLE() here }
+  Inc(JSAMPLE_PTR(inptr), nc);
+      end;
+    end;
+    Inc(JSAMPROW_PTR(input_buf));
+    Inc(output_row);
+  end;
+end;
+
+
+{ Empty method for start_pass. }
+
+{METHODDEF}
+procedure null_method (cinfo : j_compress_ptr);
+begin
+  { no work needed }
+end;
+
+
+{ Module initialization routine for input colorspace conversion. }
+
+{GLOBAL}
+procedure jinit_color_converter (cinfo : j_compress_ptr);
+var
+  cconvert : my_cconvert_ptr;
+begin
+  cconvert := my_cconvert_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_color_converter)) );
+  cinfo^.cconvert := jpeg_color_converter_ptr(cconvert);
+  { set start_pass to null method until we find out differently }
+  cconvert^.pub.start_pass := null_method;
+
+  { Make sure input_components agrees with in_color_space }
+  case (cinfo^.in_color_space) of
+  JCS_GRAYSCALE:
+    if (cinfo^.input_components <> 1) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
+
+{$ifdef RGB_PIXELSIZE <> 3}
+  JCS_RGB:
+    if (cinfo^.input_components <> RGB_PIXELSIZE) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
+{$else} { share code with YCbCr }
+  JCS_RGB,
+{$endif}
+  JCS_YCbCr:
+    if (cinfo^.input_components <> 3) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
+
+  JCS_CMYK,
+  JCS_YCCK:
+    if (cinfo^.input_components <> 4) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
+
+  else      { JCS_UNKNOWN can be anything }
+    if (cinfo^.input_components < 1) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
+  end;
+
+  { Check num_components, set conversion method based on requested space }
+  case (cinfo^.jpeg_color_space) of
+  JCS_GRAYSCALE:
+    begin
+      if (cinfo^.num_components <> 1) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+      if (cinfo^.in_color_space = JCS_GRAYSCALE) then
+        cconvert^.pub.color_convert := grayscale_convert
+      else
+        if (cinfo^.in_color_space = JCS_RGB) then
+        begin
+          cconvert^.pub.start_pass := rgb_ycc_start;
+          cconvert^.pub.color_convert := rgb_gray_convert;
+        end
+        else
+          if (cinfo^.in_color_space = JCS_YCbCr) then
+            cconvert^.pub.color_convert := grayscale_convert
+          else
+            ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  JCS_RGB:
+    begin
+      if (cinfo^.num_components <> 3) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+        if (cinfo^.in_color_space = JCS_RGB) and (RGB_PIXELSIZE = 3) then
+          cconvert^.pub.color_convert := null_convert
+        else
+          ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  JCS_YCbCr:
+    begin
+      if (cinfo^.num_components <> 3) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+      if (cinfo^.in_color_space = JCS_RGB) then
+      begin
+        cconvert^.pub.start_pass := rgb_ycc_start;
+        cconvert^.pub.color_convert := rgb_ycc_convert;
+      end
+      else
+        if (cinfo^.in_color_space = JCS_YCbCr) then
+          cconvert^.pub.color_convert := null_convert
+        else
+          ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  JCS_CMYK:
+    begin
+      if (cinfo^.num_components <> 4) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+      if (cinfo^.in_color_space = JCS_CMYK) then
+        cconvert^.pub.color_convert := null_convert
+      else
+        ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  JCS_YCCK:
+    begin
+      if (cinfo^.num_components <> 4) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+      if (cinfo^.in_color_space = JCS_CMYK) then
+      begin
+        cconvert^.pub.start_pass := rgb_ycc_start;
+        cconvert^.pub.color_convert := cmyk_ycck_convert;
+      end
+      else
+        if (cinfo^.in_color_space = JCS_YCCK) then
+          cconvert^.pub.color_convert := null_convert
+        else
+          ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  else    { allow null conversion of JCS_UNKNOWN }
+    begin
+      if (cinfo^.jpeg_color_space <> cinfo^.in_color_space) or
+   (cinfo^.num_components <> cinfo^.input_components) then
+        ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+      cconvert^.pub.color_convert := null_convert;
+    end;
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcdctmgr.pas b/src/lib/vampimg/JpegLib/imjcdctmgr.pas
new file mode 100644 (file)
index 0000000..f63569e
--- /dev/null
@@ -0,0 +1,514 @@
+unit imjcdctmgr;
+
+{ Original : jcdctmgr.c ;  Copyright (C) 1994-1996, Thomas G. Lane. }
+
+{ This file is part of the Independent JPEG Group's software.
+  For conditions of distribution and use, see the accompanying README file.
+
+  This file contains the forward-DCT management logic.
+  This code selects a particular DCT implementation to be used,
+  and it performs related housekeeping chores including coefficient
+  quantization. }
+
+interface
+
+{$N+}
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib,
+  imjdct,                 { Private declarations for DCT subsystem }
+  imjfdctint, imjfdctfst, imjfdctflt;
+
+{ Initialize FDCT manager. }
+
+{GLOBAL}
+procedure jinit_forward_dct (cinfo : j_compress_ptr);
+
+implementation
+
+
+{ Private subobject for this module }
+
+type
+  my_fdct_ptr = ^my_fdct_controller;
+  my_fdct_controller = record
+    pub : jpeg_forward_dct; { public fields }
+
+    { Pointer to the DCT routine actually in use }
+    do_dct : forward_DCT_method_ptr;
+
+    { The actual post-DCT divisors --- not identical to the quant table
+      entries, because of scaling (especially for an unnormalized DCT).
+      Each table is given in normal array order. }
+
+    divisors : array[0..NUM_QUANT_TBLS-1] of DCTELEM_FIELD_PTR;
+
+  {$ifdef DCT_FLOAT_SUPPORTED}
+    { Same as above for the floating-point case. }
+    do_float_dct : float_DCT_method_ptr;
+    float_divisors : array[0..NUM_QUANT_TBLS-1] of FAST_FLOAT_FIELD_PTR;
+  {$endif}
+  end;
+
+
+{ Initialize for a processing pass.
+  Verify that all referenced Q-tables are present, and set up
+  the divisor table for each one.
+  In the current implementation, DCT of all components is done during
+  the first pass, even if only some components will be output in the
+  first scan.  Hence all components should be examined here. }
+
+{METHODDEF}
+procedure start_pass_fdctmgr (cinfo : j_compress_ptr);
+var
+  fdct : my_fdct_ptr;
+  ci, qtblno, i : int;
+  compptr : jpeg_component_info_ptr;
+  qtbl : JQUANT_TBL_PTR;
+  dtbl : DCTELEM_FIELD_PTR;
+{$ifdef DCT_IFAST_SUPPORTED}
+const
+  CONST_BITS = 14;
+  aanscales : array[0..DCTSIZE2-1] of INT16 =
+         ({ precomputed values scaled up by 14 bits }
+    16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+    22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
+    21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
+    19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
+    16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+    12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
+     8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
+     4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247);
+  {SHIFT_TEMPS}
+
+  { Descale and correctly round an INT32 value that's scaled by N bits.
+    We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+    the fudge factor is correct for either sign of X. }
+
+  function DESCALE(x : INT32; n : int) : INT32;
+  var
+    shift_temp : INT32;
+  begin
+    shift_temp := x + (INT32(1) shl (n-1));
+  {$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+    if shift_temp < 0 then
+      Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+    else
+  {$endif}
+      Descale :=  (shift_temp shr n);
+  end;
+
+{$endif}
+{$ifdef DCT_FLOAT_SUPPORTED}
+var
+  fdtbl : FAST_FLOAT_FIELD_PTR;
+  row, col : int;
+const
+  aanscalefactor : array[0..DCTSIZE-1] of double =
+    (1.0, 1.387039845, 1.306562965, 1.175875602,
+     1.0, 0.785694958, 0.541196100, 0.275899379);
+{$endif}
+begin
+  fdct := my_fdct_ptr (cinfo^.fdct);
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    qtblno := compptr^.quant_tbl_no;
+    { Make sure specified quantization table is present }
+    if (qtblno < 0) or (qtblno >= NUM_QUANT_TBLS) or
+       (cinfo^.quant_tbl_ptrs[qtblno] = NIL) then
+      ERREXIT1(j_common_ptr(cinfo), JERR_NO_QUANT_TABLE, qtblno);
+    qtbl := cinfo^.quant_tbl_ptrs[qtblno];
+    { Compute divisors for this quant table }
+    { We may do this more than once for same table, but it's not a big deal }
+    case (cinfo^.dct_method) of
+{$ifdef DCT_ISLOW_SUPPORTED}
+    JDCT_ISLOW:
+    begin
+      { For LL&M IDCT method, divisors are equal to raw quantization
+        coefficients multiplied by 8 (to counteract scaling). }
+
+      if (fdct^.divisors[qtblno] = NIL) then
+      begin
+  fdct^.divisors[qtblno] := DCTELEM_FIELD_PTR(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+              DCTSIZE2 * SIZEOF(DCTELEM)) );
+      end;
+      dtbl := fdct^.divisors[qtblno];
+      for i := 0 to pred(DCTSIZE2) do
+      begin
+  dtbl^[i] := (DCTELEM(qtbl^.quantval[i])) shl 3;
+      end;
+    end;
+{$endif}
+{$ifdef DCT_IFAST_SUPPORTED}
+    JDCT_IFAST:
+      begin
+        { For AA&N IDCT method, divisors are equal to quantization
+          coefficients scaled by scalefactor[row]*scalefactor[col], where
+            scalefactor[0] := 1
+            scalefactor[k] := cos(k*PI/16) * sqrt(2)    for k=1..7
+          We apply a further scale factor of 8. }
+
+
+  if (fdct^.divisors[qtblno] = NIL) then
+        begin
+    fdct^.divisors[qtblno] := DCTELEM_FIELD_PTR(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          DCTSIZE2 * SIZEOF(DCTELEM)) );
+  end;
+  dtbl := fdct^.divisors[qtblno];
+  for i := 0 to pred(DCTSIZE2) do
+        begin
+    dtbl^[i] := DCTELEM(
+                     {MULTIPLY16V16}
+      DESCALE( INT32(qtbl^.quantval[i]) * INT32 (aanscales[i]),
+         CONST_BITS-3) );
+  end;
+      end;
+{$endif}
+{$ifdef DCT_FLOAT_SUPPORTED}
+
+    JDCT_FLOAT:
+      begin
+  { For float AA&N IDCT method, divisors are equal to quantization
+    coefficients scaled by scalefactor[row]*scalefactor[col], where
+      scalefactor[0] := 1
+      scalefactor[k] := cos(k*PI/16) * sqrt(2)    for k=1..7
+    We apply a further scale factor of 8.
+    What's actually stored is 1/divisor so that the inner loop can
+    use a multiplication rather than a division. }
+
+  if (fdct^.float_divisors[qtblno] = NIL) then
+        begin
+    fdct^.float_divisors[qtblno] := FAST_FLOAT_FIELD_PTR(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          DCTSIZE2 * SIZEOF(FAST_FLOAT)) );
+  end;
+  fdtbl := fdct^.float_divisors[qtblno];
+  i := 0;
+  for row := 0 to pred(DCTSIZE) do
+        begin
+    for col := 0 to pred(DCTSIZE) do
+          begin
+      fdtbl^[i] := {FAST_FLOAT}
+        (1.0 / (( {double}(qtbl^.quantval[i]) *
+           aanscalefactor[row] * aanscalefactor[col] * 8.0)));
+      Inc(i);
+    end;
+  end;
+      end;
+{$endif}
+    else
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+    end;
+    Inc(compptr);
+  end;
+end;
+
+
+{ Perform forward DCT on one or more blocks of a component.
+
+  The input samples are taken from the sample_data[] array starting at
+  position start_row/start_col, and moving to the right for any additional
+  blocks. The quantized coefficients are returned in coef_blocks[]. }
+
+{METHODDEF}
+procedure forward_DCT (cinfo : j_compress_ptr;
+                       compptr : jpeg_component_info_ptr;
+                 sample_data : JSAMPARRAY;
+                       coef_blocks : JBLOCKROW;
+                 start_row : JDIMENSION;
+                       start_col : JDIMENSION;
+                 num_blocks : JDIMENSION);
+{ This version is used for integer DCT implementations. }
+var
+  { This routine is heavily used, so it's worth coding it tightly. }
+  fdct : my_fdct_ptr;
+  do_dct : forward_DCT_method_ptr;
+  divisors : DCTELEM_FIELD_PTR;
+  workspace : array[0..DCTSIZE2-1] of DCTELEM;  { work area for FDCT subroutine }
+  bi : JDIMENSION;
+var
+  {register} workspaceptr : DCTELEMPTR;
+  {register} elemptr : JSAMPLE_PTR;
+  {register} elemr : int;
+{$ifndef DCTSIZE_IS_8}
+var
+  {register} elemc : int;
+{$endif}
+var
+  {register} temp, qval : DCTELEM;
+  {register} i : int;
+  {register} output_ptr : JCOEFPTR;
+begin
+  fdct := my_fdct_ptr (cinfo^.fdct);
+  do_dct := fdct^.do_dct;
+  divisors := fdct^.divisors[compptr^.quant_tbl_no];
+
+  Inc(JSAMPROW_PTR(sample_data), start_row);  { fold in the vertical offset once }
+
+  for bi := 0 to pred(num_blocks) do
+  begin
+
+    { Load data into workspace, applying unsigned->signed conversion }
+
+    workspaceptr := @workspace[0];
+    for elemr := 0 to pred(DCTSIZE) do
+    begin
+      elemptr := @sample_data^[elemr]^[start_col];
+{$ifdef DCTSIZE_IS_8}   { unroll the inner loop }
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+      Inc(workspaceptr);
+      {Inc(elemptr);       - Value never used }
+{$else}
+      for elemc := pred(DCTSIZE) downto 0 do
+      begin
+        workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE;
+        Inc(workspaceptr);
+        Inc(elemptr);
+      end;
+{$endif}
+    end;
+
+    { Perform the DCT }
+    do_dct (workspace);
+
+    { Quantize/descale the coefficients, and store into coef_blocks[] }
+
+    output_ptr := JCOEFPTR(@coef_blocks^[bi]);
+    for i := 0 to pred(DCTSIZE2) do
+    begin
+      qval := divisors^[i];
+      temp := workspace[i];
+      { Divide the coefficient value by qval, ensuring proper rounding.
+  Since C does not specify the direction of rounding for negative
+  quotients, we have to force the dividend positive for portability.
+
+  In most files, at least half of the output values will be zero
+  (at default quantization settings, more like three-quarters...)
+  so we should ensure that this case is fast.  On many machines,
+  a comparison is enough cheaper than a divide to make a special test
+  a win.  Since both inputs will be nonnegative, we need only test
+  for a < b to discover whether a/b is 0.
+  If your machine's division is fast enough, define FAST_DIVIDE. }
+
+      if (temp < 0) then
+      begin
+  temp := -temp;
+  Inc(temp, qval shr 1);  { for rounding }
+        {DIVIDE_BY(temp, qval);}
+        {$ifdef FAST_DIVIDE}
+          temp := temp div qval;
+        {$else}
+          if (temp >= qval) then
+            temp := temp div qval
+          else
+            temp := 0;
+        {$endif}
+  temp := -temp;
+      end
+      else
+      begin
+  Inc(temp, qval shr 1);  { for rounding }
+        {DIVIDE_BY(temp, qval);}
+        {$ifdef FAST_DIVIDE}
+          temp := temp div qval;
+        {$else}
+          if (temp >= qval) then
+            temp := temp div qval
+          else
+            temp := 0;
+        {$endif}
+      end;
+      output_ptr^[i] := JCOEF (temp);
+    end;
+    Inc(start_col, DCTSIZE);
+  end;
+end;
+
+
+{$ifdef DCT_FLOAT_SUPPORTED}
+
+{METHODDEF}
+procedure forward_DCT_float (cinfo : j_compress_ptr;
+                             compptr : jpeg_component_info_ptr;
+                 sample_data : JSAMPARRAY;
+                             coef_blocks : JBLOCKROW;
+                 start_row : JDIMENSION;
+                             start_col : JDIMENSION;
+                 num_blocks : JDIMENSION);
+{ This version is used for floating-point DCT implementations. }
+var
+  { This routine is heavily used, so it's worth coding it tightly. }
+  fdct : my_fdct_ptr;
+  do_dct : float_DCT_method_ptr;
+  divisors : FAST_FLOAT_FIELD_PTR;
+  workspace : array[0..DCTSIZE2-1] of FAST_FLOAT; { work area for FDCT subroutine }
+  bi : JDIMENSION;
+var
+  {register} workspaceptr : FAST_FLOAT_PTR;
+  {register} elemptr : JSAMPLE_PTR;
+  {register} elemr : int;
+{$ifndef DCTSIZE_IS_8}
+var
+  {register} elemc : int;
+{$endif}
+var
+  {register} temp : FAST_FLOAT;
+  {register} i : int;
+  {register} output_ptr : JCOEFPTR;
+begin
+  fdct := my_fdct_ptr (cinfo^.fdct);
+  do_dct := fdct^.do_float_dct;
+  divisors := fdct^.float_divisors[compptr^.quant_tbl_no];
+
+  Inc(JSAMPROW_PTR(sample_data), start_row);  { fold in the vertical offset once }
+
+  for bi := 0 to pred(num_blocks) do
+  begin
+    { Load data into workspace, applying unsigned->signed conversion }
+
+    workspaceptr := @workspace[0];
+    for elemr := 0 to pred(DCTSIZE) do
+    begin
+      elemptr := @(sample_data^[elemr]^[start_col]);
+{$ifdef DCTSIZE_IS_8}   { unroll the inner loop }
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      Inc(elemptr);
+      workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE);
+      Inc(workspaceptr);
+      {Inc(elemptr);         - value never used }
+{$else}
+      for elemc := pred(DCTSIZE) downto 0 do
+      begin
+  workspaceptr^ := {FAST_FLOAT}(
+    (GETJSAMPLE(elemptr^) - CENTERJSAMPLE) );
+        Inc(workspaceptr);
+        Inc(elemptr);
+      end;
+{$endif}
+    end;
+
+
+    { Perform the DCT }
+    do_dct (workspace);
+
+    { Quantize/descale the coefficients, and store into coef_blocks[] }
+
+    output_ptr := JCOEFPTR(@(coef_blocks^[bi]));
+
+    for i := 0 to pred(DCTSIZE2) do
+    begin
+      { Apply the quantization and scaling factor }
+      temp := workspace[i] * divisors^[i];
+      { Round to nearest integer.
+  Since C does not specify the direction of rounding for negative
+  quotients, we have to force the dividend positive for portability.
+  The maximum coefficient size is +-16K (for 12-bit data), so this
+  code should work for either 16-bit or 32-bit ints. }
+      output_ptr^[i] := JCOEF ( int(Trunc (temp + {FAST_FLOAT}(16384.5))) - 16384);
+    end;
+    Inc(start_col, DCTSIZE);
+  end;
+end;
+
+{$endif} { DCT_FLOAT_SUPPORTED }
+
+
+{ Initialize FDCT manager. }
+
+{GLOBAL}
+procedure jinit_forward_dct (cinfo : j_compress_ptr);
+var
+  fdct : my_fdct_ptr;
+  i : int;
+begin
+  fdct := my_fdct_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_fdct_controller)) );
+  cinfo^.fdct := jpeg_forward_dct_ptr (fdct);
+  fdct^.pub.start_pass := start_pass_fdctmgr;
+
+  case (cinfo^.dct_method) of
+{$ifdef DCT_ISLOW_SUPPORTED}
+  JDCT_ISLOW:
+    begin
+      fdct^.pub.forward_DCT := forward_DCT;
+      fdct^.do_dct := jpeg_fdct_islow;
+    end;
+{$endif}
+{$ifdef DCT_IFAST_SUPPORTED}
+  JDCT_IFAST:
+    begin
+      fdct^.pub.forward_DCT := forward_DCT;
+      fdct^.do_dct := jpeg_fdct_ifast;
+    end;
+{$endif}
+{$ifdef DCT_FLOAT_SUPPORTED}
+  JDCT_FLOAT:
+    begin
+      fdct^.pub.forward_DCT := forward_DCT_float;
+      fdct^.do_float_dct := jpeg_fdct_float;
+    end;
+{$endif}
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+  end;
+
+  { Mark divisor tables unallocated }
+  for i := 0 to pred(NUM_QUANT_TBLS) do
+  begin
+    fdct^.divisors[i] := NIL;
+{$ifdef DCT_FLOAT_SUPPORTED}
+    fdct^.float_divisors[i] := NIL;
+{$endif}
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjchuff.pas b/src/lib/vampimg/JpegLib/imjchuff.pas
new file mode 100644 (file)
index 0000000..66856dc
--- /dev/null
@@ -0,0 +1,1116 @@
+unit imjchuff;
+
+{ This file contains Huffman entropy encoding routines.
+
+  Much of the complexity here has to do with supporting output suspension.
+  If the data destination module demands suspension, we want to be able to
+  back up to the start of the current MCU.  To do this, we copy state
+  variables into local working storage, and update them back to the
+  permanent JPEG objects only upon successful completion of an MCU. }
+
+{ Original: jchuff.c; Copyright (C) 1991-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg, { longptr definition missing }
+  imjpeglib,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjinclude,
+  imjcomapi;
+
+{ The legal range of a DCT coefficient is
+   -1024 .. +1023  for 8-bit data;
+  -16384 .. +16383 for 12-bit data.
+  Hence the magnitude should always fit in 10 or 14 bits respectively. }
+
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  MAX_COEF_BITS = 10;
+{$else}
+const
+  MAX_COEF_BITS = 14;
+{$endif}
+
+{ Derived data constructed for each Huffman table }
+{ Declarations shared with jcphuff.c }
+type
+  c_derived_tbl_ptr = ^c_derived_tbl;
+  c_derived_tbl = record
+    ehufco : array[0..256-1] of uInt; { code for each symbol }
+    ehufsi : array[0..256-1] of byte;   { length of code for each symbol }
+    { If no code has been allocated for a symbol S, ehufsi[S] contains 0 }
+  end;
+{ for JCHUFF und JCPHUFF }
+type
+  TLongTable = array[0..256] of long;
+  TLongTablePtr = ^TLongTable;
+
+{ Compute the derived values for a Huffman table.
+  Note this is also used by jcphuff.c. }
+
+{GLOBAL}
+procedure jpeg_make_c_derived_tbl (cinfo : j_compress_ptr;
+                                   isDC : boolean;
+                                   tblno : int;
+                 var pdtbl : c_derived_tbl_ptr);
+
+{ Generate the optimal coding for the given counts, fill htbl.
+  Note this is also used by jcphuff.c. }
+
+{GLOBAL}
+procedure jpeg_gen_optimal_table (cinfo : j_compress_ptr;
+                                  htbl : JHUFF_TBL_PTR;
+                                  var freq : TLongTable);  { Nomssi }
+
+{ Module initialization routine for Huffman entropy encoding. }
+
+{GLOBAL}
+procedure jinit_huff_encoder (cinfo : j_compress_ptr);
+
+implementation
+
+{ Expanded entropy encoder object for Huffman encoding.
+
+  The savable_state subrecord contains fields that change within an MCU,
+  but must not be updated permanently until we complete the MCU. }
+
+type
+  savable_state = record
+    put_buffer : INT32;   { current bit-accumulation buffer }
+    put_bits : int;   { # of bits now in it }
+    last_dc_val : array[0..MAX_COMPS_IN_SCAN-1] of int;
+                                { last DC coef for each component }
+  end;
+
+
+type
+  huff_entropy_ptr = ^huff_entropy_encoder;
+  huff_entropy_encoder = record
+    pub : jpeg_entropy_encoder; { public fields }
+
+    saved : savable_state;  { Bit buffer & DC state at start of MCU }
+
+    { These fields are NOT loaded into local working state. }
+    restarts_to_go : uInt;  { MCUs left in this restart interval }
+    next_restart_num : int; { next restart number to write (0-7) }
+
+    { Pointers to derived tables (these workspaces have image lifespan) }
+    dc_derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr;
+    ac_derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr;
+
+  {$ifdef ENTROPY_OPT_SUPPORTED} { Statistics tables for optimization }
+    dc_count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr;
+    ac_count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr;
+  {$endif}
+  end;
+
+
+
+{ Working state while writing an MCU.
+  This struct contains all the fields that are needed by subroutines. }
+
+type
+  working_state = record
+    next_output_byte : JOCTETptr; { => next byte to write in buffer }
+    free_in_buffer : size_t;    { # of byte spaces remaining in buffer }
+    cur : savable_state;    { Current bit buffer & DC state }
+    cinfo : j_compress_ptr;   { dump_buffer needs access to this }
+  end;
+
+
+{ Forward declarations }
+{METHODDEF}
+function encode_mcu_huff (cinfo : j_compress_ptr;
+                          const MCU_data : array of JBLOCKROW) : boolean;
+                          forward;
+{METHODDEF}
+procedure finish_pass_huff (cinfo : j_compress_ptr); forward;
+{$ifdef ENTROPY_OPT_SUPPORTED}
+{METHODDEF}
+function encode_mcu_gather (cinfo : j_compress_ptr;
+                            const MCU_data: array of JBLOCKROW) : boolean;
+                            forward;
+
+{METHODDEF}
+procedure finish_pass_gather (cinfo : j_compress_ptr); forward;
+{$endif}
+
+
+{ Initialize for a Huffman-compressed scan.
+  If gather_statistics is TRUE, we do not output anything during the scan,
+  just count the Huffman symbols used and generate Huffman code tables. }
+
+{METHODDEF}
+procedure start_pass_huff (cinfo : j_compress_ptr;
+                           gather_statistics : boolean);
+var
+  entropy : huff_entropy_ptr;
+  ci, dctbl, actbl : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+
+  if (gather_statistics) then
+  begin
+{$ifdef ENTROPY_OPT_SUPPORTED}
+    entropy^.pub.encode_mcu := encode_mcu_gather;
+    entropy^.pub.finish_pass := finish_pass_gather;
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+  end
+  else
+  begin
+    entropy^.pub.encode_mcu := encode_mcu_huff;
+    entropy^.pub.finish_pass := finish_pass_huff;
+  end;
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    dctbl := compptr^.dc_tbl_no;
+    actbl := compptr^.ac_tbl_no;
+    if (gather_statistics) then
+    begin
+{$ifdef ENTROPY_OPT_SUPPORTED}
+      { Check for invalid table indexes }
+      { (make_c_derived_tbl does this in the other path) }
+      if (dctbl < 0) or (dctbl >= NUM_HUFF_TBLS) then
+  ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, dctbl);
+      if (actbl < 0) or (actbl >= NUM_HUFF_TBLS) then
+  ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, actbl);
+      { Allocate and zero the statistics tables }
+      { Note that jpeg_gen_optimal_table expects 257 entries in each table! }
+      if (entropy^.dc_count_ptrs[dctbl] = NIL) then
+  entropy^.dc_count_ptrs[dctbl] := TLongTablePtr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+              257 * SIZEOF(long)) );
+      MEMZERO(entropy^.dc_count_ptrs[dctbl], 257 * SIZEOF(long));
+      if (entropy^.ac_count_ptrs[actbl] = NIL) then
+  entropy^.ac_count_ptrs[actbl] := TLongTablePtr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+              257 * SIZEOF(long)) );
+      MEMZERO(entropy^.ac_count_ptrs[actbl], 257 * SIZEOF(long));
+{$endif}
+    end
+    else
+    begin
+      { Compute derived values for Huffman tables }
+      { We may do this more than once for a table, but it's not expensive }
+      jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl,
+            entropy^.dc_derived_tbls[dctbl]);
+      jpeg_make_c_derived_tbl(cinfo, FALSE, actbl,
+            entropy^.ac_derived_tbls[actbl]);
+    end;
+    { Initialize DC predictions to 0 }
+    entropy^.saved.last_dc_val[ci] := 0;
+  end;
+
+  { Initialize bit buffer to empty }
+  entropy^.saved.put_buffer := 0;
+  entropy^.saved.put_bits := 0;
+
+  { Initialize restart stuff }
+  entropy^.restarts_to_go := cinfo^.restart_interval;
+  entropy^.next_restart_num := 0;
+end;
+
+
+{ Compute the derived values for a Huffman table.
+  This routine also performs some validation checks on the table.
+
+  Note this is also used by jcphuff.c. }
+
+{GLOBAL}
+procedure jpeg_make_c_derived_tbl (cinfo : j_compress_ptr;
+                                   isDC : boolean;
+                                   tblno : int;
+                 var pdtbl : c_derived_tbl_ptr);
+var
+  htbl : JHUFF_TBL_PTR;
+  dtbl : c_derived_tbl_ptr;
+  p, i, l, lastp, si, maxsymbol : int;
+  huffsize : array[0..257-1] of byte;
+  huffcode : array[0..257-1] of uInt;
+  code : uInt;
+begin
+  { Note that huffsize[] and huffcode[] are filled in code-length order,
+    paralleling the order of the symbols themselves in htbl->huffval[]. }
+
+  { Find the input Huffman table }
+  if (tblno < 0) or (tblno >= NUM_HUFF_TBLS) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno);
+  if isDC then
+    htbl := cinfo^.dc_huff_tbl_ptrs[tblno]
+  else
+    htbl := cinfo^.ac_huff_tbl_ptrs[tblno];
+  if (htbl = NIL) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno);
+
+  { Allocate a workspace if we haven't already done so. }
+  if (pdtbl = NIL) then
+    pdtbl := c_derived_tbl_ptr(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          SIZEOF(c_derived_tbl)) );
+  dtbl := pdtbl;
+
+  { Figure C.1: make table of Huffman code length for each symbol }
+
+  p := 0;
+  for l := 1 to 16 do
+  begin
+    i := int(htbl^.bits[l]);
+    if (i < 0) and (p + i > 256) then { protect against table overrun }
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+    while (i > 0) do
+    begin
+      huffsize[p] := byte(l);
+      Inc(p);
+      Dec(i);
+    end;
+  end;
+  huffsize[p] := 0;
+  lastp := p;
+
+  { Figure C.2: generate the codes themselves }
+  { We also validate that the counts represent a legal Huffman code tree. }
+
+  code := 0;
+  si := huffsize[0];
+  p := 0;
+  while (huffsize[p] <> 0) do
+  begin
+    while (( int(huffsize[p]) ) = si) do
+    begin
+      huffcode[p] := code;
+      Inc(p);
+      Inc(code);
+    end;
+    { code is now 1 more than the last code used for codelength si; but
+      it must still fit in si bits, since no code is allowed to be all ones. }
+
+    if (INT32(code) >= (INT32(1) shl si)) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+    code := code shl 1;
+    Inc(si);
+  end;
+
+  { Figure C.3: generate encoding tables }
+  { These are code and size indexed by symbol value }
+
+  { Set all codeless symbols to have code length 0;
+    this lets us detect duplicate VAL entries here, and later
+    allows emit_bits to detect any attempt to emit such symbols. }
+
+  MEMZERO(@dtbl^.ehufsi, SIZEOF(dtbl^.ehufsi));
+
+  { This is also a convenient place to check for out-of-range
+    and duplicated VAL entries.  We allow 0..255 for AC symbols
+    but only 0..15 for DC.  (We could constrain them further
+    based on data depth and mode, but this seems enough.) }
+
+  if isDC then
+    maxsymbol := 15
+  else
+    maxsymbol := 255;
+
+  for p := 0 to pred(lastp) do
+  begin
+    i := htbl^.huffval[p];
+    if (i < 0) or (i > maxsymbol) or (dtbl^.ehufsi[i] <> 0) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+    dtbl^.ehufco[i] := huffcode[p];
+    dtbl^.ehufsi[i] := huffsize[p];
+  end;
+end;
+
+
+{ Outputting bytes to the file }
+
+
+{LOCAL}
+function dump_buffer (var state : working_state) : boolean;
+{ Empty the output buffer; return TRUE if successful, FALSE if must suspend }
+var
+  dest : jpeg_destination_mgr_ptr;
+begin
+  dest := state.cinfo^.dest;
+
+  if (not dest^.empty_output_buffer (state.cinfo)) then
+  begin
+    dump_buffer := FALSE;
+    exit;
+  end;
+  { After a successful buffer dump, must reset buffer pointers }
+  state.next_output_byte := dest^.next_output_byte;
+  state.free_in_buffer := dest^.free_in_buffer;
+  dump_buffer := TRUE;
+end;
+
+
+{ Outputting bits to the file }
+
+{ Only the right 24 bits of put_buffer are used; the valid bits are
+  left-justified in this part.  At most 16 bits can be passed to emit_bits
+  in one call, and we never retain more than 7 bits in put_buffer
+  between calls, so 24 bits are sufficient. }
+
+
+{LOCAL}
+function emit_bits (var state : working_state;
+                    code : uInt;
+                    size : int) : boolean;  {INLINE}
+{ Emit some bits; return TRUE if successful, FALSE if must suspend }
+var
+  { This routine is heavily used, so it's worth coding tightly. }
+  {register} put_buffer : INT32;
+  {register} put_bits : int;
+var
+  c : int;
+begin
+  put_buffer := INT32 (code);
+  put_bits := state.cur.put_bits;
+
+  { if size is 0, caller used an invalid Huffman table entry }
+  if (size = 0) then
+    ERREXIT(j_common_ptr(state.cinfo), JERR_HUFF_MISSING_CODE);
+
+  put_buffer := put_buffer and pred(INT32(1) shl size);
+                { mask off any extra bits in code }
+
+  Inc(put_bits, size);          { new number of bits in buffer }
+
+  put_buffer := put_buffer shl (24 - put_bits);
+                                { align incoming bits }
+  put_buffer := put_buffer or state.cur.put_buffer;
+                                { and merge with old buffer contents }
+  while (put_bits >= 8) do
+  begin
+    c := int ((put_buffer shr 16) and $FF);
+
+    {emit_byte(state, c, return FALSE);}
+    { Emit a byte, return FALSE if must suspend. }
+    state.next_output_byte^ := JOCTET (c);
+    Inc(state.next_output_byte);
+    Dec(state.free_in_buffer);
+    if (state.free_in_buffer = 0) then
+      if not dump_buffer(state) then
+      begin
+        emit_bits := FALSE;
+        exit;
+      end;
+
+    if (c = $FF) then          { need to stuff a zero byte? }
+    begin
+      {emit_byte(state, 0, return FALSE);}
+      state.next_output_byte^ := JOCTET (0);
+      Inc(state.next_output_byte);
+      Dec(state.free_in_buffer);
+      if (state.free_in_buffer = 0) then
+  if not dump_buffer(state) then
+  begin
+          emit_bits := FALSE;
+          exit;
+        end;
+
+    end;
+    put_buffer := put_buffer shl 8;
+    Dec(put_bits, 8);
+  end;
+
+  state.cur.put_buffer := put_buffer; { update state variables }
+  state.cur.put_bits := put_bits;
+
+  emit_bits := TRUE;
+end;
+
+
+{LOCAL}
+function flush_bits (var state : working_state) : boolean;
+begin
+  if (not emit_bits(state, $7F, 7)) then { fill any partial byte with ones }
+  begin
+    flush_bits := FALSE;
+    exit;
+  end;
+  state.cur.put_buffer := 0;  { and reset bit-buffer to empty }
+  state.cur.put_bits := 0;
+  flush_bits := TRUE;
+end;
+
+
+{ Encode a single block's worth of coefficients }
+
+{LOCAL}
+function encode_one_block (var state : working_state;
+                           const block : JBLOCK;
+                           last_dc_val : int;
+                           dctbl : c_derived_tbl_ptr;
+                           actbl : c_derived_tbl_ptr) : boolean;
+var
+  {register} temp, temp2 : int;
+  {register} nbits : int;
+  {register} k, r, i : int;
+begin
+  { Encode the DC coefficient difference per section F.1.2.1 }
+
+  temp2 := block[0] - last_dc_val;
+  temp := temp2;
+
+  if (temp < 0) then
+  begin
+    temp := -temp;    { temp is abs value of input }
+    { For a negative input, want temp2 := bitwise complement of abs(input) }
+    { This code assumes we are on a two's complement machine }
+    Dec(temp2);
+  end;
+
+  { Find the number of bits needed for the magnitude of the coefficient }
+  nbits := 0;
+  while (temp <> 0) do
+  begin
+    Inc(nbits);
+    temp := temp shr 1;
+  end;
+
+  { Check for out-of-range coefficient values.
+    Since we're encoding a difference, the range limit is twice as much. }
+
+  if (nbits > MAX_COEF_BITS+1) then
+    ERREXIT(j_common_ptr(state.cinfo), JERR_BAD_DCT_COEF);
+
+  { Emit the Huffman-coded symbol for the number of bits }
+  if not emit_bits(state, dctbl^.ehufco[nbits], dctbl^.ehufsi[nbits]) then
+  begin
+    encode_one_block := FALSE;
+    exit;
+  end;
+
+  { Emit that number of bits of the value, if positive, }
+  { or the complement of its magnitude, if negative. }
+  if (nbits <> 0) then              { emit_bits rejects calls with size 0 }
+    if not emit_bits(state, uInt(temp2), nbits) then
+    begin
+      encode_one_block := FALSE;
+      exit;
+    end;
+
+  { Encode the AC coefficients per section F.1.2.2 }
+
+  r := 0;     { r := run length of zeros }
+
+  for k := 1 to pred(DCTSIZE2) do
+  begin
+    temp := block[jpeg_natural_order[k]];
+    if (temp = 0) then
+    begin
+      Inc(r);
+    end
+    else
+    begin
+      { if run length > 15, must emit special run-length-16 codes ($F0) }
+      while (r > 15) do
+      begin
+  if not emit_bits(state, actbl^.ehufco[$F0], actbl^.ehufsi[$F0]) then
+        begin
+          encode_one_block := FALSE;
+          exit;
+        end;
+  Dec(r, 16);
+      end;
+
+      temp2 := temp;
+      if (temp < 0) then
+      begin
+  temp := -temp;    { temp is abs value of input }
+  { This code assumes we are on a two's complement machine }
+  Dec(temp2);
+      end;
+
+      { Find the number of bits needed for the magnitude of the coefficient }
+      nbits := 0;   { there must be at least one 1 bit }
+      repeat
+  Inc(nbits);
+        temp := temp shr 1;
+      until (temp = 0);
+
+      { Check for out-of-range coefficient values }
+      if (nbits > MAX_COEF_BITS) then
+  ERREXIT(j_common_ptr(state.cinfo), JERR_BAD_DCT_COEF);
+
+      { Emit Huffman symbol for run length / number of bits }
+      i := (r shl 4) + nbits;
+      if not emit_bits(state, actbl^.ehufco[i], actbl^.ehufsi[i]) then
+      begin
+        encode_one_block := FALSE;
+        exit;
+      end;
+
+      { Emit that number of bits of the value, if positive, }
+      { or the complement of its magnitude, if negative. }
+      if not emit_bits(state, uInt(temp2), nbits) then
+      begin
+        encode_one_block := FALSE;
+        exit;
+      end;
+
+      r := 0;
+    end;
+  end;
+
+  { If the last coef(s) were zero, emit an end-of-block code }
+  if (r > 0) then
+    if not emit_bits(state, actbl^.ehufco[0], actbl^.ehufsi[0]) then
+    begin
+      encode_one_block := FALSE;
+      exit;
+    end;
+
+  encode_one_block := TRUE;
+end;
+
+
+{ Emit a restart marker & resynchronize predictions. }
+
+{LOCAL}
+function emit_restart (var state : working_state;
+                       restart_num : int) : boolean;
+var
+  ci : int;
+begin
+  if (not flush_bits(state)) then
+  begin
+    emit_restart  := FALSE;
+    exit;
+  end;
+
+  {emit_byte(state, $FF, return FALSE);}
+  { Emit a byte, return FALSE if must suspend. }
+  state.next_output_byte^ := JOCTET ($FF);
+  Inc(state.next_output_byte);
+  Dec(state.free_in_buffer);
+  if (state.free_in_buffer = 0) then
+    if not dump_buffer(state) then
+    begin
+      emit_restart := FALSE;
+      exit;
+    end;
+
+  {emit_byte(state, JPEG_RST0 + restart_num, return FALSE);}
+  { Emit a byte, return FALSE if must suspend. }
+  state.next_output_byte^ := JOCTET (JPEG_RST0 + restart_num);
+  Inc(state.next_output_byte);
+  Dec(state.free_in_buffer);
+  if (state.free_in_buffer = 0) then
+    if not dump_buffer(state) then
+    begin
+      emit_restart := FALSE;
+      exit;
+    end;
+
+  { Re-initialize DC predictions to 0 }
+  for ci := 0 to pred(state.cinfo^.comps_in_scan) do
+    state.cur.last_dc_val[ci] := 0;
+
+  { The restart counter is not updated until we successfully write the MCU. }
+
+  emit_restart := TRUE;
+end;
+
+
+{ Encode and output one MCU's worth of Huffman-compressed coefficients. }
+
+{METHODDEF}
+function encode_mcu_huff (cinfo : j_compress_ptr;
+                          const MCU_data: array of JBLOCKROW) : boolean;
+var
+  entropy : huff_entropy_ptr;
+  state : working_state;
+  blkn, ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+  { Load up working state }
+  state.next_output_byte := cinfo^.dest^.next_output_byte;
+  state.free_in_buffer := cinfo^.dest^.free_in_buffer;
+  {ASSIGN_STATE(state.cur, entropy^.saved);}
+  state.cur := entropy^.saved;
+  state.cinfo := cinfo;
+
+  { Emit restart marker if needed }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+      if not emit_restart(state, entropy^.next_restart_num) then
+      begin
+  encode_mcu_huff := FALSE;
+        exit;
+      end;
+  end;
+
+  { Encode the MCU data blocks }
+  for blkn := 0  to pred(cinfo^.blocks_in_MCU) do
+  begin
+    ci := cinfo^.MCU_membership[blkn];
+    compptr := cinfo^.cur_comp_info[ci];
+    if not encode_one_block(state,
+                            MCU_data[blkn]^[0],
+                            state.cur.last_dc_val[ci],
+                            entropy^.dc_derived_tbls[compptr^.dc_tbl_no],
+                            entropy^.ac_derived_tbls[compptr^.ac_tbl_no]) then
+    begin
+      encode_mcu_huff := FALSE;
+      exit;
+    end;
+    { Update last_dc_val }
+    state.cur.last_dc_val[ci] := MCU_data[blkn]^[0][0];
+  end;
+
+  { Completed MCU, so update state }
+  cinfo^.dest^.next_output_byte := state.next_output_byte;
+  cinfo^.dest^.free_in_buffer := state.free_in_buffer;
+  {ASSIGN_STATE(entropy^.saved, state.cur);}
+  entropy^.saved := state.cur;
+
+  { Update restart-interval state too }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+    begin
+      entropy^.restarts_to_go := cinfo^.restart_interval;
+      Inc(entropy^.next_restart_num);
+      with entropy^ do
+        next_restart_num := next_restart_num and 7;
+    end;
+    Dec(entropy^.restarts_to_go);
+  end;
+
+  encode_mcu_huff := TRUE;
+end;
+
+
+{ Finish up at the end of a Huffman-compressed scan. }
+
+{METHODDEF}
+procedure finish_pass_huff (cinfo : j_compress_ptr);
+var
+  entropy : huff_entropy_ptr;
+  state : working_state;
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+
+  { Load up working state ... flush_bits needs it }
+  state.next_output_byte := cinfo^.dest^.next_output_byte;
+  state.free_in_buffer := cinfo^.dest^.free_in_buffer;
+  {ASSIGN_STATE(state.cur, entropy^.saved);}
+  state.cur := entropy^.saved;
+  state.cinfo := cinfo;
+
+  { Flush out the last data }
+  if not flush_bits(state) then
+    ERREXIT(j_common_ptr(cinfo), JERR_CANT_SUSPEND);
+
+  { Update state }
+  cinfo^.dest^.next_output_byte := state.next_output_byte;
+  cinfo^.dest^.free_in_buffer := state.free_in_buffer;
+  {ASSIGN_STATE(entropy^.saved, state.cur);}
+  entropy^.saved := state.cur;
+end;
+
+
+{ Huffman coding optimization.
+
+  We first scan the supplied data and count the number of uses of each symbol
+  that is to be Huffman-coded. (This process MUST agree with the code above.)
+  Then we build a Huffman coding tree for the observed counts.
+  Symbols which are not needed at all for the particular image are not
+  assigned any code, which saves space in the DHT marker as well as in
+  the compressed data. }
+
+{$ifdef ENTROPY_OPT_SUPPORTED}
+
+
+{ Process a single block's worth of coefficients }
+
+{LOCAL}
+procedure htest_one_block (cinfo : j_compress_ptr;
+                           const block : JBLOCK;
+                           last_dc_val : int;
+               dc_counts : TLongTablePtr;
+                           ac_counts : TLongTablePtr);
+
+var
+  {register} temp : int;
+  {register} nbits : int;
+  {register} k, r : int;
+begin
+  { Encode the DC coefficient difference per section F.1.2.1 }
+  temp := block[0] - last_dc_val;
+  if (temp < 0) then
+    temp := -temp;
+
+  { Find the number of bits needed for the magnitude of the coefficient }
+  nbits := 0;
+  while (temp <> 0) do
+  begin
+    Inc(nbits);
+    temp := temp shr 1;
+  end;
+
+  { Check for out-of-range coefficient values.
+    Since we're encoding a difference, the range limit is twice as much. }
+
+  if (nbits > MAX_COEF_BITS+1) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_DCT_COEF);
+
+  { Count the Huffman symbol for the number of bits }
+  Inc(dc_counts^[nbits]);
+
+  { Encode the AC coefficients per section F.1.2.2 }
+
+  r := 0;     { r := run length of zeros }
+
+  for k := 1 to pred(DCTSIZE2) do
+  begin
+    temp := block[jpeg_natural_order[k]];
+    if (temp = 0) then
+    begin
+      Inc(r);
+    end
+    else
+    begin
+      { if run length > 15, must emit special run-length-16 codes ($F0) }
+      while (r > 15) do
+      begin
+  Inc(ac_counts^[$F0]);
+  Dec(r, 16);
+      end;
+
+      { Find the number of bits needed for the magnitude of the coefficient }
+      if (temp < 0) then
+  temp := -temp;
+
+      { Find the number of bits needed for the magnitude of the coefficient }
+      nbits := 0;   { there must be at least one 1 bit }
+      repeat
+        Inc(nbits);
+        temp := temp shr 1;
+      until (temp = 0);
+
+
+      { Count Huffman symbol for run length / number of bits }
+      Inc(ac_counts^[(r shl 4) + nbits]);
+
+      r := 0;
+    end;
+  end;
+
+  { If the last coef(s) were zero, emit an end-of-block code }
+  if (r > 0) then
+    Inc(ac_counts^[0]);
+end;
+
+
+{ Trial-encode one MCU's worth of Huffman-compressed coefficients.
+  No data is actually output, so no suspension return is possible. }
+
+{METHODDEF}
+function encode_mcu_gather (cinfo : j_compress_ptr;
+                           const MCU_data: array of JBLOCKROW) : boolean;
+var
+  entropy : huff_entropy_ptr;
+  blkn, ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+  { Take care of restart intervals if needed }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+    begin
+      { Re-initialize DC predictions to 0 }
+      for ci := 0 to pred(cinfo^.comps_in_scan) do
+  entropy^.saved.last_dc_val[ci] := 0;
+      { Update restart state }
+      entropy^.restarts_to_go := cinfo^.restart_interval;
+    end;
+    Dec(entropy^.restarts_to_go);
+  end;
+
+  for blkn := 0 to pred(cinfo^.blocks_in_MCU) do
+  begin
+    ci := cinfo^.MCU_membership[blkn];
+    compptr := cinfo^.cur_comp_info[ci];
+    htest_one_block(cinfo, MCU_data[blkn]^[0],
+                    entropy^.saved.last_dc_val[ci],
+                    entropy^.dc_count_ptrs[compptr^.dc_tbl_no],
+        entropy^.ac_count_ptrs[compptr^.ac_tbl_no]);
+    entropy^.saved.last_dc_val[ci] := MCU_data[blkn]^[0][0];
+  end;
+
+  encode_mcu_gather := TRUE;
+end;
+
+
+{ Generate the best Huffman code table for the given counts, fill htbl.
+  Note this is also used by jcphuff.c.
+
+  The JPEG standard requires that no symbol be assigned a codeword of all
+  one bits (so that padding bits added at the end of a compressed segment
+  can't look like a valid code).  Because of the canonical ordering of
+  codewords, this just means that there must be an unused slot in the
+  longest codeword length category.  Section K.2 of the JPEG spec suggests
+  reserving such a slot by pretending that symbol 256 is a valid symbol
+  with count 1.  In theory that's not optimal; giving it count zero but
+  including it in the symbol set anyway should give a better Huffman code.
+  But the theoretically better code actually seems to come out worse in
+  practice, because it produces more all-ones bytes (which incur stuffed
+  zero bytes in the final file).  In any case the difference is tiny.
+
+  The JPEG standard requires Huffman codes to be no more than 16 bits long.
+  If some symbols have a very small but nonzero probability, the Huffman tree
+  must be adjusted to meet the code length restriction.  We currently use
+  the adjustment method suggested in JPEG section K.2.  This method is *not*
+  optimal; it may not choose the best possible limited-length code.  But
+  typically only very-low-frequency symbols will be given less-than-optimal
+  lengths, so the code is almost optimal.  Experimental comparisons against
+  an optimal limited-length-code algorithm indicate that the difference is
+  microscopic --- usually less than a hundredth of a percent of total size.
+  So the extra complexity of an optimal algorithm doesn't seem worthwhile. }
+
+
+{GLOBAL}
+procedure jpeg_gen_optimal_table (cinfo : j_compress_ptr;
+                                  htbl : JHUFF_TBL_PTR;
+                                  var freq : TLongTable);
+const
+  MAX_CLEN = 32;    { assumed maximum initial code length }
+var
+  bits : array[0..MAX_CLEN+1-1] of UINT8;  { bits[k] := # of symbols with code length k }
+  codesize : array[0..257-1] of int;       { codesize[k] := code length of symbol k }
+  others : array[0..257-1] of int;         { next symbol in current branch of tree }
+  c1, c2 : int;
+  p, i, j : int;
+  v : long;
+begin
+  { This algorithm is explained in section K.2 of the JPEG standard }
+
+  MEMZERO(@bits, SIZEOF(bits));
+  MEMZERO(@codesize, SIZEOF(codesize));
+  for i := 0 to 256 do
+    others[i] := -1;    { init links to empty }
+
+  freq[256] := 1;   { make sure 256 has a nonzero count }
+  { Including the pseudo-symbol 256 in the Huffman procedure guarantees
+    that no real symbol is given code-value of all ones, because 256
+    will be placed last in the largest codeword category. }
+
+  { Huffman's basic algorithm to assign optimal code lengths to symbols }
+
+  while TRUE do
+  begin
+    { Find the smallest nonzero frequency, set c1 := its symbol }
+    { In case of ties, take the larger symbol number }
+    c1 := -1;
+    v := long(1000000000);
+    for i := 0 to 256 do
+    begin
+      if (freq[i] <> 0) and (freq[i] <= v) then
+      begin
+        v := freq[i];
+        c1 := i;
+      end;
+    end;
+
+    { Find the next smallest nonzero frequency, set c2 := its symbol }
+    { In case of ties, take the larger symbol number }
+    c2 := -1;
+    v := long(1000000000);
+    for i := 0 to 256 do
+    begin
+      if (freq[i] <> 0) and (freq[i] <= v) and (i <> c1) then
+      begin
+        v := freq[i];
+        c2 := i;
+      end;
+    end;
+
+    { Done if we've merged everything into one frequency }
+    if (c2 < 0) then
+      break;
+
+    { Else merge the two counts/trees }
+    Inc(freq[c1], freq[c2]);
+    freq[c2] := 0;
+
+    { Increment the codesize of everything in c1's tree branch }
+    Inc(codesize[c1]);
+    while (others[c1] >= 0) do
+    begin
+      c1 := others[c1];
+      Inc(codesize[c1]);
+    end;
+
+    others[c1] := c2;   { chain c2 onto c1's tree branch }
+
+    { Increment the codesize of everything in c2's tree branch }
+    Inc(codesize[c2]);
+    while (others[c2] >= 0) do
+    begin
+      c2 := others[c2];
+      Inc(codesize[c2]);
+    end;
+  end;
+
+  { Now count the number of symbols of each code length }
+  for i := 0 to 256 do
+  begin
+    if (codesize[i]<>0) then
+    begin
+      { The JPEG standard seems to think that this can't happen, }
+      { but I'm paranoid... }
+      if (codesize[i] > MAX_CLEN) then
+  ERREXIT(j_common_ptr(cinfo), JERR_HUFF_CLEN_OVERFLOW);
+
+      Inc(bits[codesize[i]]);
+    end;
+  end;
+
+  { JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
+    Huffman procedure assigned any such lengths, we must adjust the coding.
+    Here is what the JPEG spec says about how this next bit works:
+    Since symbols are paired for the longest Huffman code, the symbols are
+    removed from this length category two at a time.  The prefix for the pair
+    (which is one bit shorter) is allocated to one of the pair; then,
+    skipping the BITS entry for that prefix length, a code word from the next
+    shortest nonzero BITS entry is converted into a prefix for two code words
+    one bit longer.  }
+
+  for i := MAX_CLEN downto 17 do
+  begin
+    while (bits[i] > 0) do
+    begin
+      j := i - 2;               { find length of new prefix to be used }
+      while (bits[j] = 0) do
+        Dec(j);
+
+      Dec(bits[i], 2);          { remove two symbols }
+      Inc(bits[i-1]);           { one goes in this length }
+      Inc(bits[j+1], 2);        { two new symbols in this length }
+      Dec(bits[j]);   { symbol of this length is now a prefix }
+    end;
+  end;
+
+  { Delphi 2: FOR-loop variable 'i' may be undefined after loop }
+  i := 16;                      { Nomssi: work around }
+
+  { Remove the count for the pseudo-symbol 256 from the largest codelength }
+  while (bits[i] = 0) do        { find largest codelength still in use }
+    Dec(i);
+  Dec(bits[i]);
+
+  { Return final symbol counts (only for lengths 0..16) }
+  MEMCOPY(@htbl^.bits, @bits, SIZEOF(htbl^.bits));
+
+  { Return a list of the symbols sorted by code length }
+  { It's not real clear to me why we don't need to consider the codelength
+    changes made above, but the JPEG spec seems to think this works. }
+
+  p := 0;
+  for i := 1 to MAX_CLEN do
+  begin
+    for j := 0 to 255 do
+    begin
+      if (codesize[j] = i) then
+      begin
+  htbl^.huffval[p] := UINT8 (j);
+  Inc(p);
+      end;
+    end;
+  end;
+
+  { Set sent_table FALSE so updated table will be written to JPEG file. }
+  htbl^.sent_table := FALSE;
+end;
+
+
+{ Finish up a statistics-gathering pass and create the new Huffman tables. }
+
+{METHODDEF}
+procedure finish_pass_gather (cinfo : j_compress_ptr);
+var
+  entropy : huff_entropy_ptr;
+  ci, dctbl, actbl : int;
+  compptr : jpeg_component_info_ptr;
+  htblptr : ^JHUFF_TBL_PTR;
+  did_dc : array[0..NUM_HUFF_TBLS-1] of boolean;
+  did_ac : array[0..NUM_HUFF_TBLS-1] of boolean;
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+
+  { It's important not to apply jpeg_gen_optimal_table more than once
+    per table, because it clobbers the input frequency counts! }
+
+  MEMZERO(@did_dc, SIZEOF(did_dc));
+  MEMZERO(@did_ac, SIZEOF(did_ac));
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    dctbl := compptr^.dc_tbl_no;
+    actbl := compptr^.ac_tbl_no;
+    if (not did_dc[dctbl]) then
+    begin
+      htblptr := @(cinfo^.dc_huff_tbl_ptrs[dctbl]);
+      if ( htblptr^ = NIL) then
+  htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo));
+      jpeg_gen_optimal_table(cinfo, htblptr^, entropy^.dc_count_ptrs[dctbl]^);
+      did_dc[dctbl] := TRUE;
+    end;
+    if (not did_ac[actbl]) then
+    begin
+      htblptr := @(cinfo^.ac_huff_tbl_ptrs[actbl]);
+      if ( htblptr^ = NIL) then
+  htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo));
+      jpeg_gen_optimal_table(cinfo, htblptr^, entropy^.ac_count_ptrs[actbl]^);
+      did_ac[actbl] := TRUE;
+    end;
+  end;
+end;
+
+{$endif} { ENTROPY_OPT_SUPPORTED }
+
+
+{ Module initialization routine for Huffman entropy encoding. }
+
+{GLOBAL}
+procedure jinit_huff_encoder (cinfo : j_compress_ptr);
+var
+  entropy : huff_entropy_ptr;
+  i : int;
+begin
+  entropy := huff_entropy_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(huff_entropy_encoder)) );
+  cinfo^.entropy := jpeg_entropy_encoder_ptr (entropy);
+  entropy^.pub.start_pass := start_pass_huff;
+
+  { Mark tables unallocated }
+  for i := 0 to pred(NUM_HUFF_TBLS) do
+  begin
+    entropy^.ac_derived_tbls[i] := NIL;
+    entropy^.dc_derived_tbls[i] := NIL;
+{$ifdef ENTROPY_OPT_SUPPORTED}
+    entropy^.ac_count_ptrs[i] := NIL;
+    entropy^.dc_count_ptrs[i] := NIL;
+{$endif}
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcinit.pas b/src/lib/vampimg/JpegLib/imjcinit.pas
new file mode 100644 (file)
index 0000000..9adaee6
--- /dev/null
@@ -0,0 +1,95 @@
+unit imjcinit;
+
+{ Original: jcinit.c ;  Copyright (C) 1991-1997, Thomas G. Lane. }
+
+{ This file contains initialization logic for the JPEG compressor.
+  This routine is in charge of selecting the modules to be executed and
+  making an initialization call to each one.
+
+  Logically, this code belongs in jcmaster.c.  It's split out because
+  linking this routine implies linking the entire compression library.
+  For a transcoding-only application, we want to be able to use jcmaster.c
+  without linking in the whole library. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib,
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+  imjcphuff,
+{$endif}
+  imjchuff, imjcmaster, imjccolor, imjcsample, imjcprepct,
+  imjcdctmgr, imjccoefct, imjcmainct, imjcmarker;
+
+{ Master selection of compression modules.
+  This is done once at the start of processing an image.  We determine
+  which modules will be used and give them appropriate initialization calls. }
+
+{GLOBAL}
+procedure jinit_compress_master (cinfo : j_compress_ptr);
+
+implementation
+
+
+
+{ Master selection of compression modules.
+  This is done once at the start of processing an image.  We determine
+  which modules will be used and give them appropriate initialization calls. }
+
+{GLOBAL}
+procedure jinit_compress_master (cinfo : j_compress_ptr);
+begin
+  { Initialize master control (includes parameter checking/processing) }
+  jinit_c_master_control(cinfo, FALSE { full compression });
+
+  { Preprocessing }
+  if (not cinfo^.raw_data_in) then
+  begin
+    jinit_color_converter(cinfo);
+    jinit_downsampler(cinfo);
+    jinit_c_prep_controller(cinfo, FALSE { never need full buffer here });
+  end;
+  { Forward DCT }
+  jinit_forward_dct(cinfo);
+  { Entropy encoding: either Huffman or arithmetic coding. }
+  if (cinfo^.arith_code) then
+  begin
+    ERREXIT(j_common_ptr(cinfo), JERR_ARITH_NOTIMPL);
+  end
+  else
+  begin
+    if (cinfo^.progressive_mode) then
+    begin
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+      jinit_phuff_encoder(cinfo);
+{$else}
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+    end
+    else
+      jinit_huff_encoder(cinfo);
+  end;
+
+  { Need a full-image coefficient buffer in any multi-pass mode. }
+  jinit_c_coef_controller(cinfo,
+        (cinfo^.num_scans > 1) or (cinfo^.optimize_coding));
+  jinit_c_main_controller(cinfo, FALSE { never need full buffer here });
+
+  jinit_marker_writer(cinfo);
+
+  { We can now tell the memory manager to allocate virtual arrays. }
+  cinfo^.mem^.realize_virt_arrays (j_common_ptr(cinfo));
+
+  { Write the datastream header (SOI) immediately.
+    Frame and scan headers are postponed till later.
+    This lets application insert special markers after the SOI. }
+
+  cinfo^.marker^.write_file_header (cinfo);
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcmainct.pas b/src/lib/vampimg/JpegLib/imjcmainct.pas
new file mode 100644 (file)
index 0000000..983ac83
--- /dev/null
@@ -0,0 +1,343 @@
+unit imjcmainct;
+
+{ This file contains the main buffer controller for compression.
+  The main buffer lies between the pre-processor and the JPEG
+  compressor proper; it holds downsampled data in the JPEG colorspace. }
+
+{ Original : jcmainct.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+{ Note: currently, there is no operating mode in which a full-image buffer
+  is needed at this step.  If there were, that mode could not be used with
+  "raw data" input, since this module is bypassed in that case.  However,
+  we've left the code here for possible use in special applications. }
+
+{$undef FULL_MAIN_BUFFER_SUPPORTED}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+{$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+  imjutils,
+{$endif}
+  imjpeglib;
+
+{ Initialize main buffer controller. }
+
+{GLOBAL}
+procedure jinit_c_main_controller (cinfo : j_compress_ptr;
+                                   need_full_buffer : boolean);
+
+implementation
+
+
+{ Private buffer controller object }
+
+type
+  my_main_ptr = ^my_main_controller;
+  my_main_controller = record
+    pub : jpeg_c_main_controller; { public fields }
+
+    cur_iMCU_row : JDIMENSION;  { number of current iMCU row }
+    rowgroup_ctr : JDIMENSION;  { counts row groups received in iMCU row }
+    suspended : boolean;    { remember if we suspended output }
+    pass_mode : J_BUF_MODE;   { current operating mode }
+
+    { If using just a strip buffer, this points to the entire set of buffers
+      (we allocate one for each component).  In the full-image case, this
+      points to the currently accessible strips of the virtual arrays. }
+
+    buffer : array[0..MAX_COMPONENTS-1] of JSAMPARRAY;
+
+  {$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+    { If using full-image storage, this array holds pointers to virtual-array
+      control blocks for each component.  Unused if not full-image storage. }
+
+    whole_image : array[0..MAX_COMPONENTS-1] of jvirt_sarray_ptr;
+  {$endif}
+  end; {my_main_controller}
+
+
+{ Forward declarations }
+{METHODDEF}
+procedure process_data_simple_main(cinfo : j_compress_ptr;
+                                   input_buf : JSAMPARRAY;
+                                   var in_row_ctr: JDIMENSION;
+                                   in_rows_avail : JDIMENSION); forward;
+
+{$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+{METHODDEF}
+procedure process_data_buffer_main(cinfo : j_compress_ptr;
+                                   input_buf : JSAMPARRAY;
+                                   var in_row_ctr : JDIMENSION;
+                                   in_rows_avail : JDIMENSION); forward;
+{$endif}
+
+
+{ Initialize for a processing pass. }
+
+{METHODDEF}
+procedure start_pass_main (cinfo : j_compress_ptr;
+                           pass_mode : J_BUF_MODE);
+var
+  main : my_main_ptr;
+begin
+  main := my_main_ptr (cinfo^.main);
+
+  { Do nothing in raw-data mode. }
+  if (cinfo^.raw_data_in) then
+    exit;
+
+  main^.cur_iMCU_row := 0;  { initialize counters }
+  main^.rowgroup_ctr := 0;
+  main^.suspended := FALSE;
+  main^.pass_mode := pass_mode; { save mode for use by process_data }
+
+  case (pass_mode) of
+  JBUF_PASS_THRU:
+    begin
+{$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+      if (main^.whole_image[0] <> NIL) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+{$endif}
+      main^.pub.process_data := process_data_simple_main;
+    end;
+{$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+  JBUF_SAVE_SOURCE,
+  JBUF_CRANK_DEST,
+  JBUF_SAVE_AND_PASS:
+    begin
+      if (main^.whole_image[0] = NIL) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+      main^.pub.process_data := process_data_buffer_main;
+    end;
+{$endif}
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+  end;
+end;
+
+
+{ Process some data.
+  This routine handles the simple pass-through mode,
+  where we have only a strip buffer. }
+
+{METHODDEF}
+procedure process_data_simple_main (cinfo : j_compress_ptr;
+                  input_buf : JSAMPARRAY;
+                                    var in_row_ctr : JDIMENSION;
+                                    in_rows_avail : JDIMENSION);
+var
+  main : my_main_ptr;
+begin
+  main := my_main_ptr (cinfo^.main);
+
+  while (main^.cur_iMCU_row < cinfo^.total_iMCU_rows) do
+  begin
+    { Read input data if we haven't filled the main buffer yet }
+    if (main^.rowgroup_ctr < DCTSIZE) then
+      cinfo^.prep^.pre_process_data (cinfo,
+                                     input_buf,
+                                     in_row_ctr,
+                                     in_rows_avail,
+             JSAMPIMAGE(@main^.buffer),
+                                     main^.rowgroup_ctr,
+             JDIMENSION(DCTSIZE));
+
+    { If we don't have a full iMCU row buffered, return to application for
+      more data.  Note that preprocessor will always pad to fill the iMCU row
+      at the bottom of the image. }
+    if (main^.rowgroup_ctr <> DCTSIZE) then
+      exit;
+
+    { Send the completed row to the compressor }
+    if (not cinfo^.coef^.compress_data (cinfo, JSAMPIMAGE(@main^.buffer))) then
+    begin
+      { If compressor did not consume the whole row, then we must need to
+        suspend processing and return to the application.  In this situation
+        we pretend we didn't yet consume the last input row; otherwise, if
+        it happened to be the last row of the image, the application would
+        think we were done. }
+
+      if (not main^.suspended) then
+      begin
+  Dec(in_row_ctr);
+  main^.suspended := TRUE;
+      end;
+      exit;
+    end;
+    { We did finish the row.  Undo our little suspension hack if a previous
+      call suspended; then mark the main buffer empty. }
+
+    if (main^.suspended) then
+    begin
+      Inc(in_row_ctr);
+      main^.suspended := FALSE;
+    end;
+    main^.rowgroup_ctr := 0;
+    Inc(main^.cur_iMCU_row);
+  end;
+end;
+
+
+{$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+
+{ Process some data.
+  This routine handles all of the modes that use a full-size buffer. }
+
+{METHODDEF}
+procedure process_data_buffer_main (cinfo : j_compress_ptr;
+                  input_buf : JSAMPARRAY;
+                                    var in_row_ctr : JDIMENSION;
+                  in_rows_avail : JDIMENSION);
+var
+  main : my_main_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+  writing : boolean;
+begin
+  main := my_main_ptr (cinfo^.main);
+  writing := (main^.pass_mode <> JBUF_CRANK_DEST);
+
+  while (main^.cur_iMCU_row < cinfo^.total_iMCU_rows) do
+  begin
+    { Realign the virtual buffers if at the start of an iMCU row. }
+    if (main^.rowgroup_ctr = 0) then
+    begin
+      compptr := cinfo^.comp_info;
+      for ci := 0 to pred(cinfo^.num_components) do
+      begin
+  main^.buffer[ci] := cinfo^.mem^.access_virt_sarray
+    (j_common_ptr (cinfo), main^.whole_image[ci],
+     main^.cur_iMCU_row * (compptr^.v_samp_factor * DCTSIZE),
+     JDIMENSION (compptr^.v_samp_factor * DCTSIZE), writing);
+        Inc(compptr);
+      end;
+      { In a read pass, pretend we just read some source data. }
+      if (not writing) then
+      begin
+  Inc(in_row_ctr, cinfo^.max_v_samp_factor * DCTSIZE);
+  main^.rowgroup_ctr := DCTSIZE;
+      end;
+    end;
+
+    { If a write pass, read input data until the current iMCU row is full. }
+    { Note: preprocessor will pad if necessary to fill the last iMCU row. }
+    if (writing) then
+    begin
+      cinfo^.prep^.pre_process_data (cinfo,
+                                     input_buf, in_row_ctr, in_rows_avail,
+             JSAMPIMAGE(@main^.buffer),
+                                     main^.rowgroup_ctr,
+             JDIMENSION (DCTSIZE));
+
+      { Return to application if we need more data to fill the iMCU row. }
+      if (main^.rowgroup_ctr < DCTSIZE) then
+  exit;
+    end;
+
+    { Emit data, unless this is a sink-only pass. }
+    if (main^.pass_mode <> JBUF_SAVE_SOURCE) then
+    begin
+      if (not cinfo^.coef^.compress_data (cinfo,
+                                          JSAMPIMAGE(@main^.buffer))) then
+      begin
+  { If compressor did not consume the whole row, then we must need to
+    suspend processing and return to the application.  In this situation
+    we pretend we didn't yet consume the last input row; otherwise, if
+    it happened to be the last row of the image, the application would
+    think we were done. }
+
+  if (not main^.suspended) then
+        begin
+    Dec(in_row_ctr);
+    main^.suspended := TRUE;
+  end;
+  exit;
+      end;
+      { We did finish the row.  Undo our little suspension hack if a previous
+        call suspended; then mark the main buffer empty. }
+
+      if (main^.suspended) then
+      begin
+  Inc(in_row_ctr);
+  main^.suspended := FALSE;
+      end;
+    end;
+
+    { If get here, we are done with this iMCU row.  Mark buffer empty. }
+    main^.rowgroup_ctr := 0;
+    Inc(main^.cur_iMCU_row);
+  end;
+end;
+
+{$endif} { FULL_MAIN_BUFFER_SUPPORTED }
+
+
+{ Initialize main buffer controller. }
+
+{GLOBAL}
+procedure jinit_c_main_controller (cinfo : j_compress_ptr;
+                                   need_full_buffer : boolean);
+var
+  main : my_main_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  main := my_main_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_main_controller)) );
+  cinfo^.main := jpeg_c_main_controller_ptr(main);
+  main^.pub.start_pass := start_pass_main;
+
+  { We don't need to create a buffer in raw-data mode. }
+  if (cinfo^.raw_data_in) then
+    exit;
+
+  { Create the buffer.  It holds downsampled data, so each component
+    may be of a different size. }
+
+  if (need_full_buffer) then
+  begin
+{$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+    { Allocate a full-image virtual array for each component }
+    { Note we pad the bottom to a multiple of the iMCU height }
+    compptr := cinfo^.comp_info;
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      main^.whole_image[ci] := cinfo^.mem^.request_virt_sarray
+  (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
+   compptr^.width_in_blocks * DCTSIZE,
+   JDIMENSION (jround_up( long (compptr^.height_in_blocks),
+        long (compptr^.v_samp_factor)) * DCTSIZE),
+   JDIMENSION (compptr^.v_samp_factor * DCTSIZE));
+      Inc(compptr);
+    end;
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+{$endif}
+  end
+  else
+  begin
+{$ifdef FULL_MAIN_BUFFER_SUPPORTED}
+    main^.whole_image[0] := NIL; { flag for no virtual arrays }
+{$endif}
+    { Allocate a strip buffer for each component }
+    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      main^.buffer[ci] := cinfo^.mem^.alloc_sarray
+  (j_common_ptr(cinfo), JPOOL_IMAGE,
+   compptr^.width_in_blocks * DCTSIZE,
+   JDIMENSION (compptr^.v_samp_factor * DCTSIZE));
+      Inc(compptr);
+    end;
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcmarker.pas b/src/lib/vampimg/JpegLib/imjcmarker.pas
new file mode 100644 (file)
index 0000000..35463dc
--- /dev/null
@@ -0,0 +1,724 @@
+unit imjcmarker;
+
+{ This file contains routines to write JPEG datastream markers. }
+
+{ Original: jcmarker.c; Copyright (C) 1991-1998, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjinclude, imjmorecfg, imjerror,
+  imjdeferr, imjpeglib, imjutils;
+
+
+const
+                { JPEG marker codes }
+  M_SOF0  = $c0;
+  M_SOF1  = $c1;
+  M_SOF2  = $c2;
+  M_SOF3  = $c3;
+
+  M_SOF5  = $c5;
+  M_SOF6  = $c6;
+  M_SOF7  = $c7;
+
+  M_JPG   = $c8;
+  M_SOF9  = $c9;
+  M_SOF10 = $ca;
+  M_SOF11 = $cb;
+
+  M_SOF13 = $cd;
+  M_SOF14 = $ce;
+  M_SOF15 = $cf;
+
+  M_DHT   = $c4;
+
+  M_DAC   = $cc;
+
+  M_RST0  = $d0;
+  M_RST1  = $d1;
+  M_RST2  = $d2;
+  M_RST3  = $d3;
+  M_RST4  = $d4;
+  M_RST5  = $d5;
+  M_RST6  = $d6;
+  M_RST7  = $d7;
+
+  M_SOI   = $d8;
+  M_EOI   = $d9;
+  M_SOS   = $da;
+  M_DQT   = $db;
+  M_DNL   = $dc;
+  M_DRI   = $dd;
+  M_DHP   = $de;
+  M_EXP   = $df;
+
+  M_APP0  = $e0;
+  M_APP1  = $e1;
+  M_APP2  = $e2;
+  M_APP3  = $e3;
+  M_APP4  = $e4;
+  M_APP5  = $e5;
+  M_APP6  = $e6;
+  M_APP7  = $e7;
+  M_APP8  = $e8;
+  M_APP9  = $e9;
+  M_APP10 = $ea;
+  M_APP11 = $eb;
+  M_APP12 = $ec;
+  M_APP13 = $ed;
+  M_APP14 = $ee;
+  M_APP15 = $ef;
+
+  M_JPG0  = $f0;
+  M_JPG13 = $fd;
+  M_COM   = $fe;
+
+  M_TEM   = $01;
+
+  M_ERROR = $100;
+
+type
+  JPEG_MARKER = Word;
+
+{ Private state }
+
+type
+  my_marker_ptr = ^my_marker_writer;
+  my_marker_writer = record
+    pub : jpeg_marker_writer; { public fields }
+
+    last_restart_interval : uint; { last DRI value emitted; 0 after SOI }
+  end;
+
+
+
+
+{GLOBAL}
+procedure jinit_marker_writer (cinfo : j_compress_ptr);
+
+implementation
+
+{ Basic output routines.
+
+  Note that we do not support suspension while writing a marker.
+  Therefore, an application using suspension must ensure that there is
+  enough buffer space for the initial markers (typ. 600-700 bytes) before
+  calling jpeg_start_compress, and enough space to write the trailing EOI
+  (a few bytes) before calling jpeg_finish_compress.  Multipass compression
+  modes are not supported at all with suspension, so those two are the only
+  points where markers will be written. }
+
+
+{LOCAL}
+procedure emit_byte (cinfo : j_compress_ptr; val : int);
+{ Emit a byte }
+var
+  dest : jpeg_destination_mgr_ptr;
+begin
+  dest := cinfo^.dest;
+
+  dest^.next_output_byte^ := JOCTET(val);
+  Inc(dest^.next_output_byte);
+
+  Dec(dest^.free_in_buffer);
+  if (dest^.free_in_buffer = 0) then
+  begin
+    if not dest^.empty_output_buffer(cinfo) then
+      ERREXIT(j_common_ptr(cinfo), JERR_CANT_SUSPEND);
+  end;
+end;
+
+
+{LOCAL}
+procedure emit_marker(cinfo : j_compress_ptr; mark : JPEG_MARKER);
+{ Emit a marker code }
+begin
+  emit_byte(cinfo, $FF);
+  emit_byte(cinfo, int(mark));
+end;
+
+
+{LOCAL}
+procedure emit_2bytes (cinfo : j_compress_ptr; value : int);
+{ Emit a 2-byte integer; these are always MSB first in JPEG files }
+begin
+  emit_byte(cinfo, (value shr 8) and $FF);
+  emit_byte(cinfo, value and $FF);
+end;
+
+
+{ Routines to write specific marker types. }
+
+{LOCAL}
+function emit_dqt (cinfo : j_compress_ptr; index : int) : int;
+{ Emit a DQT marker }
+{ Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking }
+var
+  qtbl : JQUANT_TBL_PTR;
+  prec : int;
+  i : int;
+var
+  qval : uint;
+begin
+  qtbl := cinfo^.quant_tbl_ptrs[index];
+  if (qtbl = NIL) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_NO_QUANT_TABLE, index);
+
+  prec := 0;
+  for i := 0 to Pred(DCTSIZE2) do
+  begin
+    if (qtbl^.quantval[i] > 255) then
+      prec := 1;
+  end;
+
+  if not qtbl^.sent_table then
+  begin
+    emit_marker(cinfo, M_DQT);
+
+    if (prec <> 0) then
+      emit_2bytes(cinfo, DCTSIZE2*2 + 1 + 2)
+    else
+      emit_2bytes(cinfo, DCTSIZE2 + 1 + 2);
+
+    emit_byte(cinfo, index + (prec shl 4));
+
+    for i := 0 to Pred(DCTSIZE2) do
+    begin
+      { The table entries must be emitted in zigzag order. }
+      qval := qtbl^.quantval[jpeg_natural_order[i]];
+      if (prec <> 0) then
+  emit_byte(cinfo, int(qval shr 8));
+      emit_byte(cinfo, int(qval and $FF));
+    end;
+
+    qtbl^.sent_table := TRUE;
+  end;
+
+  emit_dqt := prec;
+end;
+
+
+{LOCAL}
+procedure emit_dht (cinfo : j_compress_ptr; index : int; is_ac : boolean);
+{ Emit a DHT marker }
+var
+  htbl : JHUFF_TBL_PTR;
+  length, i : int;
+begin
+  if (is_ac) then
+  begin
+    htbl := cinfo^.ac_huff_tbl_ptrs[index];
+    index := index + $10;                { output index has AC bit set }
+  end
+  else
+  begin
+    htbl := cinfo^.dc_huff_tbl_ptrs[index];
+  end;
+
+  if (htbl = NIL) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, index);
+
+  if not htbl^.sent_table then
+  begin
+    emit_marker(cinfo, M_DHT);
+
+    length := 0;
+    for i := 1 to 16 do
+      length := length + htbl^.bits[i];
+
+    emit_2bytes(cinfo, length + 2 + 1 + 16);
+    emit_byte(cinfo, index);
+
+    for i := 1 to 16 do
+      emit_byte(cinfo, htbl^.bits[i]);
+
+    for i := 0 to Pred(length) do
+      emit_byte(cinfo, htbl^.huffval[i]);
+
+    htbl^.sent_table := TRUE;
+  end;
+end;
+
+
+{LOCAL}
+procedure emit_dac (cinfo : j_compress_ptr);
+{ Emit a DAC marker }
+{ Since the useful info is so small, we want to emit all the tables in }
+{ one DAC marker.  Therefore this routine does its own scan of the table. }
+{$ifdef C_ARITH_CODING_SUPPORTED}
+var
+  dc_in_use : array[0..NUM_ARITH_TBLS] of byte;
+  ac_in_use : array[0..NUM_ARITH_TBLS] of byte;
+  length, i : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  for i := 0 to pred(NUM_ARITH_TBLS) do
+  begin
+    dc_in_use[i] := 0;
+    ac_in_use[i] := 0;
+  end;
+
+  for i := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[i];
+    dc_in_use[compptr^.dc_tbl_no] := 1;
+    ac_in_use[compptr^.ac_tbl_no] := 1;
+  end;
+
+  length := 0;
+  for i := 0 to pred(NUM_ARITH_TBLS) do
+    Inc(length, dc_in_use[i] + ac_in_use[i]);
+
+  emit_marker(cinfo, M_DAC);
+
+  emit_2bytes(cinfo, length*2 + 2);
+
+  for i := 0 to pred(NUM_ARITH_TBLS) do
+  begin
+    if (dc_in_use[i] <> 0) then
+    begin
+      emit_byte(cinfo, i);
+      emit_byte(cinfo, cinfo^.arith_dc_L[i] + (cinfo^.arith_dc_U[i] shl 4));
+    end;
+    if (ac_in_use[i] <> 0) then
+    begin
+      emit_byte(cinfo, i + $10);
+      emit_byte(cinfo, cinfo^.arith_ac_K[i]);
+    end;
+  end;
+end;
+{$else}
+begin
+end;
+{$endif}  {C_ARITH_CODING_SUPPORTED}
+
+
+{LOCAL}
+procedure emit_dri (cinfo : j_compress_ptr);
+{ Emit a DRI marker }
+begin
+  emit_marker(cinfo, M_DRI);
+
+  emit_2bytes(cinfo, 4);  { fixed length }
+
+  emit_2bytes(cinfo, int(cinfo^.restart_interval));
+end;
+
+
+{LOCAL}
+procedure emit_sof (cinfo : j_compress_ptr; code : JPEG_MARKER);
+{ Emit a SOF marker }
+var
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  emit_marker(cinfo, code);
+
+  emit_2bytes(cinfo, 3 * cinfo^.num_components + 2 + 5 + 1); { length }
+
+  { Make sure image isn't bigger than SOF field can handle }
+  if (long(cinfo^.image_height) > long(65535)) or
+     (long(cinfo^.image_width) > long(65535)) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_IMAGE_TOO_BIG, uInt(65535));
+
+  emit_byte(cinfo, cinfo^.data_precision);
+  emit_2bytes(cinfo, int(cinfo^.image_height));
+  emit_2bytes(cinfo, int(cinfo^.image_width));
+
+  emit_byte(cinfo, cinfo^.num_components);
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0  to Pred(cinfo^.num_components) do
+  begin
+    emit_byte(cinfo, compptr^.component_id);
+    emit_byte(cinfo, (compptr^.h_samp_factor shl 4) + compptr^.v_samp_factor);
+    emit_byte(cinfo, compptr^.quant_tbl_no);
+    Inc(compptr);
+  end;
+end;
+
+
+{LOCAL}
+procedure emit_sos (cinfo : j_compress_ptr);
+{ Emit a SOS marker }
+var
+  i, td, ta : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  emit_marker(cinfo, M_SOS);
+
+  emit_2bytes(cinfo, 2 * cinfo^.comps_in_scan + 2 + 1 + 3); { length }
+
+  emit_byte(cinfo, cinfo^.comps_in_scan);
+
+  for i := 0 to Pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[i];
+    emit_byte(cinfo, compptr^.component_id);
+    td := compptr^.dc_tbl_no;
+    ta := compptr^.ac_tbl_no;
+    if (cinfo^.progressive_mode) then
+    begin
+      { Progressive mode: only DC or only AC tables are used in one scan;
+        furthermore, Huffman coding of DC refinement uses no table at all.
+        We emit 0 for unused field(s); this is recommended by the P&M text
+        but does not seem to be specified in the standard. }
+
+      if (cinfo^.Ss = 0) then
+      begin
+  ta := 0;                { DC scan }
+  if (cinfo^.Ah <> 0) and not cinfo^.arith_code then
+    td := 0;              { no DC table either }
+      end
+      else
+      begin
+  td := 0;      { AC scan }
+      end;
+    end;
+    emit_byte(cinfo, (td shl 4) + ta);
+  end;
+
+  emit_byte(cinfo, cinfo^.Ss);
+  emit_byte(cinfo, cinfo^.Se);
+  emit_byte(cinfo, (cinfo^.Ah shl 4) + cinfo^.Al);
+end;
+
+
+{LOCAL}
+procedure emit_jfif_app0 (cinfo : j_compress_ptr);
+{ Emit a JFIF-compliant APP0 marker }
+{
+ Length of APP0 block (2 bytes)
+ Block ID     (4 bytes - ASCII "JFIF")
+ Zero byte      (1 byte to terminate the ID string)
+ Version Major, Minor   (2 bytes - major first)
+ Units      (1 byte - $00 = none, $01 = inch, $02 = cm)
+ Xdpu     (2 bytes - dots per unit horizontal)
+ Ydpu     (2 bytes - dots per unit vertical)
+ Thumbnail X size   (1 byte)
+ Thumbnail Y size   (1 byte)
+}
+begin
+  emit_marker(cinfo, M_APP0);
+
+  emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); { length }
+
+  emit_byte(cinfo, $4A);  { Identifier: ASCII "JFIF" }
+  emit_byte(cinfo, $46);
+  emit_byte(cinfo, $49);
+  emit_byte(cinfo, $46);
+  emit_byte(cinfo, 0);
+  emit_byte(cinfo, cinfo^.JFIF_major_version); { Version fields }
+  emit_byte(cinfo, cinfo^.JFIF_minor_version);
+  emit_byte(cinfo, cinfo^.density_unit); { Pixel size information }
+  emit_2bytes(cinfo, int(cinfo^.X_density));
+  emit_2bytes(cinfo, int(cinfo^.Y_density));
+  emit_byte(cinfo, 0);    { No thumbnail image }
+  emit_byte(cinfo, 0);
+end;
+
+
+{LOCAL}
+procedure emit_adobe_app14 (cinfo : j_compress_ptr);
+{ Emit an Adobe APP14 marker }
+{
+  Length of APP14 block (2 bytes)
+  Block ID      (5 bytes - ASCII "Adobe")
+  Version Number    (2 bytes - currently 100)
+  Flags0      (2 bytes - currently 0)
+  Flags1      (2 bytes - currently 0)
+  Color transform   (1 byte)
+
+  Although Adobe TN 5116 mentions Version = 101, all the Adobe files
+  now in circulation seem to use Version = 100, so that's what we write.
+
+  We write the color transform byte as 1 if the JPEG color space is
+  YCbCr, 2 if it's YCCK, 0 otherwise.  Adobe's definition has to do with
+  whether the encoder performed a transformation, which is pretty useless.
+}
+begin
+  emit_marker(cinfo, M_APP14);
+
+  emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); { length }
+
+  emit_byte(cinfo, $41);  { Identifier: ASCII "Adobe" }
+  emit_byte(cinfo, $64);
+  emit_byte(cinfo, $6F);
+  emit_byte(cinfo, $62);
+  emit_byte(cinfo, $65);
+  emit_2bytes(cinfo, 100);  { Version }
+  emit_2bytes(cinfo, 0);  { Flags0 }
+  emit_2bytes(cinfo, 0);  { Flags1 }
+  case (cinfo^.jpeg_color_space) of
+  JCS_YCbCr:
+    emit_byte(cinfo, 1);  { Color transform = 1 }
+  JCS_YCCK:
+    emit_byte(cinfo, 2);  { Color transform = 2 }
+  else
+    emit_byte(cinfo, 0);  { Color transform = 0 }
+  end;
+end;
+
+
+{ These routines allow writing an arbitrary marker with parameters.
+  The only intended use is to emit COM or APPn markers after calling
+  write_file_header and before calling write_frame_header.
+  Other uses are not guaranteed to produce desirable results.
+  Counting the parameter bytes properly is the caller's responsibility. }
+
+{METHODDEF}
+procedure write_marker_header (cinfo : j_compress_ptr;
+                               marker : int;
+                               datalen : uint);
+{ Emit an arbitrary marker header }
+begin
+  if (datalen > uint(65533)) then  { safety check }
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
+
+  emit_marker(cinfo, JPEG_MARKER(marker));
+
+  emit_2bytes(cinfo, int(datalen + 2)); { total length }
+end;
+
+{METHODDEF}
+procedure write_marker_byte (cinfo : j_compress_ptr; val : int);
+{ Emit one byte of marker parameters following write_marker_header }
+begin
+  emit_byte(cinfo, val);
+end;
+
+{ Write datastream header.
+  This consists of an SOI and optional APPn markers.
+  We recommend use of the JFIF marker, but not the Adobe marker,
+  when using YCbCr or grayscale data.  The JFIF marker should NOT
+  be used for any other JPEG colorspace.  The Adobe marker is helpful
+  to distinguish RGB, CMYK, and YCCK colorspaces.
+  Note that an application can write additional header markers after
+  jpeg_start_compress returns. }
+
+
+{METHODDEF}
+procedure write_file_header (cinfo : j_compress_ptr);
+var
+  marker : my_marker_ptr;
+begin
+  marker := my_marker_ptr(cinfo^.marker);
+
+  emit_marker(cinfo, M_SOI);   { first the SOI }
+
+  { SOI is defined to reset restart interval to 0 }
+  marker^.last_restart_interval := 0;
+
+  if (cinfo^.write_JFIF_header) then { next an optional JFIF APP0 }
+    emit_jfif_app0(cinfo);
+  if (cinfo^.write_Adobe_marker) then { next an optional Adobe APP14 }
+    emit_adobe_app14(cinfo);
+end;
+
+
+{ Write frame header.
+  This consists of DQT and SOFn markers.
+  Note that we do not emit the SOF until we have emitted the DQT(s).
+  This avoids compatibility problems with incorrect implementations that
+  try to error-check the quant table numbers as soon as they see the SOF. }
+
+
+{METHODDEF}
+procedure write_frame_header (cinfo : j_compress_ptr);
+var
+  ci, prec : int;
+  is_baseline : boolean;
+  compptr : jpeg_component_info_ptr;
+begin
+  { Emit DQT for each quantization table.
+    Note that emit_dqt() suppresses any duplicate tables. }
+
+  prec := 0;
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to Pred(cinfo^.num_components) do
+  begin
+    prec := prec + emit_dqt(cinfo, compptr^.quant_tbl_no);
+    Inc(compptr);
+  end;
+  { now prec is nonzero iff there are any 16-bit quant tables. }
+
+  { Check for a non-baseline specification.
+    Note we assume that Huffman table numbers won't be changed later. }
+
+  if (cinfo^.arith_code) or (cinfo^.progressive_mode)
+   or (cinfo^.data_precision <> 8) then
+  begin
+    is_baseline := FALSE;
+  end
+  else
+  begin
+    is_baseline := TRUE;
+    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+    for ci := 0 to Pred(cinfo^.num_components) do
+    begin
+      if (compptr^.dc_tbl_no > 1) or (compptr^.ac_tbl_no > 1) then
+  is_baseline := FALSE;
+      Inc(compptr);
+    end;
+    if (prec <> 0) and (is_baseline) then
+    begin
+      is_baseline := FALSE;
+      { If it's baseline except for quantizer size, warn the user }
+      {$IFDEF DEBUG}
+      TRACEMS(j_common_ptr(cinfo), 0, JTRC_16BIT_TABLES);
+      {$ENDIF}
+    end;
+  end;
+
+  { Emit the proper SOF marker }
+  if (cinfo^.arith_code) then
+  begin
+    emit_sof(cinfo, M_SOF9);  { SOF code for arithmetic coding }
+  end
+  else
+  begin
+    if (cinfo^.progressive_mode) then
+      emit_sof(cinfo, M_SOF2) { SOF code for progressive Huffman }
+    else if (is_baseline) then
+      emit_sof(cinfo, M_SOF0) { SOF code for baseline implementation }
+    else
+      emit_sof(cinfo, M_SOF1);  { SOF code for non-baseline Huffman file }
+  end;
+end;
+
+
+{ Write scan header.
+  This consists of DHT or DAC markers, optional DRI, and SOS.
+  Compressed data will be written following the SOS. }
+
+{METHODDEF}
+procedure write_scan_header (cinfo : j_compress_ptr);
+var
+  marker : my_marker_ptr;
+  i : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  marker := my_marker_ptr(cinfo^.marker);
+  if (cinfo^.arith_code) then
+  begin
+    { Emit arith conditioning info.  We may have some duplication
+      if the file has multiple scans, but it's so small it's hardly
+      worth worrying about. }
+    emit_dac(cinfo);
+  end
+  else
+  begin
+    { Emit Huffman tables.
+      Note that emit_dht() suppresses any duplicate tables. }
+    for i := 0 to Pred(cinfo^.comps_in_scan) do
+    begin
+      compptr := cinfo^.cur_comp_info[i];
+      if (cinfo^.progressive_mode) then
+      begin
+  { Progressive mode: only DC or only AC tables are used in one scan }
+  if (cinfo^.Ss = 0) then
+        begin
+    if (cinfo^.Ah = 0) then  { DC needs no table for refinement scan }
+      emit_dht(cinfo, compptr^.dc_tbl_no, FALSE);
+  end
+        else
+        begin
+    emit_dht(cinfo, compptr^.ac_tbl_no, TRUE);
+  end;
+      end
+      else
+      begin
+  { Sequential mode: need both DC and AC tables }
+  emit_dht(cinfo, compptr^.dc_tbl_no, FALSE);
+  emit_dht(cinfo, compptr^.ac_tbl_no, TRUE);
+      end;
+    end;
+  end;
+
+  { Emit DRI if required --- note that DRI value could change for each scan.
+    We avoid wasting space with unnecessary DRIs, however. }
+
+  if (cinfo^.restart_interval <> marker^.last_restart_interval) then
+  begin
+    emit_dri(cinfo);
+    marker^.last_restart_interval := cinfo^.restart_interval;
+  end;
+
+  emit_sos(cinfo);
+end;
+
+
+
+{ Write datastream trailer. }
+
+
+{METHODDEF}
+procedure write_file_trailer (cinfo : j_compress_ptr);
+begin
+  emit_marker(cinfo, M_EOI);
+end;
+
+
+{ Write an abbreviated table-specification datastream.
+  This consists of SOI, DQT and DHT tables, and EOI.
+  Any table that is defined and not marked sent_table = TRUE will be
+  emitted.  Note that all tables will be marked sent_table = TRUE at exit. }
+
+
+{METHODDEF}
+procedure write_tables_only (cinfo : j_compress_ptr);
+var
+  i : int;
+begin
+  emit_marker(cinfo, M_SOI);
+
+  for i := 0 to Pred(NUM_QUANT_TBLS) do
+  begin
+    if (cinfo^.quant_tbl_ptrs[i] <> NIL) then
+      emit_dqt(cinfo, i);  { dummy := ... }
+  end;
+
+  if (not cinfo^.arith_code) then
+  begin
+    for i := 0 to Pred(NUM_HUFF_TBLS) do
+    begin
+      if (cinfo^.dc_huff_tbl_ptrs[i] <> NIL) then
+  emit_dht(cinfo, i, FALSE);
+      if (cinfo^.ac_huff_tbl_ptrs[i] <> NIL) then
+  emit_dht(cinfo, i, TRUE);
+    end;
+  end;
+
+  emit_marker(cinfo, M_EOI);
+end;
+
+
+{ Initialize the marker writer module. }
+
+{GLOBAL}
+procedure jinit_marker_writer (cinfo : j_compress_ptr);
+var
+  marker : my_marker_ptr;
+begin
+  { Create the subobject }
+  marker := my_marker_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_marker_writer)) );
+  cinfo^.marker := jpeg_marker_writer_ptr(marker);
+  { Initialize method pointers }
+  marker^.pub.write_file_header := write_file_header;
+  marker^.pub.write_frame_header := write_frame_header;
+  marker^.pub.write_scan_header := write_scan_header;
+  marker^.pub.write_file_trailer := write_file_trailer;
+  marker^.pub.write_tables_only := write_tables_only;
+  marker^.pub.write_marker_header := write_marker_header;
+  marker^.pub.write_marker_byte := write_marker_byte;
+  { Initialize private state }
+  marker^.last_restart_interval := 0;
+end;
+
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcmaster.pas b/src/lib/vampimg/JpegLib/imjcmaster.pas
new file mode 100644 (file)
index 0000000..1498398
--- /dev/null
@@ -0,0 +1,701 @@
+unit imjcmaster;
+
+{ This file contains master control logic for the JPEG compressor.
+  These routines are concerned with parameter validation, initial setup,
+  and inter-pass control (determining the number of passes and the work
+  to be done in each pass). }
+
+{ Original: jcmaster.c ; Copyright (C) 1991-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjpeglib;
+
+{ Initialize master compression control. }
+
+{GLOBAL}
+procedure jinit_c_master_control (cinfo : j_compress_ptr;
+                                  transcode_only : boolean);
+
+implementation
+
+{ Private state }
+
+type
+  c_pass_type = (
+  main_pass,    { input data, also do first output step }
+  huff_opt_pass,    { Huffman code optimization pass }
+  output_pass   { data output pass }
+                );
+
+type
+  my_master_ptr = ^my_comp_master;
+  my_comp_master = record
+    pub : jpeg_comp_master; { public fields }
+
+    pass_type : c_pass_type;  { the type of the current pass }
+
+    pass_number : int;    { # of passes completed }
+    total_passes : int;   { total # of passes needed }
+
+    scan_number : int;    { current index in scan_info[] }
+  end;
+
+
+{ Support routines that do various essential calculations. }
+
+{LOCAL}
+procedure initial_setup (cinfo : j_compress_ptr);
+{ Do computations that are needed before master selection phase }
+var
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+  samplesperrow : long;
+  jd_samplesperrow : JDIMENSION;
+begin
+
+  { Sanity check on image dimensions }
+  if (cinfo^.image_height <= 0) or (cinfo^.image_width <= 0) or
+     (cinfo^.num_components <= 0) or (cinfo^.input_components <= 0) then
+    ERREXIT(j_common_ptr(cinfo), JERR_EMPTY_IMAGE);
+
+  { Make sure image isn't bigger than I can handle }
+  if ( long(cinfo^.image_height) > long(JPEG_MAX_DIMENSION)) or
+      ( long(cinfo^.image_width) > long(JPEG_MAX_DIMENSION)) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_IMAGE_TOO_BIG,
+                                  uInt(JPEG_MAX_DIMENSION));
+
+  { Width of an input scanline must be representable as JDIMENSION. }
+  samplesperrow := long (cinfo^.image_width) * long (cinfo^.input_components);
+  jd_samplesperrow := JDIMENSION (samplesperrow);
+  if ( long(jd_samplesperrow) <> samplesperrow) then
+    ERREXIT(j_common_ptr(cinfo), JERR_WIDTH_OVERFLOW);
+
+  { For now, precision must match compiled-in value... }
+  if (cinfo^.data_precision <> BITS_IN_JSAMPLE) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PRECISION, cinfo^.data_precision);
+
+  { Check that number of components won't exceed internal array sizes }
+  if (cinfo^.num_components > MAX_COMPONENTS) then
+    ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.num_components,
+       MAX_COMPONENTS);
+
+  { Compute maximum sampling factors; check factor validity }
+  cinfo^.max_h_samp_factor := 1;
+  cinfo^.max_v_samp_factor := 1;
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    if (compptr^.h_samp_factor<=0) or (compptr^.h_samp_factor>MAX_SAMP_FACTOR)
+    or (compptr^.v_samp_factor<=0) or (compptr^.v_samp_factor>MAX_SAMP_FACTOR) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_SAMPLING);
+    { MAX }
+    if cinfo^.max_h_samp_factor > compptr^.h_samp_factor then
+      cinfo^.max_h_samp_factor := cinfo^.max_h_samp_factor
+    else
+      cinfo^.max_h_samp_factor := compptr^.h_samp_factor;
+    { MAX }
+    if cinfo^.max_v_samp_factor > compptr^.v_samp_factor then
+      cinfo^.max_v_samp_factor := cinfo^.max_v_samp_factor
+    else
+      cinfo^.max_v_samp_factor := compptr^.v_samp_factor;
+    Inc(compptr);
+  end;
+
+  { Compute dimensions of components }
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Fill in the correct component_index value; don't rely on application }
+    compptr^.component_index := ci;
+    { For compression, we never do DCT scaling. }
+    compptr^.DCT_scaled_size := DCTSIZE;
+    { Size in DCT blocks }
+    compptr^.width_in_blocks := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_width) * long (compptr^.h_samp_factor),
+        long (cinfo^.max_h_samp_factor * DCTSIZE)) );
+    compptr^.height_in_blocks := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_height) * long (compptr^.v_samp_factor),
+        long (cinfo^.max_v_samp_factor * DCTSIZE)) );
+    { Size in samples }
+    compptr^.downsampled_width := JDIMENSION (
+      jdiv_round_up(long(cinfo^.image_width) * long(compptr^.h_samp_factor),
+        long(cinfo^.max_h_samp_factor)) );
+    compptr^.downsampled_height := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_height) * long(compptr^.v_samp_factor),
+        long (cinfo^.max_v_samp_factor)) );
+    { Mark component needed (this flag isn't actually used for compression) }
+    compptr^.component_needed := TRUE;
+    Inc(compptr);
+  end;
+
+  { Compute number of fully interleaved MCU rows (number of times that
+    main controller will call coefficient controller). }
+
+  cinfo^.total_iMCU_rows := JDIMENSION (
+    jdiv_round_up(long (cinfo^.image_height),
+      long (cinfo^.max_v_samp_factor*DCTSIZE)) );
+end;
+
+
+{$ifdef C_MULTISCAN_FILES_SUPPORTED}
+
+{LOCAL}
+procedure validate_script (cinfo : j_compress_ptr);
+{ Verify that the scan script in cinfo^.scan_info[] is valid; also
+  determine whether it uses progressive JPEG, and set cinfo^.progressive_mode. }
+type
+  IntRow = array[0..DCTSIZE2-1] of int;
+  introw_ptr = ^IntRow;
+var
+  {const}scanptr : jpeg_scan_info_ptr;
+  scanno, ncomps, ci, coefi, thisi : int;
+  Ss, Se, Ah, Al : int;
+  component_sent : array[0..MAX_COMPONENTS-1] of boolean;
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+  last_bitpos_int_ptr : int_ptr;
+  last_bitpos_ptr : introw_ptr;
+  last_bitpos : array[0..MAX_COMPONENTS-1] of IntRow;
+  { -1 until that coefficient has been seen; then last Al for it }
+  { The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that
+    seems wrong: the upper bound ought to depend on data precision.
+    Perhaps they really meant 0..N+1 for N-bit precision.
+    Here we allow 0..10 for 8-bit data; Al larger than 10 results in
+    out-of-range reconstructed DC values during the first DC scan,
+    which might cause problems for some decoders. }
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  MAX_AH_AL = 10;
+{$else}
+const
+  MAX_AH_AL = 13;
+{$endif}
+{$endif}
+begin
+
+  if (cinfo^.num_scans <= 0) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, 0);
+
+  { For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
+    for progressive JPEG, no scan can have this. }
+
+  scanptr := cinfo^.scan_info;
+  if (scanptr^.Ss <> 0) or (scanptr^.Se <> DCTSIZE2-1) then
+  begin
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+    cinfo^.progressive_mode := TRUE;
+    last_bitpos_int_ptr := @(last_bitpos[0][0]);
+    for ci := 0 to pred(cinfo^.num_components) do
+      for coefi := 0 to pred(DCTSIZE2) do
+      begin
+  last_bitpos_int_ptr^ := -1;
+        Inc(last_bitpos_int_ptr);
+      end;
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+  end
+  else
+  begin
+    cinfo^.progressive_mode := FALSE;
+    for ci := 0 to pred(cinfo^.num_components) do
+      component_sent[ci] := FALSE;
+  end;
+
+  for scanno := 1 to cinfo^.num_scans do
+  begin
+    { Validate component indexes }
+    ncomps := scanptr^.comps_in_scan;
+    if (ncomps <= 0) or (ncomps > MAX_COMPS_IN_SCAN) then
+      ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);
+    for ci := 0 to pred(ncomps) do
+    begin
+      thisi := scanptr^.component_index[ci];
+      if (thisi < 0) or (thisi >= cinfo^.num_components) then
+  ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno);
+      { Components must appear in SOF order within each scan }
+      if (ci > 0) and (thisi <= scanptr^.component_index[ci-1]) then
+  ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno);
+    end;
+    { Validate progression parameters }
+    Ss := scanptr^.Ss;
+    Se := scanptr^.Se;
+    Ah := scanptr^.Ah;
+    Al := scanptr^.Al;
+    if (cinfo^.progressive_mode) then
+    begin
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+      if (Ss < 0) or (Ss >= DCTSIZE2) or (Se < Ss) or (Se >= DCTSIZE2) or
+   (Ah < 0) or (Ah > MAX_AH_AL) or (Al < 0) or (Al > MAX_AH_AL) then
+  ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+
+      if (Ss < 0) or (Ss >= DCTSIZE2) or (Se < Ss) or (Se >= DCTSIZE2)
+       or (Ah < 0) or (Ah > MAX_AH_AL) or (Al < 0) or (Al > MAX_AH_AL) then
+  ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+      if (Ss = 0) then
+      begin
+  if (Se <> 0) then { DC and AC together not OK }
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+      end
+      else
+      begin
+  if (ncomps <> 1) then  { AC scans must be for only one component }
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+      end;
+      for ci := 0 to pred(ncomps) do
+      begin
+  last_bitpos_ptr := @( last_bitpos[scanptr^.component_index[ci]]);
+  if (Ss <> 0) and (last_bitpos_ptr^[0] < 0) then { AC without prior DC scan }
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+  for coefi := Ss to Se do
+        begin
+    if (last_bitpos_ptr^[coefi] < 0) then
+          begin
+      { first scan of this coefficient }
+      if (Ah <> 0) then
+        ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+    end
+          else
+          begin
+      { not first scan }
+      if (Ah <> last_bitpos_ptr^[coefi]) or (Al <> Ah-1) then
+        ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+    end;
+    last_bitpos_ptr^[coefi] := Al;
+  end;
+      end;
+{$endif}
+    end
+    else
+    begin
+      { For sequential JPEG, all progression parameters must be these: }
+      if (Ss <> 0) or (Se <> DCTSIZE2-1) or (Ah <> 0) or (Al <> 0) then
+  ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno);
+      { Make sure components are not sent twice }
+      for ci := 0 to pred(ncomps) do
+      begin
+  thisi := scanptr^.component_index[ci];
+  if (component_sent[thisi]) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno);
+  component_sent[thisi] := TRUE;
+      end;
+    end;
+    Inc(scanptr);
+  end;
+
+  { Now verify that everything got sent. }
+  if (cinfo^.progressive_mode) then
+  begin
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+    { For progressive mode, we only check that at least some DC data
+      got sent for each component; the spec does not require that all bits
+      of all coefficients be transmitted.  Would it be wiser to enforce
+      transmission of all coefficient bits?? }
+
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      if (last_bitpos[ci][0] < 0) then
+  ERREXIT(j_common_ptr(cinfo), JERR_MISSING_DATA);
+    end;
+{$endif}
+  end
+  else
+  begin
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      if (not component_sent[ci]) then
+  ERREXIT(j_common_ptr(cinfo), JERR_MISSING_DATA);
+    end;
+  end;
+end;
+
+{$endif} { C_MULTISCAN_FILES_SUPPORTED }
+
+
+{LOCAL}
+procedure select_scan_parameters (cinfo : j_compress_ptr);
+{ Set up the scan parameters for the current scan }
+var
+  master : my_master_ptr;
+  {const} scanptr : jpeg_scan_info_ptr;
+  ci : int;
+var
+  comp_infos : jpeg_component_info_list_ptr;
+begin
+{$ifdef C_MULTISCAN_FILES_SUPPORTED}
+  if (cinfo^.scan_info <> NIL) then
+  begin
+    { Prepare for current scan --- the script is already validated }
+    master := my_master_ptr (cinfo^.master);
+    scanptr := cinfo^.scan_info;
+    Inc(scanptr, master^.scan_number);
+
+    cinfo^.comps_in_scan := scanptr^.comps_in_scan;
+    comp_infos := cinfo^.comp_info;
+    for ci := 0 to pred(scanptr^.comps_in_scan) do
+    begin
+      cinfo^.cur_comp_info[ci] :=
+        @(comp_infos^[scanptr^.component_index[ci]]);
+    end;
+    cinfo^.Ss := scanptr^.Ss;
+    cinfo^.Se := scanptr^.Se;
+    cinfo^.Ah := scanptr^.Ah;
+    cinfo^.Al := scanptr^.Al;
+  end
+  else
+{$endif}
+  begin
+    { Prepare for single sequential-JPEG scan containing all components }
+    if (cinfo^.num_components > MAX_COMPS_IN_SCAN) then
+      ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.num_components,
+         MAX_COMPS_IN_SCAN);
+    cinfo^.comps_in_scan := cinfo^.num_components;
+    comp_infos := cinfo^.comp_info;
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      cinfo^.cur_comp_info[ci] := @(comp_infos^[ci]);
+    end;
+    cinfo^.Ss := 0;
+    cinfo^.Se := DCTSIZE2-1;
+    cinfo^.Ah := 0;
+    cinfo^.Al := 0;
+  end;
+end;
+
+
+{LOCAL}
+procedure per_scan_setup (cinfo : j_compress_ptr);
+{ Do computations that are needed before processing a JPEG scan }
+{ cinfo^.comps_in_scan and cinfo^.cur_comp_info[] are already set }
+var
+  ci, mcublks, tmp : int;
+  compptr : jpeg_component_info_ptr;
+  nominal : long;
+begin
+  if (cinfo^.comps_in_scan = 1) then
+  begin
+
+    { Noninterleaved (single-component) scan }
+    compptr := cinfo^.cur_comp_info[0];
+
+    { Overall image size in MCUs }
+    cinfo^.MCUs_per_row := compptr^.width_in_blocks;
+    cinfo^.MCU_rows_in_scan := compptr^.height_in_blocks;
+
+    { For noninterleaved scan, always one block per MCU }
+    compptr^.MCU_width := 1;
+    compptr^.MCU_height := 1;
+    compptr^.MCU_blocks := 1;
+    compptr^.MCU_sample_width := DCTSIZE;
+    compptr^.last_col_width := 1;
+    { For noninterleaved scans, it is convenient to define last_row_height
+      as the number of block rows present in the last iMCU row. }
+
+    tmp := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor;
+    if (tmp = 0) then
+      tmp := compptr^.v_samp_factor;
+    compptr^.last_row_height := tmp;
+
+    { Prepare array describing MCU composition }
+    cinfo^.blocks_in_MCU := 1;
+    cinfo^.MCU_membership[0] := 0;
+
+  end
+  else
+  begin
+
+    { Interleaved (multi-component) scan }
+    if (cinfo^.comps_in_scan <= 0) or
+       (cinfo^.comps_in_scan > MAX_COMPS_IN_SCAN) then
+      ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT,
+        cinfo^.comps_in_scan,  MAX_COMPS_IN_SCAN);
+
+    { Overall image size in MCUs }
+    cinfo^.MCUs_per_row := JDIMENSION (
+      jdiv_round_up( long (cinfo^.image_width),
+         long (cinfo^.max_h_samp_factor*DCTSIZE)) );
+    cinfo^.MCU_rows_in_scan := JDIMENSION (
+      jdiv_round_up( long (cinfo^.image_height),
+         long (cinfo^.max_v_samp_factor*DCTSIZE)) );
+
+    cinfo^.blocks_in_MCU := 0;
+
+    for ci := 0 to pred(cinfo^.comps_in_scan) do
+    begin
+      compptr := cinfo^.cur_comp_info[ci];
+      { Sampling factors give # of blocks of component in each MCU }
+      compptr^.MCU_width := compptr^.h_samp_factor;
+      compptr^.MCU_height := compptr^.v_samp_factor;
+      compptr^.MCU_blocks := compptr^.MCU_width * compptr^.MCU_height;
+      compptr^.MCU_sample_width := compptr^.MCU_width * DCTSIZE;
+      { Figure number of non-dummy blocks in last MCU column & row }
+      tmp := int (compptr^.width_in_blocks) mod compptr^.MCU_width;
+      if (tmp = 0) then
+        tmp := compptr^.MCU_width;
+      compptr^.last_col_width := tmp;
+      tmp := int (compptr^.height_in_blocks) mod compptr^.MCU_height;
+      if (tmp = 0) then
+        tmp := compptr^.MCU_height;
+      compptr^.last_row_height := tmp;
+      { Prepare array describing MCU composition }
+      mcublks := compptr^.MCU_blocks;
+      if (cinfo^.blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) then
+  ERREXIT(j_common_ptr(cinfo), JERR_BAD_MCU_SIZE);
+      while (mcublks > 0) do
+      begin
+        Dec(mcublks);
+  cinfo^.MCU_membership[cinfo^.blocks_in_MCU] := ci;
+        Inc(cinfo^.blocks_in_MCU);
+      end;
+    end;
+
+  end;
+
+  { Convert restart specified in rows to actual MCU count. }
+  { Note that count must fit in 16 bits, so we provide limiting. }
+  if (cinfo^.restart_in_rows > 0) then
+  begin
+    nominal := long(cinfo^.restart_in_rows) * long(cinfo^.MCUs_per_row);
+    if nominal < long(65535) then
+      cinfo^.restart_interval := uInt (nominal)
+    else
+      cinfo^.restart_interval := long(65535);
+  end;
+end;
+
+
+{ Per-pass setup.
+  This is called at the beginning of each pass.  We determine which modules
+  will be active during this pass and give them appropriate start_pass calls.
+  We also set is_last_pass to indicate whether any more passes will be
+  required. }
+
+{METHODDEF}
+procedure prepare_for_pass (cinfo : j_compress_ptr);
+var
+  master : my_master_ptr;
+var
+  fallthrough : boolean;
+begin
+  master := my_master_ptr (cinfo^.master);
+  fallthrough := true;
+
+  case (master^.pass_type) of
+  main_pass:
+    begin
+      { Initial pass: will collect input data, and do either Huffman
+        optimization or data output for the first scan. }
+      select_scan_parameters(cinfo);
+      per_scan_setup(cinfo);
+      if (not cinfo^.raw_data_in) then
+      begin
+        cinfo^.cconvert^.start_pass (cinfo);
+        cinfo^.downsample^.start_pass (cinfo);
+        cinfo^.prep^.start_pass (cinfo, JBUF_PASS_THRU);
+      end;
+      cinfo^.fdct^.start_pass (cinfo);
+      cinfo^.entropy^.start_pass (cinfo, cinfo^.optimize_coding);
+      if master^.total_passes > 1 then
+        cinfo^.coef^.start_pass (cinfo, JBUF_SAVE_AND_PASS)
+      else
+        cinfo^.coef^.start_pass (cinfo, JBUF_PASS_THRU);
+      cinfo^.main^.start_pass (cinfo, JBUF_PASS_THRU);
+      if (cinfo^.optimize_coding) then
+      begin
+        { No immediate data output; postpone writing frame/scan headers }
+        master^.pub.call_pass_startup := FALSE;
+      end
+      else
+      begin
+        { Will write frame/scan headers at first jpeg_write_scanlines call }
+        master^.pub.call_pass_startup := TRUE;
+      end;
+    end;
+{$ifdef ENTROPY_OPT_SUPPORTED}
+  huff_opt_pass,
+  output_pass:
+    begin
+      if (master^.pass_type = huff_opt_pass) then
+      begin
+        { Do Huffman optimization for a scan after the first one. }
+        select_scan_parameters(cinfo);
+        per_scan_setup(cinfo);
+        if (cinfo^.Ss <> 0) or (cinfo^.Ah = 0) or (cinfo^.arith_code) then
+        begin
+          cinfo^.entropy^.start_pass (cinfo, TRUE);
+          cinfo^.coef^.start_pass (cinfo, JBUF_CRANK_DEST);
+          master^.pub.call_pass_startup := FALSE;
+          fallthrough := false;
+        end;
+        { Special case: Huffman DC refinement scans need no Huffman table
+          and therefore we can skip the optimization pass for them. }
+        if fallthrough then
+        begin
+          master^.pass_type := output_pass;
+          Inc(master^.pass_number);
+          {FALLTHROUGH}
+        end;
+      end;
+{$else}
+  output_pass:
+    begin
+{$endif}
+      if fallthrough then
+      begin
+        { Do a data-output pass. }
+        { We need not repeat per-scan setup if prior optimization pass did it. }
+        if (not cinfo^.optimize_coding) then
+        begin
+          select_scan_parameters(cinfo);
+          per_scan_setup(cinfo);
+        end;
+        cinfo^.entropy^.start_pass (cinfo, FALSE);
+        cinfo^.coef^.start_pass (cinfo, JBUF_CRANK_DEST);
+        { We emit frame/scan headers now }
+        if (master^.scan_number = 0) then
+          cinfo^.marker^.write_frame_header (cinfo);
+        cinfo^.marker^.write_scan_header (cinfo);
+        master^.pub.call_pass_startup := FALSE;
+      end;
+    end;
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+  end;
+
+  master^.pub.is_last_pass := (master^.pass_number = master^.total_passes-1);
+
+  { Set up progress monitor's pass info if present }
+  if (cinfo^.progress <> NIL) then
+  begin
+    cinfo^.progress^.completed_passes := master^.pass_number;
+    cinfo^.progress^.total_passes := master^.total_passes;
+  end;
+end;
+
+
+{ Special start-of-pass hook.
+  This is called by jpeg_write_scanlines if call_pass_startup is TRUE.
+  In single-pass processing, we need this hook because we don't want to
+  write frame/scan headers during jpeg_start_compress; we want to let the
+  application write COM markers etc. between jpeg_start_compress and the
+  jpeg_write_scanlines loop.
+  In multi-pass processing, this routine is not used. }
+
+{METHODDEF}
+procedure pass_startup (cinfo : j_compress_ptr);
+begin
+  cinfo^.master^.call_pass_startup := FALSE; { reset flag so call only once }
+
+  cinfo^.marker^.write_frame_header (cinfo);
+  cinfo^.marker^.write_scan_header (cinfo);
+end;
+
+
+{ Finish up at end of pass. }
+
+{METHODDEF}
+procedure finish_pass_master (cinfo : j_compress_ptr);
+var
+  master : my_master_ptr;
+begin
+  master := my_master_ptr (cinfo^.master);
+
+  { The entropy coder always needs an end-of-pass call,
+    either to analyze statistics or to flush its output buffer. }
+  cinfo^.entropy^.finish_pass (cinfo);
+
+  { Update state for next pass }
+  case (master^.pass_type) of
+  main_pass:
+    begin
+      { next pass is either output of scan 0 (after optimization)
+        or output of scan 1 (if no optimization). }
+
+      master^.pass_type := output_pass;
+      if (not cinfo^.optimize_coding) then
+        Inc(master^.scan_number);
+    end;
+  huff_opt_pass:
+    { next pass is always output of current scan }
+    master^.pass_type := output_pass;
+  output_pass:
+    begin
+      { next pass is either optimization or output of next scan }
+      if (cinfo^.optimize_coding) then
+        master^.pass_type := huff_opt_pass;
+      Inc(master^.scan_number);
+    end;
+  end;
+
+  Inc(master^.pass_number);
+end;
+
+
+{ Initialize master compression control. }
+
+{GLOBAL}
+procedure jinit_c_master_control (cinfo : j_compress_ptr;
+                                  transcode_only : boolean);
+var
+  master : my_master_ptr;
+begin
+  master := my_master_ptr(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          SIZEOF(my_comp_master)) );
+  cinfo^.master := jpeg_comp_master_ptr(master);
+  master^.pub.prepare_for_pass := prepare_for_pass;
+  master^.pub.pass_startup := pass_startup;
+  master^.pub.finish_pass := finish_pass_master;
+  master^.pub.is_last_pass := FALSE;
+
+  { Validate parameters, determine derived values }
+  initial_setup(cinfo);
+
+  if (cinfo^.scan_info <> NIL) then
+  begin
+{$ifdef C_MULTISCAN_FILES_SUPPORTED}
+    validate_script(cinfo);
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+  end
+  else
+  begin
+    cinfo^.progressive_mode := FALSE;
+    cinfo^.num_scans := 1;
+  end;
+
+  if (cinfo^.progressive_mode) then  {  TEMPORARY HACK ??? }
+    cinfo^.optimize_coding := TRUE;  { assume default tables no good for progressive mode }
+
+  { Initialize my private state }
+  if (transcode_only) then
+  begin
+    { no main pass in transcoding }
+    if (cinfo^.optimize_coding) then
+      master^.pass_type := huff_opt_pass
+    else
+      master^.pass_type := output_pass;
+  end
+  else
+  begin
+    { for normal compression, first pass is always this type: }
+    master^.pass_type := main_pass;
+  end;
+  master^.scan_number := 0;
+  master^.pass_number := 0;
+  if (cinfo^.optimize_coding) then
+    master^.total_passes := cinfo^.num_scans * 2
+  else
+    master^.total_passes := cinfo^.num_scans;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcomapi.pas b/src/lib/vampimg/JpegLib/imjcomapi.pas
new file mode 100644 (file)
index 0000000..c58a7ae
--- /dev/null
@@ -0,0 +1,130 @@
+unit imjcomapi;
+
+{ This file contains application interface routines that are used for both
+  compression and decompression. }
+
+{ Original: jcomapi.c;  Copyright (C) 1994-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib;
+
+{ Abort processing of a JPEG compression or decompression operation,
+  but don't destroy the object itself. }
+
+{GLOBAL}
+procedure jpeg_abort (cinfo : j_common_ptr);
+
+
+{ Destruction of a JPEG object. }
+
+{GLOBAL}
+procedure jpeg_destroy (cinfo : j_common_ptr);
+
+{GLOBAL}
+function jpeg_alloc_quant_table (cinfo : j_common_ptr) : JQUANT_TBL_PTR;
+
+{GLOBAL}
+function jpeg_alloc_huff_table (cinfo : j_common_ptr) : JHUFF_TBL_PTR;
+
+implementation
+
+{ Abort processing of a JPEG compression or decompression operation,
+  but don't destroy the object itself.
+
+  For this, we merely clean up all the nonpermanent memory pools.
+  Note that temp files (virtual arrays) are not allowed to belong to
+  the permanent pool, so we will be able to close all temp files here.
+  Closing a data source or destination, if necessary, is the application's
+  responsibility. }
+
+
+{GLOBAL}
+procedure jpeg_abort (cinfo : j_common_ptr);
+var
+  pool : int;
+begin
+  { Do nothing if called on a not-initialized or destroyed JPEG object. }
+  if (cinfo^.mem = NIL) then
+    exit;
+
+  { Releasing pools in reverse order might help avoid fragmentation
+    with some (brain-damaged) malloc libraries. }
+
+  for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT+1 do
+  begin
+    cinfo^.mem^.free_pool (cinfo, pool);
+  end;
+
+  { Reset overall state for possible reuse of object }
+  if (cinfo^.is_decompressor) then
+  begin
+    cinfo^.global_state := DSTATE_START;
+    { Try to keep application from accessing now-deleted marker list.
+      A bit kludgy to do it here, but this is the most central place. }
+    j_decompress_ptr(cinfo)^.marker_list := NIL;
+  end
+  else
+  begin
+    cinfo^.global_state := CSTATE_START;
+  end;
+end;
+
+
+{ Destruction of a JPEG object.
+
+  Everything gets deallocated except the master jpeg_compress_struct itself
+  and the error manager struct.  Both of these are supplied by the application
+  and must be freed, if necessary, by the application.  (Often they are on
+  the stack and so don't need to be freed anyway.)
+  Closing a data source or destination, if necessary, is the application's
+  responsibility. }
+
+
+{GLOBAL}
+procedure jpeg_destroy (cinfo : j_common_ptr);
+begin
+  { We need only tell the memory manager to release everything. }
+  { NB: mem pointer is NIL if memory mgr failed to initialize. }
+  if (cinfo^.mem <> NIL) then
+    cinfo^.mem^.self_destruct (cinfo);
+  cinfo^.mem := NIL;           { be safe if jpeg_destroy is called twice }
+  cinfo^.global_state := 0;    { mark it destroyed }
+end;
+
+
+{ Convenience routines for allocating quantization and Huffman tables.
+  (Would jutils.c be a more reasonable place to put these?) }
+
+
+{GLOBAL}
+function jpeg_alloc_quant_table (cinfo : j_common_ptr) : JQUANT_TBL_PTR;
+var
+  tbl : JQUANT_TBL_PTR;
+begin
+  tbl := JQUANT_TBL_PTR(
+    cinfo^.mem^.alloc_small (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL))
+                      );
+  tbl^.sent_table := FALSE;   { make sure this is false in any new table }
+  jpeg_alloc_quant_table := tbl;
+end;
+
+
+{GLOBAL}
+function jpeg_alloc_huff_table (cinfo : j_common_ptr) : JHUFF_TBL_PTR;
+var
+  tbl : JHUFF_TBL_PTR;
+begin
+  tbl := JHUFF_TBL_PTR(
+    cinfo^.mem^.alloc_small (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL))
+                     );
+  tbl^.sent_table := FALSE;   { make sure this is false in any new table }
+  jpeg_alloc_huff_table := tbl;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjconfig.inc b/src/lib/vampimg/JpegLib/imjconfig.inc
new file mode 100644 (file)
index 0000000..70cf478
--- /dev/null
@@ -0,0 +1,125 @@
+{ ----------------------- JPEG_INTERNAL_OPTIONS ---------------------- }
+
+
+{ These defines indicate whether to include various optional functions.
+  Undefining some of these symbols will produce a smaller but less capable
+  library.  Note that you can leave certain source files out of the
+  compilation/linking process if you've #undef'd the corresponding symbols.
+  (You may HAVE to do that if your compiler doesn't like null source files.)}
+
+
+{ Arithmetic coding is unsupported for legal reasons.  Complaints to IBM. }
+
+{ Capability options common to encoder and decoder: }
+
+{$define DCT_ISLOW_SUPPORTED}     { slow but accurate integer algorithm }
+{$define DCT_IFAST_SUPPORTED}     { faster, less accurate integer method }
+{$define DCT_FLOAT_SUPPORTED}     { floating-point: accurate, fast on fast HW }
+
+{ Encoder capability options: }
+
+{$undef C_ARITH_CODING_SUPPORTED}    { Arithmetic coding back end? }
+{$define C_MULTISCAN_FILES_SUPPORTED} { Multiple-scan JPEG files? }
+{$define C_PROGRESSIVE_SUPPORTED}     { Progressive JPEG? (Requires MULTISCAN)}
+{$define ENTROPY_OPT_SUPPORTED}       { Optimization of entropy coding parms? }
+{ Note: if you selected 12-bit data precision, it is dangerous to turn off
+  ENTROPY_OPT_SUPPORTED.  The standard Huffman tables are only good for 8-bit
+  precision, so jchuff.c normally uses entropy optimization to compute
+  usable tables for higher precision.  If you don't want to do optimization,
+  you'll have to supply different default Huffman tables.
+  The exact same statements apply for progressive JPEG: the default tables
+  don't work for progressive mode.  (This may get fixed, however.) }
+
+{$define INPUT_SMOOTHING_SUPPORTED}   { Input image smoothing option? }
+
+{ Decoder capability options: }
+
+{$undef  D_ARITH_CODING_SUPPORTED}    { Arithmetic coding back end? }
+{$define D_MULTISCAN_FILES_SUPPORTED} { Multiple-scan JPEG files? }
+{$define D_PROGRESSIVE_SUPPORTED}     { Progressive JPEG? (Requires MULTISCAN)}
+{$define SAVE_MARKERS_SUPPORTED}      { jpeg_save_markers() needed? }
+{$define BLOCK_SMOOTHING_SUPPORTED}   { Block smoothing? (Progressive only) }
+{$define IDCT_SCALING_SUPPORTED}      { Output rescaling via IDCT? }
+{$undef  UPSAMPLE_SCALING_SUPPORTED}  { Output rescaling at upsample stage? }
+{$define UPSAMPLE_MERGING_SUPPORTED}  { Fast path for sloppy upsampling? }
+{$define QUANT_1PASS_SUPPORTED}       { 1-pass color quantization? }
+{$define QUANT_2PASS_SUPPORTED}       { 2-pass color quantization? }
+
+{ If you happen not to want the image transform support, disable it here }
+{$define TRANSFORMS_SUPPORTED}
+
+{ more capability options later, no doubt }
+
+{$ifopt I+} {$define IOcheck} {$endif}
+
+{ ------------------------------------------------------------------------ }
+
+{$define USE_FMEM}              { Borland has _fmemcpy() and _fmemset() }
+
+{$define FMEMCOPY}
+{$define FMEMZERO}
+
+{$define DCTSIZE_IS_8}          { e.g. unroll the inner loop }
+{$define RIGHT_SHIFT_IS_UNSIGNED}
+{$undef AVOID_TABLES}
+{$undef FAST_DIVIDE}
+
+{$define BITS_IN_JSAMPLE_IS_8}
+
+{----------------------------------------------------------------}
+{ for test of 12 bit JPEG code only. !! }
+{-- $undef  BITS_IN_JSAMPLE_IS_8}
+{----------------------------------------------------------------}
+
+//{$define RGB_RED_IS_0}
+{ !CHANGE: This must be defined for Delphi/Kylix/FPC }
+{$define RGB_RED_IS_2}          { RGB byte order }
+
+
+{$define RGB_PIXELSIZE_IS_3}
+{$define SLOW_SHIFT_32}
+{$undef NO_ZERO_ROW_TEST}
+
+{$define USE_MSDOS_MEMMGR}      { Define this if you use jmemdos.c }
+{$define XMS_SUPPORTED}
+{$define EMS_SUPPORTED}
+
+{$undef MEM_STATS}              { Write out memory usage }
+{$define AM_MEMORY_MANAGER}     { we define jvirt_Xarray_control structs }
+
+{$undef FULL_MAIN_BUFFER_SUPPORTED}
+
+{$define PROGRESS_REPORT}
+{$define TWO_FILE_COMMANDLINE}
+{$undef BMP_SUPPORTED}
+{$undef PPM_SUPPORTED}
+{$undef GIF_SUPPORTED}
+{$undef RLE_SUPPORTED}
+{$undef TARGA_SUPPORTED}
+{$define EXT_SWITCH}
+
+{$ifndef BITS_IN_JSAMPLE_IS_8}  { for 12 bit samples }
+{$undef BMP_SUPPORTED}
+{$undef RLE_SUPPORTED}
+{$undef TARGA_SUPPORTED}
+{$endif}
+
+
+{!CHANGE: Allowed only for Delphi}
+{$undef BASM16}                  { for TP7 - use BASM for fast multiply }
+{$ifdef Win32}
+  {$ifndef FPC}
+    {$define BASM}                 { jidctint with BASM for Delphi 2/3 }
+    {$undef RGB_RED_IS_0}          { BGR byte order in JQUANT2 }
+  {$endif}
+{$endif}
+
+{$ifdef FPC}
+  {$MODE DELPHI}
+{$endif}
+
+{!CHANGE: Added this}
+{$define Delphi_Stream}
+{$Q-}
+{$MINENUMSIZE 4}
+{$ALIGN 8}
diff --git a/src/lib/vampimg/JpegLib/imjcparam.pas b/src/lib/vampimg/JpegLib/imjcparam.pas
new file mode 100644 (file)
index 0000000..66117ca
--- /dev/null
@@ -0,0 +1,701 @@
+unit imjcparam;
+
+{ This file contains optional default-setting code for the JPEG compressor.
+  Applications do not have to use this file, but those that don't use it
+  must know a lot more about the innards of the JPEG code. }
+
+{ Original: jcparam.c ; Copyright (C) 1991-1998, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjcomapi,
+  imjpeglib;
+
+{ Quantization table setup routines }
+
+{GLOBAL}
+procedure jpeg_add_quant_table (cinfo : j_compress_ptr;
+                                which_tbl : int;
+                    const basic_table : array of uInt;
+                    scale_factor : int;
+                                force_baseline : boolean);
+
+{GLOBAL}
+procedure jpeg_set_linear_quality (cinfo : j_compress_ptr;
+                                   scale_factor : int;
+                 force_baseline : boolean);
+{ Set or change the 'quality' (quantization) setting, using default tables
+  and a straight percentage-scaling quality scale.  In most cases it's better
+  to use jpeg_set_quality (below); this entry point is provided for
+  applications that insist on a linear percentage scaling. }
+
+{GLOBAL}
+function jpeg_quality_scaling (quality : int) : int;
+{ Convert a user-specified quality rating to a percentage scaling factor
+  for an underlying quantization table, using our recommended scaling curve.
+  The input 'quality' factor should be 0 (terrible) to 100 (very good). }
+
+{GLOBAL}
+procedure jpeg_set_quality (cinfo : j_compress_ptr;
+                            quality : int;
+                            force_baseline : boolean);
+{ Set or change the 'quality' (quantization) setting, using default tables.
+  This is the standard quality-adjusting entry point for typical user
+  interfaces; only those who want detailed control over quantization tables
+  would use the preceding three routines directly. }
+
+{GLOBAL}
+procedure jpeg_set_defaults (cinfo : j_compress_ptr);
+
+{ Create a recommended progressive-JPEG script.
+  cinfo^.num_components and cinfo^.jpeg_color_space must be correct. }
+
+{ Set the JPEG colorspace, and choose colorspace-dependent default values. }
+
+{GLOBAL}
+procedure jpeg_set_colorspace (cinfo : j_compress_ptr;
+                               colorspace : J_COLOR_SPACE);
+
+{ Select an appropriate JPEG colorspace for in_color_space. }
+
+{GLOBAL}
+procedure jpeg_default_colorspace (cinfo : j_compress_ptr);
+
+{GLOBAL}
+procedure jpeg_simple_progression (cinfo : j_compress_ptr);
+
+
+implementation
+
+{ Quantization table setup routines }
+
+{GLOBAL}
+procedure jpeg_add_quant_table (cinfo : j_compress_ptr;
+                      which_tbl : int;
+          const basic_table : array of uInt;
+          scale_factor : int;
+                      force_baseline : boolean);
+{ Define a quantization table equal to the basic_table times
+  a scale factor (given as a percentage).
+  If force_baseline is TRUE, the computed quantization table entries
+  are limited to 1..255 for JPEG baseline compatibility. }
+var
+  qtblptr :^JQUANT_TBL_PTR;
+  i : int;
+  temp : long;
+begin
+  { Safety check to ensure start_compress not called yet. }
+  if (cinfo^.global_state <> CSTATE_START) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  if (which_tbl < 0) or (which_tbl >= NUM_QUANT_TBLS) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_DQT_INDEX, which_tbl);
+
+  qtblptr := @(cinfo^.quant_tbl_ptrs[which_tbl]);
+
+  if (qtblptr^ = NIL) then
+    qtblptr^ := jpeg_alloc_quant_table(j_common_ptr(cinfo));
+
+  for i := 0 to pred(DCTSIZE2) do
+  begin
+    temp := (long(basic_table[i]) * scale_factor + long(50)) div long(100);
+    { limit the values to the valid range }
+    if (temp <= long(0)) then
+      temp := long(1);
+    if (temp > long(32767)) then
+      temp := long(32767); { max quantizer needed for 12 bits }
+    if (force_baseline) and (temp > long(255)) then
+      temp := long(255);    { limit to baseline range if requested }
+    (qtblptr^)^.quantval[i] := UINT16 (temp);
+  end;
+
+  { Initialize sent_table FALSE so table will be written to JPEG file. }
+  (qtblptr^)^.sent_table := FALSE;
+end;
+
+
+{GLOBAL}
+procedure jpeg_set_linear_quality (cinfo : j_compress_ptr;
+                                   scale_factor : int;
+                 force_baseline : boolean);
+{ Set or change the 'quality' (quantization) setting, using default tables
+  and a straight percentage-scaling quality scale.  In most cases it's better
+  to use jpeg_set_quality (below); this entry point is provided for
+  applications that insist on a linear percentage scaling. }
+
+{ These are the sample quantization tables given in JPEG spec section K.1.
+  The spec says that the values given produce "good" quality, and
+  when divided by 2, "very good" quality. }
+
+const
+  std_luminance_quant_tbl : array[0..DCTSIZE2-1] of uInt =
+   (16,  11,  10,  16,  24,  40,  51,  61,
+    12,  12,  14,  19,  26,  58,  60,  55,
+    14,  13,  16,  24,  40,  57,  69,  56,
+    14,  17,  22,  29,  51,  87,  80,  62,
+    18,  22,  37,  56,  68, 109, 103,  77,
+    24,  35,  55,  64,  81, 104, 113,  92,
+    49,  64,  78,  87, 103, 121, 120, 101,
+    72,  92,  95,  98, 112, 100, 103,  99);
+
+const
+  std_chrominance_quant_tbl : array[0..DCTSIZE2-1] of uInt =
+   (17,  18,  24,  47,  99,  99,  99,  99,
+    18,  21,  26,  66,  99,  99,  99,  99,
+    24,  26,  56,  99,  99,  99,  99,  99,
+    47,  66,  99,  99,  99,  99,  99,  99,
+    99,  99,  99,  99,  99,  99,  99,  99,
+    99,  99,  99,  99,  99,  99,  99,  99,
+    99,  99,  99,  99,  99,  99,  99,  99,
+    99,  99,  99,  99,  99,  99,  99,  99);
+begin
+  { Set up two quantization tables using the specified scaling }
+  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+           scale_factor, force_baseline);
+  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+           scale_factor, force_baseline);
+end;
+
+
+{GLOBAL}
+function jpeg_quality_scaling (quality : int) : int;
+{ Convert a user-specified quality rating to a percentage scaling factor
+  for an underlying quantization table, using our recommended scaling curve.
+  The input 'quality' factor should be 0 (terrible) to 100 (very good). }
+begin
+  { Safety limit on quality factor.  Convert 0 to 1 to avoid zero divide. }
+  if (quality <= 0) then
+    quality := 1;
+  if (quality > 100) then
+    quality := 100;
+
+  { The basic table is used as-is (scaling 100) for a quality of 50.
+    Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
+    note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
+    to make all the table entries 1 (hence, minimum quantization loss).
+    Qualities 1..50 are converted to scaling percentage 5000/Q. }
+  if (quality < 50) then
+    quality := 5000 div quality
+  else
+    quality := 200 - quality*2;
+
+  jpeg_quality_scaling := quality;
+end;
+
+
+{GLOBAL}
+procedure jpeg_set_quality (cinfo : j_compress_ptr;
+                            quality : int;
+                            force_baseline : boolean);
+{ Set or change the 'quality' (quantization) setting, using default tables.
+  This is the standard quality-adjusting entry point for typical user
+  interfaces; only those who want detailed control over quantization tables
+  would use the preceding three routines directly. }
+begin
+  { Convert user 0-100 rating to percentage scaling }
+  quality := jpeg_quality_scaling(quality);
+
+  { Set up standard quality tables }
+  jpeg_set_linear_quality(cinfo, quality, force_baseline);
+end;
+
+
+{ Huffman table setup routines }
+
+{LOCAL}
+procedure add_huff_table (cinfo : j_compress_ptr;
+                          var htblptr : JHUFF_TBL_PTR;
+                          var bits : array of UINT8;
+                          var val : array of UINT8);
+{ Define a Huffman table }
+var
+  nsymbols, len : int;
+begin
+  if (htblptr = NIL) then
+    htblptr := jpeg_alloc_huff_table(j_common_ptr(cinfo));
+
+  { Copy the number-of-symbols-of-each-code-length counts }
+  MEMCOPY(@htblptr^.bits, @bits, SIZEOF(htblptr^.bits));
+
+
+  { Validate the counts.  We do this here mainly so we can copy the right
+    number of symbols from the val[] array, without risking marching off
+    the end of memory.  jchuff.c will do a more thorough test later. }
+
+  nsymbols := 0;
+  for len := 1 to 16 do
+    Inc(nsymbols, bits[len]);
+  if (nsymbols < 1) or (nsymbols > 256) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+
+  MEMCOPY(@htblptr^.huffval, @val, nsymbols * SIZEOF(UINT8));
+
+  { Initialize sent_table FALSE so table will be written to JPEG file. }
+  (htblptr)^.sent_table := FALSE;
+end;
+
+
+{$J+}
+{LOCAL}
+procedure std_huff_tables (cinfo : j_compress_ptr);
+{ Set up the standard Huffman tables (cf. JPEG standard section K.3) }
+{ IMPORTANT: these are only valid for 8-bit data precision! }
+  const bits_dc_luminance : array[0..17-1] of UINT8 =
+    ({ 0-base } 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0);
+  const val_dc_luminance : array[0..11] of UINT8 =
+    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+
+  const bits_dc_chrominance : array[0..17-1] of UINT8 =
+    ( { 0-base } 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+  const val_dc_chrominance : array[0..11] of UINT8 =
+    ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 );
+
+  const bits_ac_luminance : array[0..17-1] of UINT8 =
+    ( { 0-base } 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, $7d );
+  const val_ac_luminance : array[0..161] of UINT8 =
+    ( $01, $02, $03, $00, $04, $11, $05, $12,
+      $21, $31, $41, $06, $13, $51, $61, $07,
+      $22, $71, $14, $32, $81, $91, $a1, $08,
+      $23, $42, $b1, $c1, $15, $52, $d1, $f0,
+      $24, $33, $62, $72, $82, $09, $0a, $16,
+      $17, $18, $19, $1a, $25, $26, $27, $28,
+      $29, $2a, $34, $35, $36, $37, $38, $39,
+      $3a, $43, $44, $45, $46, $47, $48, $49,
+      $4a, $53, $54, $55, $56, $57, $58, $59,
+      $5a, $63, $64, $65, $66, $67, $68, $69,
+      $6a, $73, $74, $75, $76, $77, $78, $79,
+      $7a, $83, $84, $85, $86, $87, $88, $89,
+      $8a, $92, $93, $94, $95, $96, $97, $98,
+      $99, $9a, $a2, $a3, $a4, $a5, $a6, $a7,
+      $a8, $a9, $aa, $b2, $b3, $b4, $b5, $b6,
+      $b7, $b8, $b9, $ba, $c2, $c3, $c4, $c5,
+      $c6, $c7, $c8, $c9, $ca, $d2, $d3, $d4,
+      $d5, $d6, $d7, $d8, $d9, $da, $e1, $e2,
+      $e3, $e4, $e5, $e6, $e7, $e8, $e9, $ea,
+      $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8,
+      $f9, $fa );
+
+  const bits_ac_chrominance : array[0..17-1] of UINT8 =
+    ( { 0-base } 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, $77 );
+  const val_ac_chrominance : array[0..161] of UINT8 =
+    ( $00, $01, $02, $03, $11, $04, $05, $21,
+      $31, $06, $12, $41, $51, $07, $61, $71,
+      $13, $22, $32, $81, $08, $14, $42, $91,
+      $a1, $b1, $c1, $09, $23, $33, $52, $f0,
+      $15, $62, $72, $d1, $0a, $16, $24, $34,
+      $e1, $25, $f1, $17, $18, $19, $1a, $26,
+      $27, $28, $29, $2a, $35, $36, $37, $38,
+      $39, $3a, $43, $44, $45, $46, $47, $48,
+      $49, $4a, $53, $54, $55, $56, $57, $58,
+      $59, $5a, $63, $64, $65, $66, $67, $68,
+      $69, $6a, $73, $74, $75, $76, $77, $78,
+      $79, $7a, $82, $83, $84, $85, $86, $87,
+      $88, $89, $8a, $92, $93, $94, $95, $96,
+      $97, $98, $99, $9a, $a2, $a3, $a4, $a5,
+      $a6, $a7, $a8, $a9, $aa, $b2, $b3, $b4,
+      $b5, $b6, $b7, $b8, $b9, $ba, $c2, $c3,
+      $c4, $c5, $c6, $c7, $c8, $c9, $ca, $d2,
+      $d3, $d4, $d5, $d6, $d7, $d8, $d9, $da,
+      $e2, $e3, $e4, $e5, $e6, $e7, $e8, $e9,
+      $ea, $f2, $f3, $f4, $f5, $f6, $f7, $f8,
+      $f9, $fa );
+begin
+  add_huff_table(cinfo, cinfo^.dc_huff_tbl_ptrs[0],
+  bits_dc_luminance, val_dc_luminance);
+  add_huff_table(cinfo, cinfo^.ac_huff_tbl_ptrs[0],
+  bits_ac_luminance, val_ac_luminance);
+  add_huff_table(cinfo, cinfo^.dc_huff_tbl_ptrs[1],
+  bits_dc_chrominance, val_dc_chrominance);
+  add_huff_table(cinfo, cinfo^.ac_huff_tbl_ptrs[1],
+  bits_ac_chrominance, val_ac_chrominance);
+end;
+
+
+{ Default parameter setup for compression.
+
+  Applications that don't choose to use this routine must do their
+  own setup of all these parameters.  Alternately, you can call this
+  to establish defaults and then alter parameters selectively.  This
+  is the recommended approach since, if we add any new parameters,
+  your code will still work (they'll be set to reasonable defaults). }
+
+{GLOBAL}
+procedure jpeg_set_defaults (cinfo : j_compress_ptr);
+var
+  i : int;
+begin
+  { Safety check to ensure start_compress not called yet. }
+  if (cinfo^.global_state <> CSTATE_START) then
+    ERREXIT1(J_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  { Allocate comp_info array large enough for maximum component count.
+    Array is made permanent in case application wants to compress
+    multiple images at same param settings. }
+
+  if (cinfo^.comp_info = NIL) then
+    cinfo^.comp_info := jpeg_component_info_list_ptr(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT,
+             MAX_COMPONENTS * SIZEOF(jpeg_component_info)) );
+
+  { Initialize everything not dependent on the color space }
+
+  cinfo^.data_precision := BITS_IN_JSAMPLE;
+  { Set up two quantization tables using default quality of 75 }
+  jpeg_set_quality(cinfo, 75, TRUE);
+  { Set up two Huffman tables }
+  std_huff_tables(cinfo);
+
+  { Initialize default arithmetic coding conditioning }
+  for i := 0 to pred(NUM_ARITH_TBLS) do
+  begin
+    cinfo^.arith_dc_L[i] := 0;
+    cinfo^.arith_dc_U[i] := 1;
+    cinfo^.arith_ac_K[i] := 5;
+  end;
+
+  { Default is no multiple-scan output }
+  cinfo^.scan_info := NIL;
+  cinfo^.num_scans := 0;
+
+  { Expect normal source image, not raw downsampled data }
+  cinfo^.raw_data_in := FALSE;
+
+  { Use Huffman coding, not arithmetic coding, by default }
+  cinfo^.arith_code := FALSE;
+
+  { By default, don't do extra passes to optimize entropy coding }
+  cinfo^.optimize_coding := FALSE;
+  { The standard Huffman tables are only valid for 8-bit data precision.
+    If the precision is higher, force optimization on so that usable
+    tables will be computed.  This test can be removed if default tables
+    are supplied that are valid for the desired precision. }
+
+  if (cinfo^.data_precision > 8) then
+    cinfo^.optimize_coding := TRUE;
+
+  { By default, use the simpler non-cosited sampling alignment }
+  cinfo^.CCIR601_sampling := FALSE;
+
+  { No input smoothing }
+  cinfo^.smoothing_factor := 0;
+
+  { DCT algorithm preference }
+  cinfo^.dct_method := JDCT_DEFAULT;
+
+  { No restart markers }
+  cinfo^.restart_interval := 0;
+  cinfo^.restart_in_rows := 0;
+
+  { Fill in default JFIF marker parameters.  Note that whether the marker
+    will actually be written is determined by jpeg_set_colorspace.
+
+    By default, the library emits JFIF version code 1.01.
+    An application that wants to emit JFIF 1.02 extension markers should set
+    JFIF_minor_version to 2.  We could probably get away with just defaulting
+    to 1.02, but there may still be some decoders in use that will complain
+    about that; saying 1.01 should minimize compatibility problems. }
+
+  cinfo^.JFIF_major_version := 1; { Default JFIF version = 1.01 }
+  cinfo^.JFIF_minor_version := 1;
+  cinfo^.density_unit := 0; { Pixel size is unknown by default }
+  cinfo^.X_density := 1;    { Pixel aspect ratio is square by default }
+  cinfo^.Y_density := 1;
+
+  { Choose JPEG colorspace based on input space, set defaults accordingly }
+
+  jpeg_default_colorspace(cinfo);
+end;
+
+
+{ Select an appropriate JPEG colorspace for in_color_space. }
+
+{GLOBAL}
+procedure jpeg_default_colorspace (cinfo : j_compress_ptr);
+begin
+  case (cinfo^.in_color_space) of
+  JCS_GRAYSCALE:
+    jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+  JCS_RGB:
+    jpeg_set_colorspace(cinfo, JCS_YCbCr);
+  JCS_YCbCr:
+    jpeg_set_colorspace(cinfo, JCS_YCbCr);
+  JCS_CMYK:
+    jpeg_set_colorspace(cinfo, JCS_CMYK); { By default, no translation }
+  JCS_YCCK:
+    jpeg_set_colorspace(cinfo, JCS_YCCK);
+  JCS_UNKNOWN:
+    jpeg_set_colorspace(cinfo, JCS_UNKNOWN);
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
+  end;
+end;
+
+
+{ Set the JPEG colorspace, and choose colorspace-dependent default values. }
+
+{GLOBAL}
+procedure jpeg_set_colorspace (cinfo : j_compress_ptr;
+                               colorspace : J_COLOR_SPACE);
+  { macro }
+  procedure SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl : int);
+  begin
+    with cinfo^.comp_info^[index] do
+    begin
+      component_id := (id);
+      h_samp_factor := (hsamp);
+      v_samp_factor := (vsamp);
+      quant_tbl_no := (quant);
+      dc_tbl_no := (dctbl);
+      ac_tbl_no := (actbl);
+    end;
+  end;
+
+var
+  ci : int;
+begin
+  { Safety check to ensure start_compress not called yet. }
+  if (cinfo^.global_state <> CSTATE_START) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  { For all colorspaces, we use Q and Huff tables 0 for luminance components,
+    tables 1 for chrominance components. }
+
+  cinfo^.jpeg_color_space := colorspace;
+
+  cinfo^.write_JFIF_header := FALSE; { No marker for non-JFIF colorspaces }
+  cinfo^.write_Adobe_marker := FALSE; { write no Adobe marker by default }
+
+  case (colorspace) of
+  JCS_GRAYSCALE:
+    begin
+      cinfo^.write_JFIF_header := TRUE; { Write a JFIF marker }
+      cinfo^.num_components := 1;
+      { JFIF specifies component ID 1 }
+      SET_COMP(0, 1, 1,1, 0, 0,0);
+    end;
+  JCS_RGB:
+    begin
+      cinfo^.write_Adobe_marker := TRUE; { write Adobe marker to flag RGB }
+      cinfo^.num_components := 3;
+      SET_COMP(0, $52 { 'R' }, 1,1, 0, 0,0);
+      SET_COMP(1, $47 { 'G' }, 1,1, 0, 0,0);
+      SET_COMP(2, $42 { 'B' }, 1,1, 0, 0,0);
+    end;
+  JCS_YCbCr:
+    begin
+      cinfo^.write_JFIF_header := TRUE; { Write a JFIF marker }
+      cinfo^.num_components := 3;
+      { JFIF specifies component IDs 1,2,3 }
+      { We default to 2x2 subsamples of chrominance }
+      SET_COMP(0, 1, 2,2, 0, 0,0);
+      SET_COMP(1, 2, 1,1, 1, 1,1);
+      SET_COMP(2, 3, 1,1, 1, 1,1);
+    end;
+  JCS_CMYK:
+    begin
+      cinfo^.write_Adobe_marker := TRUE; { write Adobe marker to flag CMYK }
+      cinfo^.num_components := 4;
+      SET_COMP(0, $43 { 'C' }, 1,1, 0, 0,0);
+      SET_COMP(1, $4D { 'M' }, 1,1, 0, 0,0);
+      SET_COMP(2, $59 { 'Y' }, 1,1, 0, 0,0);
+      SET_COMP(3, $4B { 'K' }, 1,1, 0, 0,0);
+    end;
+  JCS_YCCK:
+    begin
+      cinfo^.write_Adobe_marker := TRUE; { write Adobe marker to flag YCCK }
+      cinfo^.num_components := 4;
+      SET_COMP(0, 1, 2,2, 0, 0,0);
+      SET_COMP(1, 2, 1,1, 1, 1,1);
+      SET_COMP(2, 3, 1,1, 1, 1,1);
+      SET_COMP(3, 4, 2,2, 0, 0,0);
+    end;
+  JCS_UNKNOWN:
+    begin
+      cinfo^.num_components := cinfo^.input_components;
+      if (cinfo^.num_components < 1)
+      or (cinfo^.num_components > MAX_COMPONENTS) then
+        ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT,
+                 cinfo^.num_components, MAX_COMPONENTS);
+      for ci := 0 to pred(cinfo^.num_components) do
+      begin
+        SET_COMP(ci, ci, 1,1, 0, 0,0);
+      end;
+    end;
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+  end;
+end;
+
+
+{$ifdef C_PROGRESSIVE_SUPPORTED}
+
+{LOCAL}
+function fill_a_scan (scanptr : jpeg_scan_info_ptr;
+                      ci : int; Ss : int;
+                      Se : int; Ah : int;
+                      Al : int) : jpeg_scan_info_ptr;
+{ Support routine: generate one scan for specified component }
+begin
+  scanptr^.comps_in_scan := 1;
+  scanptr^.component_index[0] := ci;
+  scanptr^.Ss := Ss;
+  scanptr^.Se := Se;
+  scanptr^.Ah := Ah;
+  scanptr^.Al := Al;
+  Inc(scanptr);
+  fill_a_scan := scanptr;
+end;
+
+{LOCAL}
+function fill_scans (scanptr : jpeg_scan_info_ptr;
+                     ncomps : int;
+               Ss : int; Se : int;
+                     Ah : int; Al : int) : jpeg_scan_info_ptr;
+{ Support routine: generate one scan for each component }
+var
+  ci : int;
+begin
+
+  for ci := 0 to pred(ncomps) do
+  begin
+    scanptr^.comps_in_scan := 1;
+    scanptr^.component_index[0] := ci;
+    scanptr^.Ss := Ss;
+    scanptr^.Se := Se;
+    scanptr^.Ah := Ah;
+    scanptr^.Al := Al;
+    Inc(scanptr);
+  end;
+  fill_scans := scanptr;
+end;
+
+{LOCAL}
+function fill_dc_scans (scanptr : jpeg_scan_info_ptr;
+                        ncomps : int;
+                        Ah : int; Al : int) : jpeg_scan_info_ptr;
+{ Support routine: generate interleaved DC scan if possible, else N scans }
+var
+  ci : int;
+begin
+
+  if (ncomps <= MAX_COMPS_IN_SCAN) then
+  begin
+    { Single interleaved DC scan }
+    scanptr^.comps_in_scan := ncomps;
+    for ci := 0 to pred(ncomps) do
+      scanptr^.component_index[ci] := ci;
+    scanptr^.Ss := 0;
+    scanptr^.Se := 0;
+    scanptr^.Ah := Ah;
+    scanptr^.Al := Al;
+    Inc(scanptr);
+  end
+  else
+  begin
+    { Noninterleaved DC scan for each component }
+    scanptr := fill_scans(scanptr, ncomps, 0, 0, Ah, Al);
+  end;
+  fill_dc_scans := scanptr;
+end;
+
+
+{ Create a recommended progressive-JPEG script.
+  cinfo^.num_components and cinfo^.jpeg_color_space must be correct. }
+
+{GLOBAL}
+procedure jpeg_simple_progression (cinfo : j_compress_ptr);
+var
+  ncomps : int;
+  nscans : int;
+  scanptr : jpeg_scan_info_ptr;
+begin
+  ncomps := cinfo^.num_components;
+
+  { Safety check to ensure start_compress not called yet. }
+  if (cinfo^.global_state <> CSTATE_START) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  { Figure space needed for script.  Calculation must match code below! }
+  if (ncomps = 3) and (cinfo^.jpeg_color_space = JCS_YCbCr) then
+  begin
+    { Custom script for YCbCr color images. }
+    nscans := 10;
+  end
+  else
+  begin
+    { All-purpose script for other color spaces. }
+    if (ncomps > MAX_COMPS_IN_SCAN) then
+      nscans := 6 * ncomps  { 2 DC + 4 AC scans per component }
+    else
+      nscans := 2 + 4 * ncomps; { 2 DC scans; 4 AC scans per component }
+  end;
+
+  { Allocate space for script.
+    We need to put it in the permanent pool in case the application performs
+    multiple compressions without changing the settings.  To avoid a memory
+    leak if jpeg_simple_progression is called repeatedly for the same JPEG
+    object, we try to re-use previously allocated space, and we allocate
+    enough space to handle YCbCr even if initially asked for grayscale. }
+
+  if (cinfo^.script_space = NIL) or (cinfo^.script_space_size < nscans) then
+  begin
+    if nscans > 10 then
+      cinfo^.script_space_size := nscans
+    else
+      cinfo^.script_space_size := 10;
+
+    cinfo^.script_space := jpeg_scan_info_ptr(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT,
+    cinfo^.script_space_size * SIZEOF(jpeg_scan_info)) );
+  end;
+  scanptr := cinfo^.script_space;
+
+  cinfo^.scan_info := scanptr;
+  cinfo^.num_scans := nscans;
+
+  if (ncomps = 3) and (cinfo^.jpeg_color_space = JCS_YCbCr) then
+  begin
+    { Custom script for YCbCr color images. }
+    { Initial DC scan }
+    scanptr := fill_dc_scans(scanptr, ncomps, 0, 1);
+    { Initial AC scan: get some luma data out in a hurry }
+    scanptr := fill_a_scan(scanptr, 0, 1, 5, 0, 2);
+    { Chroma data is too small to be worth expending many scans on }
+    scanptr := fill_a_scan(scanptr, 2, 1, 63, 0, 1);
+    scanptr := fill_a_scan(scanptr, 1, 1, 63, 0, 1);
+    { Complete spectral selection for luma AC }
+    scanptr := fill_a_scan(scanptr, 0, 6, 63, 0, 2);
+    { Refine next bit of luma AC }
+    scanptr := fill_a_scan(scanptr, 0, 1, 63, 2, 1);
+    { Finish DC successive approximation }
+    scanptr := fill_dc_scans(scanptr, ncomps, 1, 0);
+    { Finish AC successive approximation }
+    scanptr := fill_a_scan(scanptr, 2, 1, 63, 1, 0);
+    scanptr := fill_a_scan(scanptr, 1, 1, 63, 1, 0);
+    { Luma bottom bit comes last since it's usually largest scan }
+    scanptr := fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+  end
+  else
+  begin
+    { All-purpose script for other color spaces. }
+    { Successive approximation first pass }
+    scanptr := fill_dc_scans(scanptr, ncomps, 0, 1);
+    scanptr := fill_scans(scanptr, ncomps, 1, 5, 0, 2);
+    scanptr := fill_scans(scanptr, ncomps, 6, 63, 0, 2);
+    { Successive approximation second pass }
+    scanptr := fill_scans(scanptr, ncomps, 1, 63, 2, 1);
+    { Successive approximation final pass }
+    scanptr := fill_dc_scans(scanptr, ncomps, 1, 0);
+    scanptr := fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+  end;
+end;
+
+{$endif}
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcphuff.pas b/src/lib/vampimg/JpegLib/imjcphuff.pas
new file mode 100644 (file)
index 0000000..3c9dbf7
--- /dev/null
@@ -0,0 +1,962 @@
+unit imjcphuff;
+
+{ This file contains Huffman entropy encoding routines for progressive JPEG.
+
+  We do not support output suspension in this module, since the library
+  currently does not allow multiple-scan files to be written with output
+  suspension. }
+
+{ Original: jcphuff.c;  Copyright (C) 1995-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjcomapi,
+  imjchuff;         { Declarations shared with jchuff.c }
+
+{ Module initialization routine for progressive Huffman entropy encoding. }
+
+{GLOBAL}
+procedure jinit_phuff_encoder (cinfo : j_compress_ptr);
+
+implementation
+
+{ Expanded entropy encoder object for progressive Huffman encoding. }
+type
+  phuff_entropy_ptr = ^phuff_entropy_encoder;
+  phuff_entropy_encoder = record
+    pub : jpeg_entropy_encoder; { public fields }
+
+    { Mode flag: TRUE for optimization, FALSE for actual data output }
+    gather_statistics : boolean;
+
+    { Bit-level coding status.
+      next_output_byte/free_in_buffer are local copies of cinfo^.dest fields.}
+
+    next_output_byte : JOCTETptr; { => next byte to write in buffer }
+    free_in_buffer : size_t;    { # of byte spaces remaining in buffer }
+    put_buffer : INT32;   { current bit-accumulation buffer }
+    put_bits : int;             { # of bits now in it }
+    cinfo : j_compress_ptr;     { link to cinfo (needed for dump_buffer) }
+
+    { Coding status for DC components }
+    last_dc_val : array[0..MAX_COMPS_IN_SCAN-1] of int;
+                                { last DC coef for each component }
+
+    { Coding status for AC components }
+    ac_tbl_no : int;            { the table number of the single component }
+    EOBRUN : uInt;              { run length of EOBs }
+    BE : uInt;                  { # of buffered correction bits before MCU }
+    bit_buffer : JBytePtr;      { buffer for correction bits (1 per char) }
+    { packing correction bits tightly would save some space but cost time... }
+
+    restarts_to_go : uInt;  { MCUs left in this restart interval }
+    next_restart_num : int;     { next restart number to write (0-7) }
+
+    { Pointers to derived tables (these workspaces have image lifespan).
+      Since any one scan codes only DC or only AC, we only need one set
+      of tables, not one for DC and one for AC. }
+
+    derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr;
+
+    { Statistics tables for optimization; again, one set is enough }
+    count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr;
+  end;
+
+
+{ MAX_CORR_BITS is the number of bits the AC refinement correction-bit
+  buffer can hold.  Larger sizes may slightly improve compression, but
+  1000 is already well into the realm of overkill.
+  The minimum safe size is 64 bits. }
+
+const
+  MAX_CORR_BITS = 1000;         { Max # of correction bits I can buffer }
+
+
+{ Forward declarations }
+{METHODDEF}
+function encode_mcu_DC_first (cinfo : j_compress_ptr;
+                              const MCU_data: array of JBLOCKROW) : boolean;
+                              forward;
+{METHODDEF}
+function encode_mcu_AC_first (cinfo : j_compress_ptr;
+                              const MCU_data: array of JBLOCKROW) : boolean;
+                              forward;
+{METHODDEF}
+function encode_mcu_DC_refine (cinfo : j_compress_ptr;
+                              const MCU_data: array of JBLOCKROW) : boolean;
+                              forward;
+{METHODDEF}
+function encode_mcu_AC_refine (cinfo : j_compress_ptr;
+                              const MCU_data: array of JBLOCKROW) : boolean;
+                              forward;
+
+{METHODDEF}
+procedure finish_pass_phuff (cinfo : j_compress_ptr); forward;
+
+{METHODDEF}
+procedure finish_pass_gather_phuff (cinfo : j_compress_ptr); forward;
+
+
+{ Initialize for a Huffman-compressed scan using progressive JPEG. }
+
+{METHODDEF}
+procedure start_pass_phuff (cinfo : j_compress_ptr;
+                            gather_statistics : boolean);
+var
+  entropy : phuff_entropy_ptr;
+  is_DC_band : boolean;
+  ci, tbl : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  tbl := 0;
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+
+  entropy^.cinfo := cinfo;
+  entropy^.gather_statistics := gather_statistics;
+
+  is_DC_band := (cinfo^.Ss = 0);
+
+  { We assume jcmaster.c already validated the scan parameters. }
+
+  { Select execution routines }
+  if (cinfo^.Ah = 0) then
+  begin
+    if (is_DC_band) then
+      entropy^.pub.encode_mcu := encode_mcu_DC_first
+    else
+      entropy^.pub.encode_mcu := encode_mcu_AC_first;
+  end
+  else
+  begin
+    if (is_DC_band) then
+      entropy^.pub.encode_mcu := encode_mcu_DC_refine
+    else
+    begin
+      entropy^.pub.encode_mcu := encode_mcu_AC_refine;
+      { AC refinement needs a correction bit buffer }
+      if (entropy^.bit_buffer = NIL) then
+  entropy^.bit_buffer := JBytePtr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+              MAX_CORR_BITS * SIZEOF(byte)) );
+    end;
+  end;
+  if (gather_statistics) then
+    entropy^.pub.finish_pass := finish_pass_gather_phuff
+  else
+    entropy^.pub.finish_pass := finish_pass_phuff;
+
+  { Only DC coefficients may be interleaved, so cinfo^.comps_in_scan = 1
+    for AC coefficients. }
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    { Initialize DC predictions to 0 }
+    entropy^.last_dc_val[ci] := 0;
+    { Get table index }
+    if (is_DC_band) then
+    begin
+      if (cinfo^.Ah <> 0) then  { DC refinement needs no table }
+  continue;
+      tbl := compptr^.dc_tbl_no;
+    end
+    else
+    begin
+      tbl := compptr^.ac_tbl_no;
+      entropy^.ac_tbl_no := tbl;
+    end;
+    if (gather_statistics) then
+    begin
+      { Check for invalid table index }
+      { (make_c_derived_tbl does this in the other path) }
+      if (tbl < 0) or (tbl >= NUM_HUFF_TBLS) then
+        ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tbl);
+      { Allocate and zero the statistics tables }
+      { Note that jpeg_gen_optimal_table expects 257 entries in each table! }
+      if (entropy^.count_ptrs[tbl] = NIL) then
+  entropy^.count_ptrs[tbl] := TLongTablePtr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+              257 * SIZEOF(long)) );
+      MEMZERO(entropy^.count_ptrs[tbl], 257 * SIZEOF(long));
+    end else
+    begin
+      { Compute derived values for Huffman table }
+      { We may do this more than once for a table, but it's not expensive }
+      jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl,
+            entropy^.derived_tbls[tbl]);
+    end;
+  end;
+
+  { Initialize AC stuff }
+  entropy^.EOBRUN := 0;
+  entropy^.BE := 0;
+
+  { Initialize bit buffer to empty }
+  entropy^.put_buffer := 0;
+  entropy^.put_bits := 0;
+
+  { Initialize restart stuff }
+  entropy^.restarts_to_go := cinfo^.restart_interval;
+  entropy^.next_restart_num := 0;
+end;
+
+
+
+
+{LOCAL}
+procedure dump_buffer (entropy : phuff_entropy_ptr);
+{ Empty the output buffer; we do not support suspension in this module. }
+var
+  dest : jpeg_destination_mgr_ptr;
+begin
+  dest := entropy^.cinfo^.dest;
+
+  if (not dest^.empty_output_buffer (entropy^.cinfo)) then
+    ERREXIT(j_common_ptr(entropy^.cinfo), JERR_CANT_SUSPEND);
+  { After a successful buffer dump, must reset buffer pointers }
+  entropy^.next_output_byte := dest^.next_output_byte;
+  entropy^.free_in_buffer := dest^.free_in_buffer;
+end;
+
+
+{ Outputting bits to the file }
+
+{ Only the right 24 bits of put_buffer are used; the valid bits are
+  left-justified in this part.  At most 16 bits can be passed to emit_bits
+  in one call, and we never retain more than 7 bits in put_buffer
+  between calls, so 24 bits are sufficient. }
+
+
+{LOCAL}
+procedure emit_bits (entropy : phuff_entropy_ptr;
+                     code : uInt;
+                     size : int); {INLINE}
+{ Emit some bits, unless we are in gather mode }
+var
+  {register} put_buffer : INT32;
+  {register} put_bits : int;
+var
+  c : int;
+begin
+  { This routine is heavily used, so it's worth coding tightly. }
+  put_buffer := INT32 (code);
+  put_bits := entropy^.put_bits;
+
+  { if size is 0, caller used an invalid Huffman table entry }
+  if (size = 0) then
+    ERREXIT(j_common_ptr(entropy^.cinfo), JERR_HUFF_MISSING_CODE);
+
+  if (entropy^.gather_statistics) then
+    exit;     { do nothing if we're only getting stats }
+
+  put_buffer := put_buffer and ((INT32(1) shl size) - 1);
+                                { mask off any extra bits in code }
+
+  Inc(put_bits, size);          { new number of bits in buffer }
+
+  put_buffer := put_buffer shl (24 - put_bits); { align incoming bits }
+
+  put_buffer := put_buffer or entropy^.put_buffer;
+                                { and merge with old buffer contents }
+
+  while (put_bits >= 8) do
+  begin
+    c := int ((put_buffer shr 16) and $FF);
+
+    {emit_byte(entropy, c);}
+    { Outputting bytes to the file.
+      NB: these must be called only when actually outputting,
+      that is, entropy^.gather_statistics = FALSE. }
+    { Emit a byte }
+    entropy^.next_output_byte^ := JOCTET(c);
+    Inc(entropy^.next_output_byte);
+    Dec(entropy^.free_in_buffer);
+    if (entropy^.free_in_buffer = 0) then
+      dump_buffer(entropy);
+
+    if (c = $FF) then
+    begin   { need to stuff a zero byte? }
+      {emit_byte(entropy, 0);}
+      entropy^.next_output_byte^ := JOCTET(0);
+      Inc(entropy^.next_output_byte);
+      Dec(entropy^.free_in_buffer);
+      if (entropy^.free_in_buffer = 0) then
+        dump_buffer(entropy);
+    end;
+    put_buffer := put_buffer shl 8;
+    Dec(put_bits, 8);
+  end;
+
+  entropy^.put_buffer := put_buffer; { update variables }
+  entropy^.put_bits := put_bits;
+end;
+
+
+{LOCAL}
+procedure flush_bits (entropy : phuff_entropy_ptr);
+begin
+  emit_bits(entropy, $7F, 7); { fill any partial byte with ones }
+  entropy^.put_buffer := 0;     { and reset bit-buffer to empty }
+  entropy^.put_bits := 0;
+end;
+
+{ Emit (or just count) a Huffman symbol. }
+
+
+{LOCAL}
+procedure emit_symbol (entropy : phuff_entropy_ptr;
+                       tbl_no : int;
+                       symbol : int); {INLINE}
+var
+  tbl : c_derived_tbl_ptr;
+begin
+  if (entropy^.gather_statistics) then
+    Inc(entropy^.count_ptrs[tbl_no]^[symbol])
+  else
+  begin
+    tbl := entropy^.derived_tbls[tbl_no];
+    emit_bits(entropy, tbl^.ehufco[symbol], tbl^.ehufsi[symbol]);
+  end;
+end;
+
+
+{ Emit bits from a correction bit buffer. }
+
+{LOCAL}
+procedure emit_buffered_bits (entropy : phuff_entropy_ptr;
+                              bufstart : JBytePtr;
+                  nbits : uInt);
+var
+  bufptr : byteptr;
+begin
+  if (entropy^.gather_statistics) then
+    exit;     { no real work }
+
+  bufptr := byteptr(bufstart);
+  while (nbits > 0) do
+  begin
+    emit_bits(entropy, uInt(bufptr^), 1);
+    Inc(bufptr);
+    Dec(nbits);
+  end;
+end;
+
+
+{ Emit any pending EOBRUN symbol. }
+
+{LOCAL}
+procedure emit_eobrun (entropy : phuff_entropy_ptr);
+var
+  {register} temp, nbits : int;
+begin
+  if (entropy^.EOBRUN > 0) then
+  begin                        { if there is any pending EOBRUN }
+    temp := entropy^.EOBRUN;
+    nbits := 0;
+    temp := temp shr 1;
+    while (temp <> 0) do
+    begin
+      Inc(nbits);
+      temp := temp shr 1;
+    end;
+
+    { safety check: shouldn't happen given limited correction-bit buffer }
+    if (nbits > 14) then
+      ERREXIT(j_common_ptr(entropy^.cinfo), JERR_HUFF_MISSING_CODE);
+
+    emit_symbol(entropy, entropy^.ac_tbl_no, nbits shl 4);
+    if (nbits <> 0) then
+      emit_bits(entropy, entropy^.EOBRUN, nbits);
+
+    entropy^.EOBRUN := 0;
+
+    { Emit any buffered correction bits }
+    emit_buffered_bits(entropy, entropy^.bit_buffer, entropy^.BE);
+    entropy^.BE := 0;
+  end;
+end;
+
+
+{ Emit a restart marker & resynchronize predictions. }
+
+{LOCAL}
+procedure emit_restart (entropy : phuff_entropy_ptr;
+                        restart_num : int);
+var
+  ci : int;
+begin
+  emit_eobrun(entropy);
+
+  if (not entropy^.gather_statistics) then
+  begin
+    flush_bits(entropy);
+    {emit_byte(entropy, $FF);}
+    { Outputting bytes to the file.
+      NB: these must be called only when actually outputting,
+      that is, entropy^.gather_statistics = FALSE. }
+
+    entropy^.next_output_byte^ := JOCTET($FF);
+    Inc(entropy^.next_output_byte);
+    Dec(entropy^.free_in_buffer);
+    if (entropy^.free_in_buffer = 0) then
+      dump_buffer(entropy);
+
+    {emit_byte(entropy, JPEG_RST0 + restart_num);}
+    entropy^.next_output_byte^ := JOCTET(JPEG_RST0 + restart_num);
+    Inc(entropy^.next_output_byte);
+    Dec(entropy^.free_in_buffer);
+    if (entropy^.free_in_buffer = 0) then
+      dump_buffer(entropy);
+  end;
+
+  if (entropy^.cinfo^.Ss = 0) then
+  begin
+    { Re-initialize DC predictions to 0 }
+    for ci := 0 to pred(entropy^.cinfo^.comps_in_scan) do
+      entropy^.last_dc_val[ci] := 0;
+  end
+  else
+  begin
+    { Re-initialize all AC-related fields to 0 }
+    entropy^.EOBRUN := 0;
+    entropy^.BE := 0;
+  end;
+end;
+
+
+{ MCU encoding for DC initial scan (either spectral selection,
+  or first pass of successive approximation). }
+
+{METHODDEF}
+function encode_mcu_DC_first (cinfo : j_compress_ptr;
+                              const MCU_data: array of JBLOCKROW) : boolean;
+var
+  entropy : phuff_entropy_ptr;
+  {register} temp, temp2 : int;
+  {register} nbits : int;
+  blkn, ci : int;
+  Al : int;
+  block : JBLOCK_PTR;
+  compptr : jpeg_component_info_ptr;
+  ishift_temp : int;
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+  Al := cinfo^.Al;
+
+  entropy^.next_output_byte := cinfo^.dest^.next_output_byte;
+  entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer;
+
+  { Emit restart marker if needed }
+  if (cinfo^.restart_interval <> 0) then
+    if (entropy^.restarts_to_go = 0) then
+      emit_restart(entropy, entropy^.next_restart_num);
+
+  { Encode the MCU data blocks }
+  for blkn := 0 to pred(cinfo^.blocks_in_MCU) do
+  begin
+    block := JBLOCK_PTR(MCU_data[blkn]);
+    ci := cinfo^.MCU_membership[blkn];
+    compptr := cinfo^.cur_comp_info[ci];
+
+    { Compute the DC value after the required point transform by Al.
+      This is simply an arithmetic right shift. }
+
+    {temp2 := IRIGHT_SHIFT( int(block^[0]), Al);}
+    {IRIGHT_SHIFT_IS_UNSIGNED}
+    ishift_temp := int(block^[0]);
+    if ishift_temp < 0 then
+      temp2 := (ishift_temp shr Al) or ((not 0) shl (16-Al))
+    else
+      temp2 := ishift_temp shr Al;
+
+
+    { DC differences are figured on the point-transformed values. }
+    temp := temp2 - entropy^.last_dc_val[ci];
+    entropy^.last_dc_val[ci] := temp2;
+
+    { Encode the DC coefficient difference per section G.1.2.1 }
+    temp2 := temp;
+    if (temp < 0) then
+    begin
+      temp := -temp;    { temp is abs value of input }
+      { For a negative input, want temp2 := bitwise complement of abs(input) }
+      { This code assumes we are on a two's complement machine }
+      Dec(temp2);
+    end;
+
+    { Find the number of bits needed for the magnitude of the coefficient }
+    nbits := 0;
+    while (temp <> 0) do
+    begin
+      Inc(nbits);
+      temp := temp shr 1;
+    end;
+
+    { Check for out-of-range coefficient values.
+      Since we're encoding a difference, the range limit is twice as much. }
+
+    if (nbits > MAX_COEF_BITS+1) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_DCT_COEF);
+
+    { Count/emit the Huffman-coded symbol for the number of bits }
+    emit_symbol(entropy, compptr^.dc_tbl_no, nbits);
+
+    { Emit that number of bits of the value, if positive, }
+    { or the complement of its magnitude, if negative. }
+    if (nbits <> 0) then       { emit_bits rejects calls with size 0 }
+      emit_bits(entropy, uInt(temp2), nbits);
+  end;
+
+  cinfo^.dest^.next_output_byte := entropy^.next_output_byte;
+  cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer;
+
+  { Update restart-interval state too }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+    begin
+      entropy^.restarts_to_go := cinfo^.restart_interval;
+      Inc(entropy^.next_restart_num);
+      with entropy^ do
+        next_restart_num := next_restart_num and 7;
+    end;
+    Dec(entropy^.restarts_to_go);
+  end;
+
+  encode_mcu_DC_first := TRUE;
+end;
+
+
+{ MCU encoding for AC initial scan (either spectral selection,
+  or first pass of successive approximation). }
+
+{METHODDEF}
+function encode_mcu_AC_first (cinfo : j_compress_ptr;
+                              const MCU_data: array of JBLOCKROW) : boolean;
+var
+  entropy : phuff_entropy_ptr;
+  {register} temp, temp2 : int;
+  {register} nbits : int;
+  {register} r, k : int;
+  Se : int;
+  Al : int;
+  block : JBLOCK_PTR;
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+  Se := cinfo^.Se;
+  Al := cinfo^.Al;
+
+  entropy^.next_output_byte := cinfo^.dest^.next_output_byte;
+  entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer;
+
+  { Emit restart marker if needed }
+  if (cinfo^.restart_interval <> 0) then
+    if (entropy^.restarts_to_go = 0) then
+      emit_restart(entropy, entropy^.next_restart_num);
+
+  { Encode the MCU data block }
+  block := JBLOCK_PTR(MCU_data[0]);
+
+  { Encode the AC coefficients per section G.1.2.2, fig. G.3 }
+
+  r := 0;     { r := run length of zeros }
+
+  for k := cinfo^.Ss to Se do
+  begin
+    temp := (block^[jpeg_natural_order[k]]);
+    if (temp = 0) then
+    begin
+      Inc(r);
+      continue;
+    end;
+    { We must apply the point transform by Al.  For AC coefficients this
+      is an integer division with rounding towards 0.  To do this portably
+      in C, we shift after obtaining the absolute value; so the code is
+      interwoven with finding the abs value (temp) and output bits (temp2). }
+
+    if (temp < 0) then
+    begin
+      temp := -temp;    { temp is abs value of input }
+      temp := temp shr Al;  { apply the point transform }
+      { For a negative coef, want temp2 := bitwise complement of abs(coef) }
+      temp2 := not temp;
+    end
+    else
+    begin
+      temp := temp shr Al;  { apply the point transform }
+      temp2 := temp;
+    end;
+    { Watch out for case that nonzero coef is zero after point transform }
+    if (temp = 0) then
+    begin
+      Inc(r);
+      continue;
+    end;
+
+    { Emit any pending EOBRUN }
+    if (entropy^.EOBRUN > 0) then
+      emit_eobrun(entropy);
+    { if run length > 15, must emit special run-length-16 codes ($F0) }
+    while (r > 15) do
+    begin
+      emit_symbol(entropy, entropy^.ac_tbl_no, $F0);
+      Dec(r, 16);
+    end;
+
+    { Find the number of bits needed for the magnitude of the coefficient }
+    nbits := 0;     { there must be at least one 1 bit }
+    repeat
+      Inc(nbits);
+      temp := temp shr 1;
+    until (temp = 0);
+
+    { Check for out-of-range coefficient values }
+    if (nbits > MAX_COEF_BITS) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_DCT_COEF);
+
+    { Count/emit Huffman symbol for run length / number of bits }
+    emit_symbol(entropy, entropy^.ac_tbl_no, (r shl 4) + nbits);
+
+    { Emit that number of bits of the value, if positive, }
+    { or the complement of its magnitude, if negative. }
+    emit_bits(entropy, uInt(temp2), nbits);
+
+    r := 0;     { reset zero run length }
+  end;
+
+  if (r > 0) then
+  begin             { If there are trailing zeroes, }
+    Inc(entropy^.EOBRUN); { count an EOB }
+    if (entropy^.EOBRUN = $7FFF) then
+      emit_eobrun(entropy); { force it out to avoid overflow }
+  end;
+
+  cinfo^.dest^.next_output_byte := entropy^.next_output_byte;
+  cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer;
+
+  { Update restart-interval state too }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+    begin
+      entropy^.restarts_to_go := cinfo^.restart_interval;
+      Inc(entropy^.next_restart_num);
+      with entropy^ do
+        next_restart_num := next_restart_num and 7;
+    end;
+    Dec(entropy^.restarts_to_go);
+  end;
+
+  encode_mcu_AC_first := TRUE;
+end;
+
+
+{ MCU encoding for DC successive approximation refinement scan.
+  Note: we assume such scans can be multi-component, although the spec
+  is not very clear on the point. }
+
+{METHODDEF}
+function encode_mcu_DC_refine (cinfo : j_compress_ptr;
+                              const MCU_data: array of JBLOCKROW) : boolean;
+var
+  entropy : phuff_entropy_ptr;
+  {register} temp : int;
+  blkn : int;
+  Al : int;
+  block : JBLOCK_PTR;
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+  Al := cinfo^.Al;
+
+  entropy^.next_output_byte := cinfo^.dest^.next_output_byte;
+  entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer;
+
+  { Emit restart marker if needed }
+  if (cinfo^.restart_interval <> 0) then
+    if (entropy^.restarts_to_go = 0) then
+      emit_restart(entropy, entropy^.next_restart_num);
+
+  { Encode the MCU data blocks }
+  for blkn := 0 to pred(cinfo^.blocks_in_MCU) do
+  begin
+    block := JBLOCK_PTR(MCU_data[blkn]);
+
+    { We simply emit the Al'th bit of the DC coefficient value. }
+    temp := block^[0];
+    emit_bits(entropy, uInt(temp shr Al), 1);
+  end;
+
+  cinfo^.dest^.next_output_byte := entropy^.next_output_byte;
+  cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer;
+
+  { Update restart-interval state too }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+    begin
+      entropy^.restarts_to_go := cinfo^.restart_interval;
+      Inc(entropy^.next_restart_num);
+      with entropy^ do
+        next_restart_num := next_restart_num and 7;
+    end;
+    Dec(entropy^.restarts_to_go);
+  end;
+
+  encode_mcu_DC_refine := TRUE;
+end;
+
+
+{ MCU encoding for AC successive approximation refinement scan. }
+
+{METHODDEF}
+function encode_mcu_AC_refine (cinfo : j_compress_ptr;
+                               const MCU_data: array of JBLOCKROW) : boolean;
+
+var
+  entropy : phuff_entropy_ptr;
+  {register} temp : int;
+  {register} r, k : int;
+  EOB : int;
+  BR_buffer : JBytePtr;
+  BR : uInt;
+  Se : int;
+  Al : int;
+  block : JBLOCK_PTR;
+  absvalues : array[0..DCTSIZE2-1] of int;
+begin
+  entropy := phuff_entropy_ptr(cinfo^.entropy);
+  Se := cinfo^.Se;
+  Al := cinfo^.Al;
+
+  entropy^.next_output_byte := cinfo^.dest^.next_output_byte;
+  entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer;
+
+  { Emit restart marker if needed }
+  if (cinfo^.restart_interval <> 0) then
+    if (entropy^.restarts_to_go = 0) then
+      emit_restart(entropy, entropy^.next_restart_num);
+
+  { Encode the MCU data block }
+  block := JBLOCK_PTR(MCU_data[0]);
+
+  { It is convenient to make a pre-pass to determine the transformed
+    coefficients' absolute values and the EOB position. }
+
+  EOB := 0;
+  for k := cinfo^.Ss to Se do
+  begin
+    temp := block^[jpeg_natural_order[k]];
+    { We must apply the point transform by Al.  For AC coefficients this
+      is an integer division with rounding towards 0.  To do this portably
+      in C, we shift after obtaining the absolute value. }
+
+    if (temp < 0) then
+      temp := -temp;    { temp is abs value of input }
+    temp := temp shr Al;    { apply the point transform }
+    absvalues[k] := temp; { save abs value for main pass }
+    if (temp = 1) then
+      EOB := k;     { EOB := index of last newly-nonzero coef }
+  end;
+
+  { Encode the AC coefficients per section G.1.2.3, fig. G.7 }
+
+  r := 0;     { r := run length of zeros }
+  BR := 0;      { BR := count of buffered bits added now }
+  BR_buffer := JBytePtr(@(entropy^.bit_buffer^[entropy^.BE]));
+                                { Append bits to buffer }
+
+  for k := cinfo^.Ss to Se do
+  begin
+    temp := absvalues[k];
+    if (temp = 0) then
+    begin
+      Inc(r);
+      continue;
+    end;
+
+    { Emit any required ZRLs, but not if they can be folded into EOB }
+    while (r > 15) and (k <= EOB) do
+    begin
+      { emit any pending EOBRUN and the BE correction bits }
+      emit_eobrun(entropy);
+      { Emit ZRL }
+      emit_symbol(entropy, entropy^.ac_tbl_no, $F0);
+      Dec(r, 16);
+      { Emit buffered correction bits that must be associated with ZRL }
+      emit_buffered_bits(entropy, BR_buffer, BR);
+      BR_buffer := entropy^.bit_buffer; { BE bits are gone now }
+      BR := 0;
+    end;
+
+    { If the coef was previously nonzero, it only needs a correction bit.
+      NOTE: a straight translation of the spec's figure G.7 would suggest
+      that we also need to test r > 15.  But if r > 15, we can only get here
+      if k > EOB, which implies that this coefficient is not 1. }
+    if (temp > 1) then
+    begin
+      { The correction bit is the next bit of the absolute value. }
+      BR_buffer^[BR] := byte (temp and 1);
+      Inc(BR);
+      continue;
+    end;
+
+    { Emit any pending EOBRUN and the BE correction bits }
+    emit_eobrun(entropy);
+
+    { Count/emit Huffman symbol for run length / number of bits }
+    emit_symbol(entropy, entropy^.ac_tbl_no, (r shl 4) + 1);
+
+    { Emit output bit for newly-nonzero coef }
+    if (block^[jpeg_natural_order[k]] < 0) then
+      temp := 0
+    else
+      temp := 1;
+    emit_bits(entropy, uInt(temp), 1);
+
+    { Emit buffered correction bits that must be associated with this code }
+    emit_buffered_bits(entropy, BR_buffer, BR);
+    BR_buffer := entropy^.bit_buffer; { BE bits are gone now }
+    BR := 0;
+    r := 0;     { reset zero run length }
+  end;
+
+  if (r > 0) or (BR > 0) then
+  begin                         { If there are trailing zeroes, }
+    Inc(entropy^.EOBRUN);       { count an EOB }
+    Inc(entropy^.BE, BR);          { concat my correction bits to older ones }
+    { We force out the EOB if we risk either:
+      1. overflow of the EOB counter;
+      2. overflow of the correction bit buffer during the next MCU. }
+
+    if (entropy^.EOBRUN = $7FFF) or
+       (entropy^.BE > (MAX_CORR_BITS-DCTSIZE2+1)) then
+      emit_eobrun(entropy);
+  end;
+
+  cinfo^.dest^.next_output_byte := entropy^.next_output_byte;
+  cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer;
+
+  { Update restart-interval state too }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+    begin
+      entropy^.restarts_to_go := cinfo^.restart_interval;
+      Inc(entropy^.next_restart_num);
+      with entropy^ do
+        next_restart_num := next_restart_num and 7;
+    end;
+    Dec(entropy^.restarts_to_go);
+  end;
+
+  encode_mcu_AC_refine := TRUE;
+end;
+
+
+{ Finish up at the end of a Huffman-compressed progressive scan. }
+
+{METHODDEF}
+procedure finish_pass_phuff (cinfo : j_compress_ptr);
+var
+  entropy : phuff_entropy_ptr;
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+
+  entropy^.next_output_byte := cinfo^.dest^.next_output_byte;
+  entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer;
+
+  { Flush out any buffered data }
+  emit_eobrun(entropy);
+  flush_bits(entropy);
+
+  cinfo^.dest^.next_output_byte := entropy^.next_output_byte;
+  cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer;
+end;
+
+
+{ Finish up a statistics-gathering pass and create the new Huffman tables. }
+
+{METHODDEF}
+procedure finish_pass_gather_phuff (cinfo : j_compress_ptr);
+var
+  entropy : phuff_entropy_ptr;
+  is_DC_band : boolean;
+  ci, tbl : int;
+  compptr : jpeg_component_info_ptr;
+  htblptr : ^JHUFF_TBL_PTR;
+  did : array[0..NUM_HUFF_TBLS-1] of boolean;
+begin
+  tbl := 0;
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+
+  { Flush out buffered data (all we care about is counting the EOB symbol) }
+  emit_eobrun(entropy);
+
+  is_DC_band := (cinfo^.Ss = 0);
+
+  { It's important not to apply jpeg_gen_optimal_table more than once
+    per table, because it clobbers the input frequency counts! }
+
+  MEMZERO(@did, SIZEOF(did));
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    if (is_DC_band) then
+    begin
+      if (cinfo^.Ah <> 0) then     { DC refinement needs no table }
+  continue;
+      tbl := compptr^.dc_tbl_no;
+    end
+    else
+    begin
+      tbl := compptr^.ac_tbl_no;
+    end;
+    if (not did[tbl]) then
+    begin
+      if (is_DC_band) then
+        htblptr := @(cinfo^.dc_huff_tbl_ptrs[tbl])
+      else
+        htblptr := @(cinfo^.ac_huff_tbl_ptrs[tbl]);
+      if (htblptr^ = NIL) then
+        htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo));
+      jpeg_gen_optimal_table(cinfo, htblptr^, entropy^.count_ptrs[tbl]^);
+      did[tbl] := TRUE;
+    end;
+  end;
+end;
+
+
+{ Module initialization routine for progressive Huffman entropy encoding. }
+
+{GLOBAL}
+procedure jinit_phuff_encoder (cinfo : j_compress_ptr);
+var
+  entropy : phuff_entropy_ptr;
+  i : int;
+begin
+  entropy := phuff_entropy_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(phuff_entropy_encoder)) );
+  cinfo^.entropy := jpeg_entropy_encoder_ptr(entropy);
+  entropy^.pub.start_pass := start_pass_phuff;
+
+  { Mark tables unallocated }
+  for i := 0 to pred(NUM_HUFF_TBLS) do
+  begin
+    entropy^.derived_tbls[i] := NIL;
+    entropy^.count_ptrs[i] := NIL;
+  end;
+  entropy^.bit_buffer := NIL; { needed only in AC refinement scan }
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcprepct.pas b/src/lib/vampimg/JpegLib/imjcprepct.pas
new file mode 100644 (file)
index 0000000..9f21e51
--- /dev/null
@@ -0,0 +1,406 @@
+unit imjcprepct;
+
+{ Original : jcprepct.c ;  Copyright (C) 1994-1996, Thomas G. Lane. }
+
+{ This file contains the compression preprocessing controller.
+  This controller manages the color conversion, downsampling,
+  and edge expansion steps.
+
+  Most of the complexity here is associated with buffering input rows
+  as required by the downsampler.  See the comments at the head of
+  jcsample.c for the downsampler's needs. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjpeglib,
+  imjdeferr,
+  imjerror,
+  imjinclude,
+  imjutils;
+
+{GLOBAL}
+procedure jinit_c_prep_controller (cinfo : j_compress_ptr;
+                                   need_full_buffer : boolean);
+
+implementation
+
+
+{ At present, jcsample.c can request context rows only for smoothing.
+  In the future, we might also need context rows for CCIR601 sampling
+  or other more-complex downsampling procedures.  The code to support
+  context rows should be compiled only if needed. }
+
+{$ifdef INPUT_SMOOTHING_SUPPORTED}
+  {$define CONTEXT_ROWS_SUPPORTED}
+{$endif}
+
+
+{ For the simple (no-context-row) case, we just need to buffer one
+  row group's worth of pixels for the downsampling step.  At the bottom of
+  the image, we pad to a full row group by replicating the last pixel row.
+  The downsampler's last output row is then replicated if needed to pad
+  out to a full iMCU row.
+
+  When providing context rows, we must buffer three row groups' worth of
+  pixels.  Three row groups are physically allocated, but the row pointer
+  arrays are made five row groups high, with the extra pointers above and
+  below "wrapping around" to point to the last and first real row groups.
+  This allows the downsampler to access the proper context rows.
+  At the top and bottom of the image, we create dummy context rows by
+  copying the first or last real pixel row.  This copying could be avoided
+  by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
+  trouble on the compression side. }
+
+
+{ Private buffer controller object }
+
+type
+  my_prep_ptr = ^my_prep_controller;
+  my_prep_controller = record
+    pub : jpeg_c_prep_controller; { public fields }
+
+    { Downsampling input buffer.  This buffer holds color-converted data
+      until we have enough to do a downsample step.  }
+
+    color_buf : array[0..MAX_COMPONENTS-1] of JSAMPARRAY;
+
+    rows_to_go : JDIMENSION;  { counts rows remaining in source image }
+    next_buf_row : int;   { index of next row to store in color_buf }
+
+  {$ifdef CONTEXT_ROWS_SUPPORTED} { only needed for context case }
+    this_row_group : int;         { starting row index of group to process }
+    next_buf_stop : int;          { downsample when we reach this index }
+  {$endif}
+  end; {my_prep_controller;}
+
+
+{ Initialize for a processing pass. }
+
+{METHODDEF}
+procedure start_pass_prep (cinfo : j_compress_ptr;
+                           pass_mode : J_BUF_MODE );
+var
+  prep : my_prep_ptr;
+begin
+  prep := my_prep_ptr (cinfo^.prep);
+
+  if (pass_mode <> JBUF_PASS_THRU) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+
+  { Initialize total-height counter for detecting bottom of image }
+  prep^.rows_to_go := cinfo^.image_height;
+  { Mark the conversion buffer empty }
+  prep^.next_buf_row := 0;
+{$ifdef CONTEXT_ROWS_SUPPORTED}
+  { Preset additional state variables for context mode.
+    These aren't used in non-context mode, so we needn't test which mode. }
+  prep^.this_row_group := 0;
+  { Set next_buf_stop to stop after two row groups have been read in. }
+  prep^.next_buf_stop := 2 * cinfo^.max_v_samp_factor;
+{$endif}
+end;
+
+
+{ Expand an image vertically from height input_rows to height output_rows,
+  by duplicating the bottom row. }
+
+{LOCAL}
+procedure expand_bottom_edge (image_data : JSAMPARRAY;
+                              num_cols : JDIMENSION;
+                  input_rows : int;
+                              output_rows : int);
+var
+  {register} row : int;
+begin
+  for row := input_rows to pred(output_rows) do
+  begin
+    jcopy_sample_rows(image_data, input_rows-1, image_data, row,
+          1, num_cols);
+  end;
+end;
+
+
+{ Process some data in the simple no-context case.
+
+  Preprocessor output data is counted in "row groups".  A row group
+  is defined to be v_samp_factor sample rows of each component.
+  Downsampling will produce this much data from each max_v_samp_factor
+  input rows. }
+
+{METHODDEF}
+procedure pre_process_data (cinfo : j_compress_ptr;
+               input_buf : JSAMPARRAY;
+                           var in_row_ctr : JDIMENSION;
+               in_rows_avail : JDIMENSION;
+               output_buf : JSAMPIMAGE;
+                           var out_row_group_ctr : JDIMENSION;
+                           out_row_groups_avail : JDIMENSION);
+var
+  prep : my_prep_ptr;
+  numrows, ci : int;
+  inrows : JDIMENSION;
+  compptr : jpeg_component_info_ptr;
+var
+  local_input_buf : JSAMPARRAY;
+begin
+  prep := my_prep_ptr (cinfo^.prep);
+
+  while (in_row_ctr < in_rows_avail) and
+  (out_row_group_ctr < out_row_groups_avail) do
+  begin
+    { Do color conversion to fill the conversion buffer. }
+    inrows := in_rows_avail - in_row_ctr;
+    numrows := cinfo^.max_v_samp_factor - prep^.next_buf_row;
+    {numrows := int( MIN(JDIMENSION(numrows), inrows) );}
+    if inrows < JDIMENSION(numrows) then
+      numrows := int(inrows);
+    local_input_buf := JSAMPARRAY(@(input_buf^[in_row_ctr]));
+    cinfo^.cconvert^.color_convert (cinfo, local_input_buf,
+                                    JSAMPIMAGE(@prep^.color_buf),
+            JDIMENSION(prep^.next_buf_row),
+            numrows);
+    Inc(in_row_ctr, numrows);
+    Inc(prep^.next_buf_row, numrows);
+    Dec(prep^.rows_to_go, numrows);
+    { If at bottom of image, pad to fill the conversion buffer. }
+    if (prep^.rows_to_go = 0) and
+       (prep^.next_buf_row < cinfo^.max_v_samp_factor) then
+    begin
+      for ci := 0 to pred(cinfo^.num_components) do
+      begin
+  expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width,
+         prep^.next_buf_row, cinfo^.max_v_samp_factor);
+      end;
+      prep^.next_buf_row := cinfo^.max_v_samp_factor;
+    end;
+    { If we've filled the conversion buffer, empty it. }
+    if (prep^.next_buf_row = cinfo^.max_v_samp_factor) then
+    begin
+      cinfo^.downsample^.downsample (cinfo,
+                                     JSAMPIMAGE(@prep^.color_buf),
+                                     JDIMENSION (0),
+             output_buf,
+                                     out_row_group_ctr);
+      prep^.next_buf_row := 0;
+      Inc(out_row_group_ctr);;
+    end;
+    { If at bottom of image, pad the output to a full iMCU height.
+      Note we assume the caller is providing a one-iMCU-height output buffer! }
+    if (prep^.rows_to_go = 0) and
+       (out_row_group_ctr < out_row_groups_avail) then
+    begin
+      compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+      for ci := 0 to pred(cinfo^.num_components) do
+      begin
+  expand_bottom_edge(output_buf^[ci],
+       compptr^.width_in_blocks * DCTSIZE,
+                   int (out_row_group_ctr) * compptr^.v_samp_factor,
+       int (out_row_groups_avail) * compptr^.v_samp_factor);
+        Inc(compptr);
+      end;
+      out_row_group_ctr := out_row_groups_avail;
+      break;      { can exit outer loop without test }
+    end;
+  end;
+end;
+
+
+{$ifdef CONTEXT_ROWS_SUPPORTED}
+
+{ Process some data in the context case. }
+
+{METHODDEF}
+procedure pre_process_context (cinfo : j_compress_ptr;
+                  input_buf : JSAMPARRAY;
+                              var in_row_ctr : JDIMENSION;
+                  in_rows_avail : JDIMENSION;
+                  output_buf : JSAMPIMAGE;
+                              var out_row_group_ctr : JDIMENSION;
+                  out_row_groups_avail : JDIMENSION);
+var
+  prep : my_prep_ptr;
+  numrows, ci : int;
+  buf_height : int;
+  inrows : JDIMENSION;
+var
+  row : int;
+
+begin
+  prep := my_prep_ptr (cinfo^.prep);
+  buf_height := cinfo^.max_v_samp_factor * 3;
+
+  while (out_row_group_ctr < out_row_groups_avail) do
+  begin
+    if (in_row_ctr < in_rows_avail) then
+    begin
+      { Do color conversion to fill the conversion buffer. }
+      inrows := in_rows_avail - in_row_ctr;
+      numrows := prep^.next_buf_stop - prep^.next_buf_row;
+      {numrows := int ( MIN( JDIMENSION(numrows), inrows) );}
+      if inrows < JDIMENSION(numrows) then
+        numrows := int(inrows);
+      cinfo^.cconvert^.color_convert (cinfo,
+                                      JSAMPARRAY(@input_buf^[in_row_ctr]),
+                                      JSAMPIMAGE(@prep^.color_buf),
+              JDIMENSION (prep^.next_buf_row),
+              numrows);
+      { Pad at top of image, if first time through }
+      if (prep^.rows_to_go = cinfo^.image_height) then
+      begin
+  for ci := 0 to pred(cinfo^.num_components) do
+        begin
+    for row := 1 to cinfo^.max_v_samp_factor do
+          begin
+      jcopy_sample_rows(prep^.color_buf[ci], 0,
+            prep^.color_buf[ci], -row,
+            1, cinfo^.image_width);
+    end;
+  end;
+      end;
+      Inc(in_row_ctr, numrows);
+      Inc(prep^.next_buf_row, numrows);
+      Dec(prep^.rows_to_go, numrows);
+    end
+    else
+    begin
+      { Return for more data, unless we are at the bottom of the image. }
+      if (prep^.rows_to_go <> 0) then
+  break;
+      { When at bottom of image, pad to fill the conversion buffer. }
+      if (prep^.next_buf_row < prep^.next_buf_stop) then
+      begin
+  for ci := 0 to pred(cinfo^.num_components) do
+        begin
+    expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width,
+           prep^.next_buf_row, prep^.next_buf_stop);
+  end;
+  prep^.next_buf_row := prep^.next_buf_stop;
+      end;
+    end;
+    { If we've gotten enough data, downsample a row group. }
+    if (prep^.next_buf_row = prep^.next_buf_stop) then
+    begin
+      cinfo^.downsample^.downsample (cinfo,
+                                     JSAMPIMAGE(@prep^.color_buf),
+             JDIMENSION(prep^.this_row_group),
+             output_buf,
+                                     out_row_group_ctr);
+      Inc(out_row_group_ctr);
+      { Advance pointers with wraparound as necessary. }
+      Inc(prep^.this_row_group, cinfo^.max_v_samp_factor);
+      if (prep^.this_row_group >= buf_height) then
+  prep^.this_row_group := 0;
+      if (prep^.next_buf_row >= buf_height) then
+  prep^.next_buf_row := 0;
+      prep^.next_buf_stop := prep^.next_buf_row + cinfo^.max_v_samp_factor;
+    end;
+  end;
+end;
+
+
+{ Create the wrapped-around downsampling input buffer needed for context mode. }
+
+{LOCAL}
+procedure create_context_buffer (cinfo : j_compress_ptr);
+var
+  prep : my_prep_ptr;
+  rgroup_height : int;
+  ci, i : int;
+  compptr : jpeg_component_info_ptr;
+  true_buffer, fake_buffer : JSAMPARRAY;
+begin
+  prep := my_prep_ptr (cinfo^.prep);
+  rgroup_height := cinfo^.max_v_samp_factor;
+  { Grab enough space for fake row pointers for all the components;
+    we need five row groups' worth of pointers for each component. }
+
+  fake_buffer := JSAMPARRAY(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        (cinfo^.num_components * 5 * rgroup_height) *
+        SIZEOF(JSAMPROW)) );
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Allocate the actual buffer space (3 row groups) for this component.
+      We make the buffer wide enough to allow the downsampler to edge-expand
+      horizontally within the buffer, if it so chooses. }
+    true_buffer := cinfo^.mem^.alloc_sarray
+      (j_common_ptr(cinfo), JPOOL_IMAGE,
+       JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE *
+          cinfo^.max_h_samp_factor) div compptr^.h_samp_factor),
+       JDIMENSION (3 * rgroup_height));
+    { Copy true buffer row pointers into the middle of the fake row array }
+    MEMCOPY(JSAMPARRAY(@ fake_buffer^[rgroup_height]), true_buffer,
+      3 * rgroup_height * SIZEOF(JSAMPROW));
+    { Fill in the above and below wraparound pointers }
+    for i := 0 to pred(rgroup_height) do
+    begin
+      fake_buffer^[i] := true_buffer^[2 * rgroup_height + i];
+      fake_buffer^[4 * rgroup_height + i] := true_buffer^[i];
+    end;
+    prep^.color_buf[ci] := JSAMPARRAY(@ fake_buffer^[rgroup_height]);
+    Inc(JSAMPROW_PTR(fake_buffer), 5 * rgroup_height); { point to space for next component }
+    Inc(compptr);
+  end;
+end;
+
+{$endif} { CONTEXT_ROWS_SUPPORTED }
+
+
+{ Initialize preprocessing controller. }
+
+{GLOBAL}
+procedure jinit_c_prep_controller (cinfo : j_compress_ptr;
+                                   need_full_buffer : boolean);
+var
+  prep : my_prep_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+
+  if (need_full_buffer) then    { safety check }
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+
+  prep := my_prep_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_prep_controller)) );
+  cinfo^.prep := jpeg_c_prep_controller_ptr(prep);
+  prep^.pub.start_pass := start_pass_prep;
+
+  { Allocate the color conversion buffer.
+    We make the buffer wide enough to allow the downsampler to edge-expand
+    horizontally within the buffer, if it so chooses. }
+
+  if (cinfo^.downsample^.need_context_rows) then
+  begin
+    { Set up to provide context rows }
+{$ifdef CONTEXT_ROWS_SUPPORTED}
+    prep^.pub.pre_process_data := pre_process_context;
+    create_context_buffer(cinfo);
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+  end
+  else
+  begin
+    { No context, just make it tall enough for one row group }
+    prep^.pub.pre_process_data := pre_process_data;
+    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      prep^.color_buf[ci] := cinfo^.mem^.alloc_sarray
+  (j_common_ptr(cinfo), JPOOL_IMAGE,
+   JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE *
+      cinfo^.max_h_samp_factor) div compptr^.h_samp_factor),
+   JDIMENSION(cinfo^.max_v_samp_factor) );
+      Inc(compptr);
+    end;
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjcsample.pas b/src/lib/vampimg/JpegLib/imjcsample.pas
new file mode 100644 (file)
index 0000000..48ea3d8
--- /dev/null
@@ -0,0 +1,631 @@
+unit imjcsample;
+
+{ This file contains downsampling routines.
+
+  Downsampling input data is counted in "row groups".  A row group
+  is defined to be max_v_samp_factor pixel rows of each component,
+  from which the downsampler produces v_samp_factor sample rows.
+  A single row group is processed in each call to the downsampler module.
+
+  The downsampler is responsible for edge-expansion of its output data
+  to fill an integral number of DCT blocks horizontally.  The source buffer
+  may be modified if it is helpful for this purpose (the source buffer is
+  allocated wide enough to correspond to the desired output width).
+  The caller (the prep controller) is responsible for vertical padding.
+
+  The downsampler may request "context rows" by setting need_context_rows
+  during startup.  In this case, the input arrays will contain at least
+  one row group's worth of pixels above and below the passed-in data;
+  the caller will create dummy rows at image top and bottom by replicating
+  the first or last real pixel row.
+
+  An excellent reference for image resampling is
+    Digital Image Warping, George Wolberg, 1990.
+    Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+
+  The downsampling algorithm used here is a simple average of the source
+  pixels covered by the output pixel.  The hi-falutin sampling literature
+  refers to this as a "box filter".  In general the characteristics of a box
+  filter are not very good, but for the specific cases we normally use (1:1
+  and 2:1 ratios) the box is equivalent to a "triangle filter" which is not
+  nearly so bad.  If you intend to use other sampling ratios, you'd be well
+  advised to improve this code.
+
+  A simple input-smoothing capability is provided.  This is mainly intended
+  for cleaning up color-dithered GIF input files (if you find it inadequate,
+  we suggest using an external filtering program such as pnmconvol).  When
+  enabled, each input pixel P is replaced by a weighted sum of itself and its
+  eight neighbors.  P's weight is 1-8*SF and each neighbor's weight is SF,
+  where SF := (smoothing_factor / 1024).
+  Currently, smoothing is only supported for 2h2v sampling factors. }
+
+{ Original: jcsample.c ; Copyright (C) 1991-1996, Thomas G. Lane. }
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjutils,
+  imjdeferr,
+  imjerror,
+  imjpeglib;
+
+
+{ Module initialization routine for downsampling.
+  Note that we must select a routine for each component. }
+
+{GLOBAL}
+procedure jinit_downsampler (cinfo : j_compress_ptr);
+
+implementation
+
+{ Pointer to routine to downsample a single component }
+type
+  downsample1_ptr = procedure(cinfo : j_compress_ptr;
+                              compptr : jpeg_component_info_ptr;
+                  input_data : JSAMPARRAY;
+                              output_data : JSAMPARRAY);
+
+{ Private subobject }
+
+type
+  my_downsample_ptr = ^my_downsampler;
+  my_downsampler = record
+    pub : jpeg_downsampler; { public fields }
+
+    { Downsampling method pointers, one per component }
+    methods : array[0..MAX_COMPONENTS-1] of downsample1_ptr;
+  end;
+
+{ Initialize for a downsampling pass. }
+
+{METHODDEF}
+procedure start_pass_downsample (cinfo : j_compress_ptr);
+begin
+  { no work for now }
+end;
+
+
+{ Expand a component horizontally from width input_cols to width output_cols,
+  by duplicating the rightmost samples. }
+
+{LOCAL}
+procedure expand_right_edge (image_data : JSAMPARRAY;
+                             num_rows : int;
+                 input_cols : JDIMENSION;
+                             output_cols : JDIMENSION);
+var
+  {register} ptr : JSAMPLE_PTR;
+  {register} pixval : JSAMPLE;
+  {register} count : int;
+  row : int;
+  numcols : int;
+begin
+  numcols := int (output_cols - input_cols);
+
+  if (numcols > 0) then
+  begin
+    for row := 0 to pred(num_rows) do
+    begin
+      ptr := JSAMPLE_PTR(@(image_data^[row]^[input_cols-1]));
+      pixval := ptr^;   { don't need GETJSAMPLE() here }
+      for count := pred(numcols) downto 0 do
+      begin
+        Inc(ptr);
+  ptr^ := pixval;
+      end;
+    end;
+  end;
+end;
+
+
+{ Do downsampling for a whole row group (all components).
+
+  In this version we simply downsample each component independently. }
+
+{METHODDEF}
+procedure sep_downsample (cinfo : j_compress_ptr;
+              input_buf : JSAMPIMAGE;
+                          in_row_index : JDIMENSION;
+              output_buf : JSAMPIMAGE;
+                          out_row_group_index : JDIMENSION);
+var
+  downsample : my_downsample_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+  in_ptr, out_ptr : JSAMPARRAY;
+begin
+  downsample := my_downsample_ptr (cinfo^.downsample);
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    in_ptr := JSAMPARRAY(@ input_buf^[ci]^[in_row_index]);
+    out_ptr := JSAMPARRAY(@ output_buf^[ci]^
+                     [out_row_group_index * JDIMENSION(compptr^.v_samp_factor)]);
+    downsample^.methods[ci] (cinfo, compptr, in_ptr, out_ptr);
+    Inc(compptr);
+  end;
+end;
+
+
+{ Downsample pixel values of a single component.
+  One row group is processed per call.
+  This version handles arbitrary integral sampling ratios, without smoothing.
+  Note that this version is not actually used for customary sampling ratios. }
+
+{METHODDEF}
+procedure int_downsample (cinfo : j_compress_ptr;
+                          compptr : jpeg_component_info_ptr;
+              input_data : JSAMPARRAY;
+                          output_data : JSAMPARRAY);
+var
+  inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v : int;
+  outcol, outcol_h :  JDIMENSION; { outcol_h = outcol*h_expand }
+  output_cols : JDIMENSION;
+  inptr,
+  outptr : JSAMPLE_PTR;
+  outvalue : INT32;
+begin
+  output_cols := compptr^.width_in_blocks * DCTSIZE;
+
+  h_expand := cinfo^.max_h_samp_factor div compptr^.h_samp_factor;
+  v_expand := cinfo^.max_v_samp_factor div compptr^.v_samp_factor;
+  numpix := h_expand * v_expand;
+  numpix2 := numpix div 2;
+
+  { Expand input data enough to let all the output samples be generated
+    by the standard loop.  Special-casing padded output would be more
+    efficient. }
+
+  expand_right_edge(input_data, cinfo^.max_v_samp_factor,
+        cinfo^.image_width, output_cols * JDIMENSION(h_expand));
+
+  inrow := 0;
+  for outrow := 0 to pred(compptr^.v_samp_factor) do
+  begin
+    outptr := JSAMPLE_PTR(output_data^[outrow]);
+    outcol_h := 0;
+    for outcol := 0 to pred(output_cols) do
+    begin
+      outvalue := 0;
+      for v := 0 to pred(v_expand) do
+      begin
+  inptr := @(input_data^[inrow+v]^[outcol_h]);
+  for h := 0 to pred(h_expand) do
+        begin
+    Inc(outvalue, INT32 (GETJSAMPLE(inptr^)) );
+          Inc(inptr);
+  end;
+      end;
+      outptr^ := JSAMPLE ((outvalue + numpix2) div numpix);
+      Inc(outptr);
+      Inc(outcol_h, h_expand);
+    end;
+    Inc(inrow, v_expand);
+  end;
+end;
+
+
+{ Downsample pixel values of a single component.
+  This version handles the special case of a full-size component,
+  without smoothing. }
+
+{METHODDEF}
+procedure fullsize_downsample (cinfo : j_compress_ptr;
+                               compptr : jpeg_component_info_ptr;
+                   input_data : JSAMPARRAY;
+                               output_data : JSAMPARRAY);
+begin
+  { Copy the data }
+  jcopy_sample_rows(input_data, 0, output_data, 0,
+        cinfo^.max_v_samp_factor, cinfo^.image_width);
+  { Edge-expand }
+  expand_right_edge(output_data, cinfo^.max_v_samp_factor,
+        cinfo^.image_width, compptr^.width_in_blocks * DCTSIZE);
+end;
+
+
+{ Downsample pixel values of a single component.
+  This version handles the common case of 2:1 horizontal and 1:1 vertical,
+  without smoothing.
+
+  A note about the "bias" calculations: when rounding fractional values to
+  integer, we do not want to always round 0.5 up to the next integer.
+  If we did that, we'd introduce a noticeable bias towards larger values.
+  Instead, this code is arranged so that 0.5 will be rounded up or down at
+  alternate pixel locations (a simple ordered dither pattern). }
+
+{METHODDEF}
+procedure h2v1_downsample (cinfo : j_compress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               input_data : JSAMPARRAY;
+                           output_data : JSAMPARRAY);
+var
+  outrow : int;
+  outcol : JDIMENSION;
+  output_cols : JDIMENSION;
+  {register} inptr, outptr : JSAMPLE_PTR;
+  {register} bias : int;
+begin
+  output_cols := compptr^.width_in_blocks * DCTSIZE;
+
+  { Expand input data enough to let all the output samples be generated
+    by the standard loop.  Special-casing padded output would be more
+    efficient. }
+
+  expand_right_edge(input_data, cinfo^.max_v_samp_factor,
+        cinfo^.image_width, output_cols * 2);
+
+  for outrow := 0 to pred(compptr^.v_samp_factor) do
+  begin
+    outptr := JSAMPLE_PTR(output_data^[outrow]);
+    inptr := JSAMPLE_PTR(input_data^[outrow]);
+    bias := 0;         { bias := 0,1,0,1,... for successive samples }
+    for outcol := 0 to pred(output_cols) do
+    begin
+      outptr^ := JSAMPLE ((GETJSAMPLE(inptr^) +
+                           GETJSAMPLE(JSAMPROW(inptr)^[1]) + bias) shr 1);
+      Inc(outptr);
+      bias := bias xor 1;    { 0=>1, 1=>0 }
+      Inc(inptr, 2);
+    end;
+  end;
+end;
+
+
+{ Downsample pixel values of a single component.
+  This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+  without smoothing. }
+
+{METHODDEF}
+procedure h2v2_downsample (cinfo : j_compress_ptr;
+                           compptr : jpeg_component_info_ptr;
+                           input_data : JSAMPARRAY;
+                           output_data : JSAMPARRAY);
+var
+  inrow, outrow : int;
+  outcol : JDIMENSION;
+  output_cols : JDIMENSION;
+  {register} inptr0, inptr1, outptr : JSAMPLE_PTR;
+  {register} bias : int;
+begin
+  output_cols := compptr^.width_in_blocks * DCTSIZE;
+
+  { Expand input data enough to let all the output samples be generated
+    by the standard loop.  Special-casing padded output would be more
+    efficient. }
+
+  expand_right_edge(input_data, cinfo^.max_v_samp_factor,
+        cinfo^.image_width, output_cols * 2);
+
+  inrow := 0;
+  for outrow := 0 to pred(compptr^.v_samp_factor) do
+  begin
+    outptr := JSAMPLE_PTR(output_data^[outrow]);
+    inptr0 := JSAMPLE_PTR(input_data^[inrow]);
+    inptr1 := JSAMPLE_PTR(input_data^[inrow+1]);
+    bias := 1;      { bias := 1,2,1,2,... for successive samples }
+    for outcol := 0 to pred(output_cols) do
+    begin
+      outptr^ := JSAMPLE ((GETJSAMPLE(inptr0^) +
+                           GETJSAMPLE(JSAMPROW(inptr0)^[1]) +
+               GETJSAMPLE(inptr1^) +
+                           GETJSAMPLE(JSAMPROW(inptr1)^[1]) + bias) shr 2);
+      Inc(outptr);
+      bias := bias xor 3;       { 1=>2, 2=>1 }
+      Inc(inptr0, 2);
+      Inc(inptr1, 2);
+    end;
+    Inc(inrow, 2);
+  end;
+end;
+
+
+{$ifdef INPUT_SMOOTHING_SUPPORTED}
+
+{ Downsample pixel values of a single component.
+  This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+  with smoothing.  One row of context is required. }
+
+{METHODDEF}
+procedure h2v2_smooth_downsample (cinfo : j_compress_ptr;
+                                  compptr : jpeg_component_info_ptr;
+                                  input_data : JSAMPARRAY;
+                                  output_data : JSAMPARRAY);
+var
+  inrow, outrow : int;
+  colctr : JDIMENSION;
+  output_cols : JDIMENSION;
+  {register} inptr0, inptr1, above_ptr, below_ptr, outptr : JSAMPLE_PTR;
+  membersum, neighsum, memberscale, neighscale : INT32;
+var
+  prev_input_data : JSAMPARRAY;
+  prev_inptr0, prev_inptr1, prev_above_ptr, prev_below_ptr : JSAMPLE_PTR;
+begin
+  output_cols := compptr^.width_in_blocks * DCTSIZE;
+
+  { Expand input data enough to let all the output samples be generated
+    by the standard loop.  Special-casing padded output would be more
+    efficient. }
+
+  prev_input_data := input_data;
+  Dec(JSAMPROW_PTR(prev_input_data));
+  expand_right_edge(prev_input_data, cinfo^.max_v_samp_factor + 2,
+        cinfo^.image_width, output_cols * 2);
+
+  { We don't bother to form the individual "smoothed" input pixel values;
+    we can directly compute the output which is the average of the four
+    smoothed values.  Each of the four member pixels contributes a fraction
+    (1-8*SF) to its own smoothed image and a fraction SF to each of the three
+    other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
+    output.  The four corner-adjacent neighbor pixels contribute a fraction
+    SF to just one smoothed pixel, or SF/4 to the final output; while the
+    eight edge-adjacent neighbors contribute SF to each of two smoothed
+    pixels, or SF/2 overall.  In order to use integer arithmetic, these
+    factors are scaled by 2^16 := 65536.
+    Also recall that SF := smoothing_factor / 1024. }
+
+  memberscale := 16384 - cinfo^.smoothing_factor * 80; { scaled (1-5*SF)/4 }
+  neighscale := cinfo^.smoothing_factor * 16; { scaled SF/4 }
+
+  inrow := 0;
+  for outrow := 0 to pred(compptr^.v_samp_factor) do
+  begin
+    outptr := JSAMPLE_PTR(output_data^[outrow]);
+    inptr0 := JSAMPLE_PTR(input_data^[inrow]);
+    inptr1 := JSAMPLE_PTR(input_data^[inrow+1]);
+    above_ptr := JSAMPLE_PTR(input_data^[inrow-1]);
+    below_ptr := JSAMPLE_PTR(input_data^[inrow+2]);
+
+    { Special case for first column: pretend column -1 is same as column 0 }
+    membersum := GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) +
+    GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]);
+    neighsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(JSAMPROW(above_ptr)^[1]) +
+         GETJSAMPLE(below_ptr^) + GETJSAMPLE(JSAMPROW(below_ptr)^[1]) +
+         GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[2]) +
+         GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[2]);
+    Inc(neighsum, neighsum);
+    Inc(neighsum, GETJSAMPLE(above_ptr^) +
+                  GETJSAMPLE(JSAMPROW(above_ptr)^[2]) +
+      GETJSAMPLE(below_ptr^) +
+                  GETJSAMPLE(JSAMPROW(below_ptr)^[2]) );
+    membersum := membersum * memberscale + neighsum * neighscale;
+    outptr^ := JSAMPLE ((membersum + 32768) shr 16);
+    Inc(outptr);
+    prev_inptr0 := inptr0;
+    prev_inptr1 := inptr1;
+    Inc(prev_inptr0);
+    Inc(prev_inptr1);
+    Inc(inptr0, 2);
+    Inc(inptr1, 2);
+    prev_above_ptr := above_ptr;
+    prev_below_ptr := below_ptr;
+    Inc(above_ptr, 2);
+    Inc(below_ptr, 2);
+    Inc(prev_above_ptr, 1);
+    Inc(prev_below_ptr, 1);
+
+    for colctr := pred(output_cols - 2) downto 0 do
+    begin
+      { sum of pixels directly mapped to this output element }
+      membersum := GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) +
+                   GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]);
+      { sum of edge-neighbor pixels }
+      neighsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(JSAMPROW(above_ptr)^[1]) +
+                  GETJSAMPLE(below_ptr^) + GETJSAMPLE(JSAMPROW(below_ptr)^[1]) +
+                  GETJSAMPLE(prev_inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[2]) +
+                  GETJSAMPLE(prev_inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[2]);
+      { The edge-neighbors count twice as much as corner-neighbors }
+      Inc(neighsum, neighsum);
+      { Add in the corner-neighbors }
+      Inc(neighsum, GETJSAMPLE(prev_above_ptr^) +
+                    GETJSAMPLE(JSAMPROW(above_ptr)^[2]) +
+        GETJSAMPLE(prev_below_ptr^) +
+                    GETJSAMPLE(JSAMPROW(below_ptr)^[2]) );
+      { form final output scaled up by 2^16 }
+      membersum := membersum * memberscale + neighsum * neighscale;
+      { round, descale and output it }
+      outptr^ := JSAMPLE ((membersum + 32768) shr 16);
+      Inc(outptr);
+      Inc(inptr0, 2);
+      Inc(inptr1, 2);
+      Inc(prev_inptr0, 2);
+      Inc(prev_inptr1, 2);
+      Inc(above_ptr, 2);
+      Inc(below_ptr, 2);
+      Inc(prev_above_ptr, 2);
+      Inc(prev_below_ptr, 2);
+    end;
+
+    { Special case for last column }
+    membersum := GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) +
+     GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]);
+    neighsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(JSAMPROW(above_ptr)^[1]) +
+          GETJSAMPLE(below_ptr^) + GETJSAMPLE(JSAMPROW(below_ptr)^[1]) +
+          GETJSAMPLE(prev_inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) +
+          GETJSAMPLE(prev_inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]);
+    Inc(neighsum, neighsum);
+    Inc(neighsum, GETJSAMPLE(prev_above_ptr^) +
+                  GETJSAMPLE(JSAMPROW(above_ptr)^[1]) +
+      GETJSAMPLE(prev_below_ptr^) +
+                  GETJSAMPLE(JSAMPROW(below_ptr)^[1]) );
+    membersum := membersum * memberscale + neighsum * neighscale;
+    outptr^ := JSAMPLE ((membersum + 32768) shr 16);
+
+    Inc(inrow, 2);
+  end;
+end;
+
+
+{ Downsample pixel values of a single component.
+  This version handles the special case of a full-size component,
+  with smoothing.  One row of context is required. }
+
+{METHODDEF}
+procedure fullsize_smooth_downsample (cinfo : j_compress_ptr;
+                                      compptr : jpeg_component_info_ptr;
+                    input_data : JSAMPARRAY;
+                                      output_data : JSAMPARRAY);
+var
+  outrow : int;
+  colctr : JDIMENSION;
+  output_cols : JDIMENSION;
+  {register} inptr, above_ptr, below_ptr, outptr : JSAMPLE_PTR;
+  membersum, neighsum, memberscale, neighscale : INT32;
+  colsum, lastcolsum, nextcolsum : int;
+var
+  prev_input_data : JSAMPARRAY;
+begin
+  output_cols := compptr^.width_in_blocks * DCTSIZE;
+
+  { Expand input data enough to let all the output samples be generated
+    by the standard loop.  Special-casing padded output would be more
+    efficient. }
+
+  prev_input_data := input_data;
+  Dec(JSAMPROW_PTR(prev_input_data));
+  expand_right_edge(prev_input_data, cinfo^.max_v_samp_factor + 2,
+        cinfo^.image_width, output_cols);
+
+  { Each of the eight neighbor pixels contributes a fraction SF to the
+    smoothed pixel, while the main pixel contributes (1-8*SF).  In order
+    to use integer arithmetic, these factors are multiplied by 2^16 := 65536.
+    Also recall that SF := smoothing_factor / 1024. }
+
+  memberscale := long(65536) - cinfo^.smoothing_factor * long(512); { scaled 1-8*SF }
+  neighscale := cinfo^.smoothing_factor * 64; { scaled SF }
+
+  for outrow := 0 to pred(compptr^.v_samp_factor) do
+  begin
+    outptr := JSAMPLE_PTR(output_data^[outrow]);
+    inptr := JSAMPLE_PTR(input_data^[outrow]);
+    above_ptr := JSAMPLE_PTR(input_data^[outrow-1]);
+    below_ptr := JSAMPLE_PTR(input_data^[outrow+1]);
+
+    { Special case for first column }
+    colsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(below_ptr^) +
+       GETJSAMPLE(inptr^);
+    Inc(above_ptr);
+    Inc(below_ptr);
+    membersum := GETJSAMPLE(inptr^);
+    Inc(inptr);
+    nextcolsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(below_ptr^) +
+      GETJSAMPLE(inptr^);
+    neighsum := colsum + (colsum - membersum) + nextcolsum;
+    membersum := membersum * memberscale + neighsum * neighscale;
+    outptr^ := JSAMPLE ((membersum + 32768) shr 16);
+    Inc(outptr);
+    lastcolsum := colsum; colsum := nextcolsum;
+
+    for colctr := pred(output_cols - 2) downto 0 do
+    begin
+      membersum := GETJSAMPLE(inptr^);
+      Inc(inptr);
+      Inc(above_ptr);
+      Inc(below_ptr);
+      nextcolsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(below_ptr^) +
+        GETJSAMPLE(inptr^);
+      neighsum := lastcolsum + (colsum - membersum) + nextcolsum;
+      membersum := membersum * memberscale + neighsum * neighscale;
+      outptr^ := JSAMPLE ((membersum + 32768) shr 16);
+      Inc(outptr);
+      lastcolsum := colsum; colsum := nextcolsum;
+    end;
+
+    { Special case for last column }
+    membersum := GETJSAMPLE(inptr^);
+    neighsum := lastcolsum + (colsum - membersum) + colsum;
+    membersum := membersum * memberscale + neighsum * neighscale;
+    outptr^ := JSAMPLE ((membersum + 32768) shr 16);
+  end;
+end;
+
+{$endif} { INPUT_SMOOTHING_SUPPORTED }
+
+
+{ Module initialization routine for downsampling.
+  Note that we must select a routine for each component. }
+
+{GLOBAL}
+procedure jinit_downsampler (cinfo : j_compress_ptr);
+var
+  downsample : my_downsample_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+  smoothok : boolean;
+begin
+  smoothok := TRUE;
+
+  downsample := my_downsample_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_downsampler)) );
+  cinfo^.downsample := jpeg_downsampler_ptr (downsample);
+  downsample^.pub.start_pass := start_pass_downsample;
+  downsample^.pub.downsample := sep_downsample;
+  downsample^.pub.need_context_rows := FALSE;
+
+  if (cinfo^.CCIR601_sampling) then
+    ERREXIT(j_common_ptr(cinfo), JERR_CCIR601_NOTIMPL);
+
+  { Verify we can handle the sampling factors, and set up method pointers }
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    if (compptr^.h_samp_factor = cinfo^.max_h_samp_factor) and
+       (compptr^.v_samp_factor = cinfo^.max_v_samp_factor) then
+    begin
+{$ifdef INPUT_SMOOTHING_SUPPORTED}
+      if (cinfo^.smoothing_factor <> 0) then
+      begin
+  downsample^.methods[ci] := fullsize_smooth_downsample;
+  downsample^.pub.need_context_rows := TRUE;
+      end
+      else
+{$endif}
+  downsample^.methods[ci] := fullsize_downsample;
+    end
+    else
+      if (compptr^.h_samp_factor * 2 = cinfo^.max_h_samp_factor) and
+         (compptr^.v_samp_factor = cinfo^.max_v_samp_factor) then
+      begin
+        smoothok := FALSE;
+        downsample^.methods[ci] := h2v1_downsample;
+      end
+      else
+        if (compptr^.h_samp_factor * 2 = cinfo^.max_h_samp_factor) and
+     (compptr^.v_samp_factor * 2 = cinfo^.max_v_samp_factor) then
+        begin
+  {$ifdef INPUT_SMOOTHING_SUPPORTED}
+        if (cinfo^.smoothing_factor <> 0) then
+        begin
+    downsample^.methods[ci] := h2v2_smooth_downsample;
+    downsample^.pub.need_context_rows := TRUE;
+        end
+        else
+  {$endif}
+          downsample^.methods[ci] := h2v2_downsample;
+        end
+        else
+          if ((cinfo^.max_h_samp_factor mod compptr^.h_samp_factor) = 0) and
+       ((cinfo^.max_v_samp_factor mod compptr^.v_samp_factor) = 0) then
+          begin
+            smoothok := FALSE;
+            downsample^.methods[ci] := int_downsample;
+          end
+          else
+            ERREXIT(j_common_ptr(cinfo), JERR_FRACT_SAMPLE_NOTIMPL);
+    Inc(compptr);
+  end;
+
+{$ifdef INPUT_SMOOTHING_SUPPORTED}
+  if (cinfo^.smoothing_factor <> 0) and (not smoothok) then
+    TRACEMS(j_common_ptr(cinfo), 0, JTRC_SMOOTH_NOTIMPL);
+{$endif}
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdapimin.pas b/src/lib/vampimg/JpegLib/imjdapimin.pas
new file mode 100644 (file)
index 0000000..726d798
--- /dev/null
@@ -0,0 +1,505 @@
+unit imjdapimin;
+
+{$N+}  { Nomssi: cinfo^.output_gamma }
+
+{ This file contains application interface code for the decompression half
+  of the JPEG library.  These are the "minimum" API routines that may be
+  needed in either the normal full-decompression case or the
+  transcoding-only case.
+
+  Most of the routines intended to be called directly by an application
+  are in this file or in jdapistd.c.  But also see jcomapi.c for routines
+  shared by compression and decompression, and jdtrans.c for the transcoding
+  case. }
+
+{ Original : jdapimin.c ;  Copyright (C) 1994-1998, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib,
+  imjmemmgr, imjdmarker, imjdinput, imjcomapi;
+
+{ Nomssi }
+procedure jpeg_create_decompress(cinfo : j_decompress_ptr);
+
+{ Initialization of a JPEG decompression object.
+  The error manager must already be set up (in case memory manager fails). }
+
+{GLOBAL}
+procedure jpeg_CreateDecompress (cinfo : j_decompress_ptr;
+                                 version : int;
+                                 structsize : size_t);
+
+{ Destruction of a JPEG decompression object }
+
+{GLOBAL}
+procedure jpeg_destroy_decompress (cinfo : j_decompress_ptr);
+
+
+{ Decompression startup: read start of JPEG datastream to see what's there.
+  Need only initialize JPEG object and supply a data source before calling.
+
+  This routine will read as far as the first SOS marker (ie, actual start of
+  compressed data), and will save all tables and parameters in the JPEG
+  object.  It will also initialize the decompression parameters to default
+  values, and finally return JPEG_HEADER_OK.  On return, the application may
+  adjust the decompression parameters and then call jpeg_start_decompress.
+  (Or, if the application only wanted to determine the image parameters,
+  the data need not be decompressed.  In that case, call jpeg_abort or
+  jpeg_destroy to release any temporary space.)
+  If an abbreviated (tables only) datastream is presented, the routine will
+  return JPEG_HEADER_TABLES_ONLY upon reaching EOI.  The application may then
+  re-use the JPEG object to read the abbreviated image datastream(s).
+  It is unnecessary (but OK) to call jpeg_abort in this case.
+  The JPEG_SUSPENDED return code only occurs if the data source module
+  requests suspension of the decompressor.  In this case the application
+  should load more source data and then re-call jpeg_read_header to resume
+  processing.
+  If a non-suspending data source is used and require_image is TRUE, then the
+  return code need not be inspected since only JPEG_HEADER_OK is possible.
+
+  This routine is now just a front end to jpeg_consume_input, with some
+  extra error checking. }
+
+{GLOBAL}
+function jpeg_read_header (cinfo : j_decompress_ptr;
+                           require_image : boolean) : int;
+
+{ Consume data in advance of what the decompressor requires.
+  This can be called at any time once the decompressor object has
+  been created and a data source has been set up.
+
+  This routine is essentially a state machine that handles a couple
+  of critical state-transition actions, namely initial setup and
+  transition from header scanning to ready-for-start_decompress.
+  All the actual input is done via the input controller's consume_input
+  method. }
+
+{GLOBAL}
+function jpeg_consume_input (cinfo : j_decompress_ptr) : int;
+
+{ Have we finished reading the input file? }
+
+{GLOBAL}
+function jpeg_input_complete (cinfo : j_decompress_ptr) : boolean;
+
+{ Is there more than one scan? }
+
+{GLOBAL}
+function jpeg_has_multiple_scans (cinfo : j_decompress_ptr) : boolean;
+
+
+{ Finish JPEG decompression.
+
+  This will normally just verify the file trailer and release temp storage.
+
+  Returns FALSE if suspended.  The return value need be inspected only if
+  a suspending data source is used. }
+
+{GLOBAL}
+function jpeg_finish_decompress (cinfo : j_decompress_ptr) : boolean;
+
+implementation
+
+procedure jpeg_create_decompress(cinfo : j_decompress_ptr);
+begin
+  jpeg_CreateDecompress(cinfo, JPEG_LIB_VERSION,
+    size_t(sizeof(jpeg_decompress_struct)));
+end;
+
+{ Initialization of a JPEG decompression object.
+  The error manager must already be set up (in case memory manager fails). }
+
+{GLOBAL}
+procedure jpeg_CreateDecompress (cinfo : j_decompress_ptr;
+                                 version : int;
+                                 structsize : size_t);
+var
+  i : int;
+var
+  err : jpeg_error_mgr_ptr;
+  client_data : voidp;
+begin
+  { Guard against version mismatches between library and caller. }
+  cinfo^.mem := NIL;    { so jpeg_destroy knows mem mgr not called }
+  if (version <> JPEG_LIB_VERSION) then
+    ERREXIT2(j_common_ptr(cinfo), JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+  if (structsize <> SIZEOF(jpeg_decompress_struct)) then
+    ERREXIT2(j_common_ptr(cinfo), JERR_BAD_STRUCT_SIZE,
+       int(SIZEOF(jpeg_decompress_struct)), int(structsize));
+
+  { For debugging purposes, we zero the whole master structure.
+    But the application has already set the err pointer, and may have set
+    client_data, so we have to save and restore those fields.
+    Note: if application hasn't set client_data, tools like Purify may
+    complain here. }
+  begin
+    err := cinfo^.err;
+    client_data := cinfo^.client_data; { ignore Purify complaint here }
+    MEMZERO(j_common_ptr(cinfo), SIZEOF(jpeg_decompress_struct));
+    cinfo^.err := err;
+    cinfo^.client_data := client_data;
+  end;
+  cinfo^.is_decompressor := TRUE;
+
+  { Initialize a memory manager instance for this object }
+  jinit_memory_mgr(j_common_ptr(cinfo));
+
+  { Zero out pointers to permanent structures. }
+  cinfo^.progress := NIL;
+  cinfo^.src := NIL;
+
+  for i := 0 to pred(NUM_QUANT_TBLS) do
+    cinfo^.quant_tbl_ptrs[i] := NIL;
+
+  for i := 0 to pred(NUM_HUFF_TBLS) do
+  begin
+    cinfo^.dc_huff_tbl_ptrs[i] := NIL;
+    cinfo^.ac_huff_tbl_ptrs[i] := NIL;
+  end;
+
+  { Initialize marker processor so application can override methods
+    for COM, APPn markers before calling jpeg_read_header.  }
+  cinfo^.marker_list := NIL;
+  jinit_marker_reader(cinfo);
+
+  { And initialize the overall input controller. }
+  jinit_input_controller(cinfo);
+
+  { OK, I'm ready }
+  cinfo^.global_state := DSTATE_START;
+end;
+
+
+{ Destruction of a JPEG decompression object }
+
+{GLOBAL}
+procedure jpeg_destroy_decompress (cinfo : j_decompress_ptr);
+begin
+  jpeg_destroy(j_common_ptr(cinfo)); { use common routine }
+end;
+
+
+{ Abort processing of a JPEG decompression operation,
+  but don't destroy the object itself. }
+
+{GLOBAL}
+procedure jpeg_abort_decompress (cinfo : j_decompress_ptr);
+begin
+  jpeg_abort(j_common_ptr(cinfo)); { use common routine }
+end;
+
+
+{ Set default decompression parameters. }
+
+{LOCAL}
+procedure default_decompress_parms (cinfo : j_decompress_ptr);
+var
+  cid0 : int;
+  cid1 : int;
+  cid2 : int;
+begin
+  { Guess the input colorspace, and set output colorspace accordingly. }
+  { (Wish JPEG committee had provided a real way to specify this...) }
+  { Note application may override our guesses. }
+  case (cinfo^.num_components) of
+  1: begin
+       cinfo^.jpeg_color_space := JCS_GRAYSCALE;
+       cinfo^.out_color_space := JCS_GRAYSCALE;
+     end;
+
+  3: begin
+       if (cinfo^.saw_JFIF_marker) then
+       begin
+         cinfo^.jpeg_color_space := JCS_YCbCr; { JFIF implies YCbCr }
+       end
+       else
+         if (cinfo^.saw_Adobe_marker) then
+         begin
+           case (cinfo^.Adobe_transform) of
+           0: cinfo^.jpeg_color_space := JCS_RGB;
+           1: cinfo^.jpeg_color_space := JCS_YCbCr;
+           else
+             begin
+         WARNMS1(j_common_ptr(cinfo), JWRN_ADOBE_XFORM, cinfo^.Adobe_transform);
+               cinfo^.jpeg_color_space := JCS_YCbCr; { assume it's YCbCr }
+             end;
+           end;
+         end
+         else
+         begin
+           { Saw no special markers, try to guess from the component IDs }
+           cid0 := cinfo^.comp_info^[0].component_id;
+           cid1 := cinfo^.comp_info^[1].component_id;
+           cid2 := cinfo^.comp_info^[2].component_id;
+
+           if (cid0 = 1) and (cid1 = 2) and (cid2 = 3) then
+       cinfo^.jpeg_color_space := JCS_YCbCr { assume JFIF w/out marker }
+           else
+             if (cid0 = 82) and (cid1 = 71) and (cid2 = 66) then
+               cinfo^.jpeg_color_space := JCS_RGB { ASCII 'R', 'G', 'B' }
+             else
+             begin
+               {$IFDEF DEBUG}
+         TRACEMS3(j_common_ptr(cinfo), 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
+               {$ENDIF}
+               cinfo^.jpeg_color_space := JCS_YCbCr; { assume it's YCbCr }
+             end;
+         end;
+       { Always guess RGB is proper output colorspace. }
+       cinfo^.out_color_space := JCS_RGB;
+     end;
+
+  4: begin
+       if (cinfo^.saw_Adobe_marker) then
+       begin
+         case (cinfo^.Adobe_transform) of
+         0: cinfo^.jpeg_color_space := JCS_CMYK;
+         2: cinfo^.jpeg_color_space := JCS_YCCK;
+         else
+           begin
+             WARNMS1(j_common_ptr(cinfo), JWRN_ADOBE_XFORM, cinfo^.Adobe_transform);
+             cinfo^.jpeg_color_space := JCS_YCCK; { assume it's YCCK }
+           end;
+         end;
+       end
+       else
+       begin
+         { No special markers, assume straight CMYK. }
+         cinfo^.jpeg_color_space := JCS_CMYK;
+       end;
+       cinfo^.out_color_space := JCS_CMYK;
+     end;
+
+  else
+    begin
+      cinfo^.jpeg_color_space := JCS_UNKNOWN;
+      cinfo^.out_color_space := JCS_UNKNOWN;
+    end;
+  end;
+
+  { Set defaults for other decompression parameters. }
+  cinfo^.scale_num := 1;    { 1:1 scaling }
+  cinfo^.scale_denom := 1;
+  cinfo^.output_gamma := 1.0;
+  cinfo^.buffered_image := FALSE;
+  cinfo^.raw_data_out := FALSE;
+  cinfo^.dct_method := JDCT_DEFAULT;
+  cinfo^.do_fancy_upsampling := TRUE;
+  cinfo^.do_block_smoothing := TRUE;
+  cinfo^.quantize_colors := FALSE;
+  { We set these in case application only sets quantize_colors. }
+  cinfo^.dither_mode := JDITHER_FS;
+{$ifdef QUANT_2PASS_SUPPORTED}
+  cinfo^.two_pass_quantize := TRUE;
+{$else}
+  cinfo^.two_pass_quantize := FALSE;
+{$endif}
+  cinfo^.desired_number_of_colors := 256;
+  cinfo^.colormap := NIL;
+  { Initialize for no mode change in buffered-image mode. }
+  cinfo^.enable_1pass_quant := FALSE;
+  cinfo^.enable_external_quant := FALSE;
+  cinfo^.enable_2pass_quant := FALSE;
+end;
+
+
+{ Decompression startup: read start of JPEG datastream to see what's there.
+  Need only initialize JPEG object and supply a data source before calling.
+
+  This routine will read as far as the first SOS marker (ie, actual start of
+  compressed data), and will save all tables and parameters in the JPEG
+  object.  It will also initialize the decompression parameters to default
+  values, and finally return JPEG_HEADER_OK.  On return, the application may
+  adjust the decompression parameters and then call jpeg_start_decompress.
+  (Or, if the application only wanted to determine the image parameters,
+  the data need not be decompressed.  In that case, call jpeg_abort or
+  jpeg_destroy to release any temporary space.)
+  If an abbreviated (tables only) datastream is presented, the routine will
+  return JPEG_HEADER_TABLES_ONLY upon reaching EOI.  The application may then
+  re-use the JPEG object to read the abbreviated image datastream(s).
+  It is unnecessary (but OK) to call jpeg_abort in this case.
+  The JPEG_SUSPENDED return code only occurs if the data source module
+  requests suspension of the decompressor.  In this case the application
+  should load more source data and then re-call jpeg_read_header to resume
+  processing.
+  If a non-suspending data source is used and require_image is TRUE, then the
+  return code need not be inspected since only JPEG_HEADER_OK is possible.
+
+  This routine is now just a front end to jpeg_consume_input, with some
+  extra error checking. }
+
+{GLOBAL}
+function jpeg_read_header (cinfo : j_decompress_ptr;
+                           require_image : boolean) : int;
+var
+  retcode : int;
+begin
+  if (cinfo^.global_state <> DSTATE_START) and
+     (cinfo^.global_state <> DSTATE_INHEADER) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  retcode := jpeg_consume_input(cinfo);
+
+  case (retcode) of
+  JPEG_REACHED_SOS:
+    retcode := JPEG_HEADER_OK;
+  JPEG_REACHED_EOI:
+    begin
+      if (require_image) then   { Complain if application wanted an image }
+        ERREXIT(j_common_ptr(cinfo), JERR_NO_IMAGE);
+      { Reset to start state; it would be safer to require the application to
+        call jpeg_abort, but we can't change it now for compatibility reasons.
+        A side effect is to free any temporary memory (there shouldn't be any). }
+
+      jpeg_abort(j_common_ptr(cinfo)); { sets state := DSTATE_START }
+      retcode := JPEG_HEADER_TABLES_ONLY;
+    end;
+  JPEG_SUSPENDED: ;    { no work }
+  end;
+
+  jpeg_read_header := retcode;
+end;
+
+
+{ Consume data in advance of what the decompressor requires.
+  This can be called at any time once the decompressor object has
+  been created and a data source has been set up.
+
+  This routine is essentially a state machine that handles a couple
+  of critical state-transition actions, namely initial setup and
+  transition from header scanning to ready-for-start_decompress.
+  All the actual input is done via the input controller's consume_input
+  method. }
+
+{GLOBAL}
+function jpeg_consume_input (cinfo : j_decompress_ptr) : int;
+var
+  retcode : int;
+begin
+  retcode := JPEG_SUSPENDED;
+
+  { NB: every possible DSTATE value should be listed in this switch }
+
+  if (cinfo^.global_state) = DSTATE_START then
+  begin {work around the FALLTHROUGH}
+    { Start-of-datastream actions: reset appropriate modules }
+    cinfo^.inputctl^.reset_input_controller (cinfo);
+    { Initialize application's data source module }
+    cinfo^.src^.init_source (cinfo);
+    cinfo^.global_state := DSTATE_INHEADER;
+  end;
+
+  case (cinfo^.global_state) of
+  DSTATE_START,
+  DSTATE_INHEADER:
+    begin
+      retcode := cinfo^.inputctl^.consume_input (cinfo);
+      if (retcode = JPEG_REACHED_SOS) then
+      begin { Found SOS, prepare to decompress }
+        { Set up default parameters based on header data }
+        default_decompress_parms(cinfo);
+        { Set global state: ready for start_decompress }
+        cinfo^.global_state := DSTATE_READY;
+      end;
+    end;
+  DSTATE_READY:
+    { Can't advance past first SOS until start_decompress is called }
+    retcode := JPEG_REACHED_SOS;
+
+  DSTATE_PRELOAD,
+  DSTATE_PRESCAN,
+  DSTATE_SCANNING,
+  DSTATE_RAW_OK,
+  DSTATE_BUFIMAGE,
+  DSTATE_BUFPOST,
+  DSTATE_STOPPING:
+    retcode := cinfo^.inputctl^.consume_input (cinfo);
+  else
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  end;
+  jpeg_consume_input := retcode;
+end;
+
+
+{ Have we finished reading the input file? }
+
+{GLOBAL}
+function jpeg_input_complete (cinfo : j_decompress_ptr) : boolean;
+begin
+  { Check for valid jpeg object }
+  if (cinfo^.global_state < DSTATE_START) or
+     (cinfo^.global_state > DSTATE_STOPPING) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  jpeg_input_complete := cinfo^.inputctl^.eoi_reached;
+end;
+
+
+{ Is there more than one scan? }
+
+{GLOBAL}
+function jpeg_has_multiple_scans (cinfo : j_decompress_ptr) : boolean;
+begin
+  { Only valid after jpeg_read_header completes }
+  if (cinfo^.global_state < DSTATE_READY) or
+     (cinfo^.global_state > DSTATE_STOPPING) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  jpeg_has_multiple_scans := cinfo^.inputctl^.has_multiple_scans;
+end;
+
+
+{ Finish JPEG decompression.
+
+  This will normally just verify the file trailer and release temp storage.
+
+  Returns FALSE if suspended.  The return value need be inspected only if
+  a suspending data source is used. }
+
+{GLOBAL}
+function jpeg_finish_decompress (cinfo : j_decompress_ptr) : boolean;
+begin
+  if ((cinfo^.global_state = DSTATE_SCANNING) or
+      (cinfo^.global_state = DSTATE_RAW_OK) and (not cinfo^.buffered_image)) then
+  begin
+    { Terminate final pass of non-buffered mode }
+    if (cinfo^.output_scanline < cinfo^.output_height) then
+      ERREXIT(j_common_ptr(cinfo), JERR_TOO_LITTLE_DATA);
+    cinfo^.master^.finish_output_pass (cinfo);
+    cinfo^.global_state := DSTATE_STOPPING;
+  end
+  else
+    if (cinfo^.global_state = DSTATE_BUFIMAGE) then
+    begin
+      { Finishing after a buffered-image operation }
+      cinfo^.global_state := DSTATE_STOPPING;
+    end
+    else
+      if (cinfo^.global_state <> DSTATE_STOPPING) then
+      begin
+        { STOPPING := repeat call after a suspension, anything else is error }
+        ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+      end;
+  { Read until EOI }
+  while (not cinfo^.inputctl^.eoi_reached) do
+  begin
+    if (cinfo^.inputctl^.consume_input (cinfo) = JPEG_SUSPENDED) then
+    begin
+      jpeg_finish_decompress := FALSE;  { Suspend, come back later }
+      exit;
+    end;
+  end;
+  { Do final cleanup }
+  cinfo^.src^.term_source (cinfo);
+  { We can use jpeg_abort to release memory and reset global_state }
+  jpeg_abort(j_common_ptr(cinfo));
+  jpeg_finish_decompress := TRUE;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdapistd.pas b/src/lib/vampimg/JpegLib/imjdapistd.pas
new file mode 100644 (file)
index 0000000..04afd11
--- /dev/null
@@ -0,0 +1,376 @@
+unit imjdapistd;
+
+{ Original : jdapistd.c ;  Copyright (C) 1994-1996, Thomas G. Lane. }
+
+{  This file is part of the Independent JPEG Group's software.
+  For conditions of distribution and use, see the accompanying README file.
+
+  This file contains application interface code for the decompression half
+  of the JPEG library.  These are the "standard" API routines that are
+  used in the normal full-decompression case.  They are not used by a
+  transcoding-only application.  Note that if an application links in
+  jpeg_start_decompress, it will end up linking in the entire decompressor.
+  We thus must separate this file from jdapimin.c to avoid linking the
+  whole decompression library into a transcoder. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib,
+  imjdmaster;
+
+{ Read some scanlines of data from the JPEG decompressor.
+
+  The return value will be the number of lines actually read.
+  This may be less than the number requested in several cases,
+  including bottom of image, data source suspension, and operating
+  modes that emit multiple scanlines at a time.
+
+  Note: we warn about excess calls to jpeg_read_scanlines() since
+  this likely signals an application programmer error.  However,
+  an oversize buffer (max_lines > scanlines remaining) is not an error. }
+
+{GLOBAL}
+function jpeg_read_scanlines (cinfo : j_decompress_ptr;
+                              scanlines : JSAMPARRAY;
+                  max_lines : JDIMENSION) : JDIMENSION;
+
+
+{ Alternate entry point to read raw data.
+  Processes exactly one iMCU row per call, unless suspended. }
+
+{GLOBAL}
+function jpeg_read_raw_data (cinfo : j_decompress_ptr;
+                             data : JSAMPIMAGE;
+                 max_lines : JDIMENSION) : JDIMENSION;
+
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+
+{ Initialize for an output pass in buffered-image mode. }
+
+{GLOBAL}
+function jpeg_start_output (cinfo : j_decompress_ptr;
+                            scan_number : int) : boolean;
+
+{ Finish up after an output pass in buffered-image mode.
+
+  Returns FALSE if suspended.  The return value need be inspected only if
+  a suspending data source is used. }
+
+{GLOBAL}
+function jpeg_finish_output (cinfo : j_decompress_ptr) : boolean;
+
+{$endif} { D_MULTISCAN_FILES_SUPPORTED }
+
+{ Decompression initialization.
+  jpeg_read_header must be completed before calling this.
+
+  If a multipass operating mode was selected, this will do all but the
+  last pass, and thus may take a great deal of time.
+
+  Returns FALSE if suspended.  The return value need be inspected only if
+  a suspending data source is used. }
+
+{GLOBAL}
+function jpeg_start_decompress (cinfo : j_decompress_ptr) : boolean;
+
+
+implementation
+
+{ Forward declarations }
+{LOCAL}
+function output_pass_setup (cinfo : j_decompress_ptr) : boolean; forward;
+
+{ Decompression initialization.
+  jpeg_read_header must be completed before calling this.
+
+  If a multipass operating mode was selected, this will do all but the
+  last pass, and thus may take a great deal of time.
+
+  Returns FALSE if suspended.  The return value need be inspected only if
+  a suspending data source is used. }
+
+{GLOBAL}
+function jpeg_start_decompress (cinfo : j_decompress_ptr) : boolean;
+var
+  retcode : int;
+begin
+  if (cinfo^.global_state = DSTATE_READY) then
+  begin
+    { First call: initialize master control, select active modules }
+    jinit_master_decompress(cinfo);
+    if (cinfo^.buffered_image) then
+    begin
+      { No more work here; expecting jpeg_start_output next }
+      cinfo^.global_state := DSTATE_BUFIMAGE;
+      jpeg_start_decompress := TRUE;
+      exit;
+    end;
+    cinfo^.global_state := DSTATE_PRELOAD;
+  end;
+  if (cinfo^.global_state = DSTATE_PRELOAD) then
+  begin
+    { If file has multiple scans, absorb them all into the coef buffer }
+    if (cinfo^.inputctl^.has_multiple_scans) then
+    begin
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+      while TRUE do
+      begin
+
+  { Call progress monitor hook if present }
+  if (cinfo^.progress <> NIL) then
+    cinfo^.progress^.progress_monitor (j_common_ptr(cinfo));
+  { Absorb some more input }
+  retcode := cinfo^.inputctl^.consume_input (cinfo);
+  if (retcode = JPEG_SUSPENDED) then
+        begin
+          jpeg_start_decompress := FALSE;
+          exit;
+        end;
+  if (retcode = JPEG_REACHED_EOI) then
+    break;
+  { Advance progress counter if appropriate }
+  if (cinfo^.progress <> NIL) and
+     ((retcode = JPEG_ROW_COMPLETED) or (retcode = JPEG_REACHED_SOS)) then
+        begin
+          Inc(cinfo^.progress^.pass_counter);
+    if (cinfo^.progress^.pass_counter >= cinfo^.progress^.pass_limit) then
+          begin
+      { jdmaster underestimated number of scans; ratchet up one scan }
+      Inc(cinfo^.progress^.pass_limit, long(cinfo^.total_iMCU_rows));
+    end;
+  end;
+      end;
+{$else}
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif} { D_MULTISCAN_FILES_SUPPORTED }
+    end;
+    cinfo^.output_scan_number := cinfo^.input_scan_number;
+  end
+  else
+    if (cinfo^.global_state <> DSTATE_PRESCAN) then
+      ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  { Perform any dummy output passes, and set up for the final pass }
+  jpeg_start_decompress := output_pass_setup(cinfo);
+end;
+
+
+{ Set up for an output pass, and perform any dummy pass(es) needed.
+  Common subroutine for jpeg_start_decompress and jpeg_start_output.
+  Entry: global_state := DSTATE_PRESCAN only if previously suspended.
+  Exit: If done, returns TRUE and sets global_state for proper output mode.
+        If suspended, returns FALSE and sets global_state := DSTATE_PRESCAN. }
+
+{LOCAL}
+function output_pass_setup (cinfo : j_decompress_ptr) : boolean;
+var
+  last_scanline : JDIMENSION;
+begin
+  if (cinfo^.global_state <> DSTATE_PRESCAN) then
+  begin
+    { First call: do pass setup }
+    cinfo^.master^.prepare_for_output_pass (cinfo);
+    cinfo^.output_scanline := 0;
+    cinfo^.global_state := DSTATE_PRESCAN;
+  end;
+  { Loop over any required dummy passes }
+  while (cinfo^.master^.is_dummy_pass) do
+  begin
+{$ifdef QUANT_2PASS_SUPPORTED}
+    { Crank through the dummy pass }
+    while (cinfo^.output_scanline < cinfo^.output_height) do
+    begin
+      { Call progress monitor hook if present }
+      if (cinfo^.progress <> NIL) then
+      begin
+  cinfo^.progress^.pass_counter := long (cinfo^.output_scanline);
+  cinfo^.progress^.pass_limit := long (cinfo^.output_height);
+  cinfo^.progress^.progress_monitor (j_common_ptr(cinfo));
+      end;
+      { Process some data }
+      last_scanline := cinfo^.output_scanline;
+      cinfo^.main^.process_data (cinfo, JSAMPARRAY(NIL),
+         cinfo^.output_scanline, {var}
+                                 JDIMENSION(0));
+      if (cinfo^.output_scanline = last_scanline) then
+      begin
+  output_pass_setup := FALSE; { No progress made, must suspend }
+        exit;
+      end;
+    end;
+    { Finish up dummy pass, and set up for another one }
+    cinfo^.master^.finish_output_pass (cinfo);
+    cinfo^.master^.prepare_for_output_pass (cinfo);
+    cinfo^.output_scanline := 0;
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif} { QUANT_2PASS_SUPPORTED }
+  end;
+  { Ready for application to drive output pass through
+    jpeg_read_scanlines or jpeg_read_raw_data. }
+  if cinfo^.raw_data_out then
+    cinfo^.global_state := DSTATE_RAW_OK
+   else
+     cinfo^.global_state := DSTATE_SCANNING;
+  output_pass_setup := TRUE;
+end;
+
+
+{ Read some scanlines of data from the JPEG decompressor.
+
+  The return value will be the number of lines actually read.
+  This may be less than the number requested in several cases,
+  including bottom of image, data source suspension, and operating
+  modes that emit multiple scanlines at a time.
+
+  Note: we warn about excess calls to jpeg_read_scanlines() since
+  this likely signals an application programmer error.  However,
+  an oversize buffer (max_lines > scanlines remaining) is not an error. }
+
+{GLOBAL}
+function jpeg_read_scanlines (cinfo : j_decompress_ptr;
+                              scanlines : JSAMPARRAY;
+                  max_lines : JDIMENSION) : JDIMENSION;
+var
+  row_ctr : JDIMENSION;
+begin
+  if (cinfo^.global_state <> DSTATE_SCANNING) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  if (cinfo^.output_scanline >= cinfo^.output_height) then
+  begin
+    WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA);
+    jpeg_read_scanlines := 0;
+    exit;
+  end;
+
+  { Call progress monitor hook if present }
+  if (cinfo^.progress <> NIL) then
+  begin
+    cinfo^.progress^.pass_counter := long (cinfo^.output_scanline);
+    cinfo^.progress^.pass_limit := long (cinfo^.output_height);
+    cinfo^.progress^.progress_monitor (j_common_ptr(cinfo));
+  end;
+
+  { Process some data }
+  row_ctr := 0;
+  cinfo^.main^.process_data (cinfo, scanlines, {var}row_ctr, max_lines);
+  Inc(cinfo^.output_scanline, row_ctr);
+  jpeg_read_scanlines := row_ctr;
+end;
+
+
+{ Alternate entry point to read raw data.
+  Processes exactly one iMCU row per call, unless suspended. }
+
+{GLOBAL}
+function jpeg_read_raw_data (cinfo : j_decompress_ptr;
+                             data : JSAMPIMAGE;
+                 max_lines : JDIMENSION) : JDIMENSION;
+var
+  lines_per_iMCU_row : JDIMENSION;
+begin
+  if (cinfo^.global_state <> DSTATE_RAW_OK) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  if (cinfo^.output_scanline >= cinfo^.output_height) then
+  begin
+    WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA);
+    jpeg_read_raw_data := 0;
+    exit;
+  end;
+
+  { Call progress monitor hook if present }
+  if (cinfo^.progress <> NIL) then
+  begin
+    cinfo^.progress^.pass_counter := long (cinfo^.output_scanline);
+    cinfo^.progress^.pass_limit := long (cinfo^.output_height);
+    cinfo^.progress^.progress_monitor (j_common_ptr(cinfo));
+  end;
+
+  { Verify that at least one iMCU row can be returned. }
+  lines_per_iMCU_row := cinfo^.max_v_samp_factor * cinfo^.min_DCT_scaled_size;
+  if (max_lines < lines_per_iMCU_row) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BUFFER_SIZE);
+
+  { Decompress directly into user's buffer. }
+  if (cinfo^.coef^.decompress_data (cinfo, data) = 0) then
+  begin
+    jpeg_read_raw_data := 0;      { suspension forced, can do nothing more }
+    exit;
+  end;
+
+  { OK, we processed one iMCU row. }
+  Inc(cinfo^.output_scanline, lines_per_iMCU_row);
+  jpeg_read_raw_data := lines_per_iMCU_row;
+end;
+
+
+{ Additional entry points for buffered-image mode. }
+
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+
+{ Initialize for an output pass in buffered-image mode. }
+
+{GLOBAL}
+function jpeg_start_output (cinfo : j_decompress_ptr;
+                            scan_number : int) : boolean;
+begin
+  if (cinfo^.global_state <> DSTATE_BUFIMAGE) and
+     (cinfo^.global_state <> DSTATE_PRESCAN) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+  { Limit scan number to valid range }
+  if (scan_number <= 0) then
+    scan_number := 1;
+  if (cinfo^.inputctl^.eoi_reached) and
+     (scan_number > cinfo^.input_scan_number) then
+    scan_number := cinfo^.input_scan_number;
+  cinfo^.output_scan_number := scan_number;
+  { Perform any dummy output passes, and set up for the real pass }
+  jpeg_start_output := output_pass_setup(cinfo);
+end;
+
+
+{ Finish up after an output pass in buffered-image mode.
+
+  Returns FALSE if suspended.  The return value need be inspected only if
+  a suspending data source is used. }
+
+{GLOBAL}
+function jpeg_finish_output (cinfo : j_decompress_ptr) : boolean;
+begin
+  if ((cinfo^.global_state = DSTATE_SCANNING) or
+      (cinfo^.global_state = DSTATE_RAW_OK) and cinfo^.buffered_image) then
+  begin
+    { Terminate this pass. }
+    { We do not require the whole pass to have been completed. }
+    cinfo^.master^.finish_output_pass (cinfo);
+    cinfo^.global_state := DSTATE_BUFPOST;
+  end
+  else
+    if (cinfo^.global_state <> DSTATE_BUFPOST) then
+    begin
+      { BUFPOST := repeat call after a suspension, anything else is error }
+      ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+    end;
+  { Read markers looking for SOS or EOI }
+  while (cinfo^.input_scan_number <= cinfo^.output_scan_number) and
+  (not cinfo^.inputctl^.eoi_reached) do
+  begin
+    if (cinfo^.inputctl^.consume_input (cinfo) = JPEG_SUSPENDED) then
+    begin
+      jpeg_finish_output := FALSE;  { Suspend, come back later }
+      exit;
+    end;
+  end;
+  cinfo^.global_state := DSTATE_BUFIMAGE;
+  jpeg_finish_output := TRUE;
+end;
+
+{$endif} { D_MULTISCAN_FILES_SUPPORTED }
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdcoefct.pas b/src/lib/vampimg/JpegLib/imjdcoefct.pas
new file mode 100644 (file)
index 0000000..5024786
--- /dev/null
@@ -0,0 +1,895 @@
+unit imjdcoefct;
+
+{ This file contains the coefficient buffer controller for decompression.
+  This controller is the top level of the JPEG decompressor proper.
+  The coefficient buffer lies between entropy decoding and inverse-DCT steps.
+
+  In buffered-image mode, this controller is the interface between
+  input-oriented processing and output-oriented processing.
+  Also, the input side (only) is used when reading a file for transcoding. }
+
+{ Original: jdcoefct.c ; Copyright (C) 1994-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjpeglib;
+
+{GLOBAL}
+procedure jinit_d_coef_controller (cinfo : j_decompress_ptr;
+                                   need_full_buffer : boolean);
+
+
+implementation
+
+
+{ Block smoothing is only applicable for progressive JPEG, so: }
+{$ifndef D_PROGRESSIVE_SUPPORTED}
+{$undef BLOCK_SMOOTHING_SUPPORTED}
+{$endif}
+
+{ Private buffer controller object }
+
+{$ifdef BLOCK_SMOOTHING_SUPPORTED}
+const
+  SAVED_COEFS = 6;              { we save coef_bits[0..5] }
+type
+  Latch = array[0..SAVED_COEFS-1] of int;
+  Latch_ptr = ^Latch;
+{$endif}
+
+type
+  my_coef_ptr = ^my_coef_controller;
+  my_coef_controller = record
+    pub : jpeg_d_coef_controller; { public fields }
+
+    { These variables keep track of the current location of the input side. }
+    { cinfo^.input_iMCU_row is also used for this. }
+    MCU_ctr : JDIMENSION;               { counts MCUs processed in current row }
+    MCU_vert_offset : int;              { counts MCU rows within iMCU row }
+    MCU_rows_per_iMCU_row : int;        { number of such rows needed }
+
+    { The output side's location is represented by cinfo^.output_iMCU_row. }
+
+    { In single-pass modes, it's sufficient to buffer just one MCU.
+      We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
+      and let the entropy decoder write into that workspace each time.
+      (On 80x86, the workspace is FAR even though it's not really very big;
+      this is to keep the module interfaces unchanged when a large coefficient
+      buffer is necessary.)
+      In multi-pass modes, this array points to the current MCU's blocks
+      within the virtual arrays; it is used only by the input side. }
+
+    MCU_buffer : array[0..D_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW;
+
+  {$ifdef D_MULTISCAN_FILES_SUPPORTED}
+    { In multi-pass modes, we need a virtual block array for each component. }
+    whole_image : jvirt_barray_tbl;
+  {$endif}
+
+  {$ifdef BLOCK_SMOOTHING_SUPPORTED}
+    { When doing block smoothing, we latch coefficient Al values here }
+    coef_bits_latch : Latch_Ptr;
+  {$endif}
+  end;
+
+{ Forward declarations }
+{METHODDEF}
+function decompress_onepass (cinfo : j_decompress_ptr;
+                             output_buf : JSAMPIMAGE) : int; forward;
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+{METHODDEF}
+function decompress_data (cinfo : j_decompress_ptr;
+                          output_buf : JSAMPIMAGE) : int; forward;
+{$endif}
+{$ifdef BLOCK_SMOOTHING_SUPPORTED}
+{LOCAL}
+function smoothing_ok (cinfo : j_decompress_ptr) : boolean; forward;
+
+{METHODDEF}
+function decompress_smooth_data (cinfo : j_decompress_ptr;
+                                 output_buf : JSAMPIMAGE) : int; forward;
+{$endif}
+
+
+{LOCAL}
+procedure start_iMCU_row (cinfo : j_decompress_ptr);
+{ Reset within-iMCU-row counters for a new row (input side) }
+var
+  coef : my_coef_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+
+  { In an interleaved scan, an MCU row is the same as an iMCU row.
+    In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+    But at the bottom of the image, process only what's left. }
+
+  if (cinfo^.comps_in_scan > 1) then
+  begin
+    coef^.MCU_rows_per_iMCU_row := 1;
+  end
+  else
+  begin
+    if (cinfo^.input_iMCU_row < (cinfo^.total_iMCU_rows-1)) then
+      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor
+    else
+      coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height;
+  end;
+
+  coef^.MCU_ctr := 0;
+  coef^.MCU_vert_offset := 0;
+end;
+
+
+{ Initialize for an input processing pass. }
+
+{METHODDEF}
+procedure start_input_pass (cinfo : j_decompress_ptr);
+begin
+  cinfo^.input_iMCU_row := 0;
+  start_iMCU_row(cinfo);
+end;
+
+
+{ Initialize for an output processing pass. }
+
+{METHODDEF}
+procedure start_output_pass (cinfo : j_decompress_ptr);
+var
+  coef : my_coef_ptr;
+begin
+{$ifdef BLOCK_SMOOTHING_SUPPORTED}
+  coef := my_coef_ptr (cinfo^.coef);
+
+  { If multipass, check to see whether to use block smoothing on this pass }
+  if (coef^.pub.coef_arrays <> NIL) then
+  begin
+    if (cinfo^.do_block_smoothing) and smoothing_ok(cinfo) then
+      coef^.pub.decompress_data := decompress_smooth_data
+    else
+      coef^.pub.decompress_data := decompress_data;
+  end;
+{$endif}
+  cinfo^.output_iMCU_row := 0;
+end;
+
+
+{ Decompress and return some data in the single-pass case.
+  Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+  Input and output must run in lockstep since we have only a one-MCU buffer.
+  Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+
+  NB: output_buf contains a plane for each component in image,
+  which we index according to the component's SOF position.}
+
+{METHODDEF}
+function decompress_onepass (cinfo : j_decompress_ptr;
+                             output_buf : JSAMPIMAGE) : int;
+var
+  coef : my_coef_ptr;
+  MCU_col_num : JDIMENSION;     { index of current MCU within row }
+  last_MCU_col : JDIMENSION;
+  last_iMCU_row : JDIMENSION;
+  blkn, ci, xindex, yindex, yoffset, useful_width : int;
+  output_ptr : JSAMPARRAY;
+  start_col, output_col : JDIMENSION;
+  compptr : jpeg_component_info_ptr;
+  inverse_DCT : inverse_DCT_method_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+  last_MCU_col := cinfo^.MCUs_per_row - 1;
+  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
+
+  { Loop to process as much as one whole iMCU row }
+  for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
+  begin
+    for MCU_col_num := coef^.MCU_ctr to last_MCU_col do
+    begin
+      { Try to fetch an MCU.  Entropy decoder expects buffer to be zeroed. }
+      jzero_far( coef^.MCU_buffer[0],
+    size_t (cinfo^.blocks_in_MCU * SIZEOF(JBLOCK)));
+      if (not cinfo^.entropy^.decode_mcu (cinfo, coef^.MCU_buffer)) then
+      begin
+  { Suspension forced; update state counters and exit }
+  coef^.MCU_vert_offset := yoffset;
+  coef^.MCU_ctr := MCU_col_num;
+  decompress_onepass := JPEG_SUSPENDED;
+        exit;
+      end;
+      { Determine where data should go in output_buf and do the IDCT thing.
+        We skip dummy blocks at the right and bottom edges (but blkn gets
+        incremented past them!).  Note the inner loop relies on having
+        allocated the MCU_buffer[] blocks sequentially. }
+
+      blkn := 0;      { index of current DCT block within MCU }
+      for ci := 0 to pred(cinfo^.comps_in_scan) do
+      begin
+  compptr := cinfo^.cur_comp_info[ci];
+  { Don't bother to IDCT an uninteresting component. }
+  if (not compptr^.component_needed) then
+        begin
+    Inc(blkn, compptr^.MCU_blocks);
+    continue;
+  end;
+  inverse_DCT := cinfo^.idct^.inverse_DCT[compptr^.component_index];
+        if (MCU_col_num < last_MCU_col) then
+          useful_width := compptr^.MCU_width
+        else
+          useful_width := compptr^.last_col_width;
+
+  output_ptr := JSAMPARRAY(@ output_buf^[compptr^.component_index]^
+                                   [yoffset * compptr^.DCT_scaled_size]);
+  start_col := LongInt(MCU_col_num) * compptr^.MCU_sample_width;
+  for yindex := 0 to pred(compptr^.MCU_height) do
+        begin
+    if (cinfo^.input_iMCU_row < last_iMCU_row) or
+             (yoffset+yindex < compptr^.last_row_height) then
+          begin
+      output_col := start_col;
+      for xindex := 0 to pred(useful_width) do
+            begin
+        inverse_DCT (cinfo, compptr,
+         JCOEFPTR(coef^.MCU_buffer[blkn+xindex]),
+         output_ptr, output_col);
+        Inc(output_col, compptr^.DCT_scaled_size);
+      end;
+    end;
+    Inc(blkn, compptr^.MCU_width);
+    Inc(JSAMPROW_PTR(output_ptr), compptr^.DCT_scaled_size);
+  end;
+      end;
+    end;
+    { Completed an MCU row, but perhaps not an iMCU row }
+    coef^.MCU_ctr := 0;
+  end;
+  { Completed the iMCU row, advance counters for next one }
+  Inc(cinfo^.output_iMCU_row);
+
+  Inc(cinfo^.input_iMCU_row);
+  if (cinfo^.input_iMCU_row < cinfo^.total_iMCU_rows) then
+  begin
+    start_iMCU_row(cinfo);
+    decompress_onepass := JPEG_ROW_COMPLETED;
+    exit;
+  end;
+  { Completed the scan }
+  cinfo^.inputctl^.finish_input_pass (cinfo);
+  decompress_onepass := JPEG_SCAN_COMPLETED;
+end;
+
+{ Dummy consume-input routine for single-pass operation. }
+
+{METHODDEF}
+function dummy_consume_data (cinfo : j_decompress_ptr) : int;
+begin
+  dummy_consume_data := JPEG_SUSPENDED; { Always indicate nothing was done }
+end;
+
+
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+
+{ Consume input data and store it in the full-image coefficient buffer.
+  We read as much as one fully interleaved MCU row ("iMCU" row) per call,
+  ie, v_samp_factor block rows for each component in the scan.
+  Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.}
+
+{METHODDEF}
+function consume_data (cinfo : j_decompress_ptr) : int;
+var
+  coef : my_coef_ptr;
+  MCU_col_num : JDIMENSION;     { index of current MCU within row }
+  blkn, ci, xindex, yindex, yoffset : int;
+  start_col : JDIMENSION;
+  buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY;
+  buffer_ptr : JBLOCKROW;
+  compptr : jpeg_component_info_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+
+  { Align the virtual buffers for the components used in this scan. }
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    buffer[ci] := cinfo^.mem^.access_virt_barray
+      (j_common_ptr (cinfo), coef^.whole_image[compptr^.component_index],
+       LongInt(cinfo^.input_iMCU_row) * compptr^.v_samp_factor,
+       JDIMENSION (compptr^.v_samp_factor), TRUE);
+    { Note: entropy decoder expects buffer to be zeroed,
+      but this is handled automatically by the memory manager
+      because we requested a pre-zeroed array. }
+
+  end;
+
+  { Loop to process one whole iMCU row }
+  for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do
+  begin
+    for MCU_col_num := coef^.MCU_ctr to pred(cinfo^.MCUs_per_row) do
+    begin
+      { Construct list of pointers to DCT blocks belonging to this MCU }
+      blkn := 0;    { index of current DCT block within MCU }
+      for ci := 0 to pred(cinfo^.comps_in_scan) do
+      begin
+  compptr := cinfo^.cur_comp_info[ci];
+  start_col := LongInt(MCU_col_num) * compptr^.MCU_width;
+  for yindex := 0 to pred(compptr^.MCU_height) do
+        begin
+    buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]);
+    for xindex := 0 to pred(compptr^.MCU_width) do
+          begin
+      coef^.MCU_buffer[blkn] := buffer_ptr;
+            Inc(blkn);
+            Inc(JBLOCK_PTR(buffer_ptr));
+    end;
+  end;
+      end;
+      { Try to fetch the MCU. }
+      if (not cinfo^.entropy^.decode_mcu (cinfo, coef^.MCU_buffer)) then
+      begin
+  { Suspension forced; update state counters and exit }
+  coef^.MCU_vert_offset := yoffset;
+  coef^.MCU_ctr := MCU_col_num;
+  consume_data := JPEG_SUSPENDED;
+        exit;
+      end;
+    end;
+    { Completed an MCU row, but perhaps not an iMCU row }
+    coef^.MCU_ctr := 0;
+  end;
+  { Completed the iMCU row, advance counters for next one }
+  Inc(cinfo^.input_iMCU_row);
+  if (cinfo^.input_iMCU_row < cinfo^.total_iMCU_rows) then
+  begin
+    start_iMCU_row(cinfo);
+    consume_data := JPEG_ROW_COMPLETED;
+    exit;
+  end;
+  { Completed the scan }
+  cinfo^.inputctl^.finish_input_pass (cinfo);
+  consume_data := JPEG_SCAN_COMPLETED;
+end;
+
+
+{ Decompress and return some data in the multi-pass case.
+  Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+  Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+
+  NB: output_buf contains a plane for each component in image. }
+
+{METHODDEF}
+function decompress_data (cinfo : j_decompress_ptr;
+                          output_buf : JSAMPIMAGE) : int;
+var
+  coef : my_coef_ptr;
+  last_iMCU_row : JDIMENSION;
+  block_num : JDIMENSION;
+  ci, block_row, block_rows : int;
+  buffer : JBLOCKARRAY;
+  buffer_ptr : JBLOCKROW;
+  output_ptr : JSAMPARRAY;
+  output_col : JDIMENSION;
+  compptr : jpeg_component_info_ptr;
+  inverse_DCT : inverse_DCT_method_ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
+
+  { Force some input to be done if we are getting ahead of the input. }
+  while (cinfo^.input_scan_number < cinfo^.output_scan_number) or
+   ((cinfo^.input_scan_number = cinfo^.output_scan_number) and
+    (LongInt(cinfo^.input_iMCU_row) <= cinfo^.output_iMCU_row)) do
+  begin
+    if (cinfo^.inputctl^.consume_input(cinfo) = JPEG_SUSPENDED) then
+    begin
+      decompress_data := JPEG_SUSPENDED;
+      exit;
+    end;
+  end;
+
+  { OK, output from the virtual arrays. }
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Don't bother to IDCT an uninteresting component. }
+    if (not compptr^.component_needed) then
+      continue;
+    { Align the virtual buffer for this component. }
+    buffer := cinfo^.mem^.access_virt_barray
+      (j_common_ptr (cinfo), coef^.whole_image[ci],
+       cinfo^.output_iMCU_row * compptr^.v_samp_factor,
+       JDIMENSION (compptr^.v_samp_factor), FALSE);
+    { Count non-dummy DCT block rows in this iMCU row. }
+    if (cinfo^.output_iMCU_row < LongInt(last_iMCU_row)) then
+      block_rows := compptr^.v_samp_factor
+    else
+    begin
+      { NB: can't use last_row_height here; it is input-side-dependent! }
+      block_rows := int(LongInt(compptr^.height_in_blocks) mod compptr^.v_samp_factor);
+      if (block_rows = 0) then
+        block_rows := compptr^.v_samp_factor;
+    end;
+    inverse_DCT := cinfo^.idct^.inverse_DCT[ci];
+    output_ptr := output_buf^[ci];
+    { Loop over all DCT blocks to be processed. }
+    for block_row := 0 to pred(block_rows) do
+    begin
+      buffer_ptr := buffer^[block_row];
+      output_col := 0;
+      for block_num := 0 to pred(compptr^.width_in_blocks) do
+      begin
+  inverse_DCT (cinfo, compptr, JCOEFPTR (buffer_ptr),
+      output_ptr, output_col);
+  Inc(JBLOCK_PTR(buffer_ptr));
+  Inc(output_col, compptr^.DCT_scaled_size);
+      end;
+      Inc(JSAMPROW_PTR(output_ptr), compptr^.DCT_scaled_size);
+    end;
+    Inc(compptr);
+  end;
+
+  Inc(cinfo^.output_iMCU_row);
+  if (cinfo^.output_iMCU_row < LongInt(cinfo^.total_iMCU_rows)) then
+  begin
+    decompress_data := JPEG_ROW_COMPLETED;
+    exit;
+  end;
+  decompress_data := JPEG_SCAN_COMPLETED;
+end;
+
+{$endif} { D_MULTISCAN_FILES_SUPPORTED }
+
+
+{$ifdef BLOCK_SMOOTHING_SUPPORTED}
+
+{ This code applies interblock smoothing as described by section K.8
+  of the JPEG standard: the first 5 AC coefficients are estimated from
+  the DC values of a DCT block and its 8 neighboring blocks.
+  We apply smoothing only for progressive JPEG decoding, and only if
+  the coefficients it can estimate are not yet known to full precision. }
+
+{ Natural-order array positions of the first 5 zigzag-order coefficients }
+const
+  Q01_POS = 1;
+  Q10_POS = 8;
+  Q20_POS = 16;
+  Q11_POS = 9;
+  Q02_POS = 2;
+
+{ Determine whether block smoothing is applicable and safe.
+  We also latch the current states of the coef_bits[] entries for the
+  AC coefficients; otherwise, if the input side of the decompressor
+  advances into a new scan, we might think the coefficients are known
+  more accurately than they really are. }
+
+{LOCAL}
+function smoothing_ok (cinfo : j_decompress_ptr) : boolean;
+var
+  coef : my_coef_ptr;
+  smoothing_useful : boolean;
+  ci, coefi : int;
+  compptr : jpeg_component_info_ptr;
+  qtable : JQUANT_TBL_PTR;
+  coef_bits : coef_bits_ptr;
+  coef_bits_latch : Latch_Ptr;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+  smoothing_useful := FALSE;
+
+  if (not cinfo^.progressive_mode) or (cinfo^.coef_bits = NIL) then
+  begin
+    smoothing_ok := FALSE;
+    exit;
+  end;
+
+  { Allocate latch area if not already done }
+  if (coef^.coef_bits_latch = NIL) then
+    coef^.coef_bits_latch := Latch_Ptr(
+      cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
+                               cinfo^.num_components *
+                               (SAVED_COEFS * SIZEOF(int))) );
+  coef_bits_latch := (coef^.coef_bits_latch);
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { All components' quantization values must already be latched. }
+    qtable := compptr^.quant_table;
+    if (qtable = NIL) then
+    begin
+      smoothing_ok := FALSE;
+      exit;
+    end;
+    { Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. }
+    if (qtable^.quantval[0] = 0) or
+       (qtable^.quantval[Q01_POS] = 0) or
+       (qtable^.quantval[Q10_POS] = 0) or
+       (qtable^.quantval[Q20_POS] = 0) or
+       (qtable^.quantval[Q11_POS] = 0) or
+       (qtable^.quantval[Q02_POS] = 0) then
+    begin
+      smoothing_ok := FALSE;
+      exit;
+    end;
+    { DC values must be at least partly known for all components. }
+    coef_bits := @cinfo^.coef_bits^[ci];  { Nomssi }
+    if (coef_bits^[0] < 0) then
+    begin
+      smoothing_ok := FALSE;
+      exit;
+    end;
+    { Block smoothing is helpful if some AC coefficients remain inaccurate. }
+    for coefi := 1 to 5 do
+    begin
+      coef_bits_latch^[coefi] := coef_bits^[coefi];
+      if (coef_bits^[coefi] <> 0) then
+  smoothing_useful := TRUE;
+    end;
+    Inc(coef_bits_latch {SAVED_COEFS});
+    Inc(compptr);
+  end;
+
+  smoothing_ok := smoothing_useful;
+end;
+
+
+{ Variant of decompress_data for use when doing block smoothing. }
+
+{METHODDEF}
+function decompress_smooth_data (cinfo : j_decompress_ptr;
+                        output_buf : JSAMPIMAGE) : int;
+var
+  coef : my_coef_ptr;
+  last_iMCU_row : JDIMENSION;
+  block_num, last_block_column : JDIMENSION;
+  ci, block_row, block_rows, access_rows : int;
+  buffer : JBLOCKARRAY;
+  buffer_ptr, prev_block_row, next_block_row : JBLOCKROW;
+  output_ptr : JSAMPARRAY;
+  output_col : JDIMENSION;
+  compptr : jpeg_component_info_ptr;
+  inverse_DCT : inverse_DCT_method_ptr;
+  first_row, last_row : boolean;
+  workspace : JBLOCK;
+  coef_bits : Latch_Ptr; { coef_bits_ptr;  }
+  quanttbl : JQUANT_TBL_PTR;
+  Q00,Q01,Q02,Q10,Q11,Q20, num : INT32;
+  DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9 : int;
+  Al, pred : int;
+var
+  delta : JDIMENSION;
+begin
+  coef := my_coef_ptr (cinfo^.coef);
+  last_iMCU_row := cinfo^.total_iMCU_rows - 1;
+
+  { Force some input to be done if we are getting ahead of the input. }
+  while (cinfo^.input_scan_number <= cinfo^.output_scan_number) and
+        (not cinfo^.inputctl^.eoi_reached) do
+  begin
+    if (cinfo^.input_scan_number = cinfo^.output_scan_number) then
+    begin
+      { If input is working on current scan, we ordinarily want it to
+        have completed the current row.  But if input scan is DC,
+        we want it to keep one row ahead so that next block row's DC
+        values are up to date. }
+
+      if (cinfo^.Ss = 0) then
+        delta := 1
+      else
+        delta := 0;
+      if (LongInt(cinfo^.input_iMCU_row) > cinfo^.output_iMCU_row+LongInt(delta)) then
+  break;
+    end;
+    if (cinfo^.inputctl^.consume_input(cinfo) = JPEG_SUSPENDED) then
+    begin
+      decompress_smooth_data := JPEG_SUSPENDED;
+      exit;
+    end;
+  end;
+
+  { OK, output from the virtual arrays. }
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to (cinfo^.num_components-1) do
+  begin
+    { Don't bother to IDCT an uninteresting component. }
+    if (not compptr^.component_needed) then
+      continue;
+    { Count non-dummy DCT block rows in this iMCU row. }
+    if (cinfo^.output_iMCU_row < LongInt(last_iMCU_row)) then
+    begin
+      block_rows := compptr^.v_samp_factor;
+      access_rows := block_rows * 2; { this and next iMCU row }
+      last_row := FALSE;
+    end
+    else
+    begin
+      { NB: can't use last_row_height here; it is input-side-dependent! }
+      block_rows := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor;
+      if (block_rows = 0) then
+        block_rows := compptr^.v_samp_factor;
+      access_rows := block_rows; { this iMCU row only }
+      last_row := TRUE;
+    end;
+    { Align the virtual buffer for this component. }
+    if (cinfo^.output_iMCU_row > 0) then
+    begin
+      Inc(access_rows, compptr^.v_samp_factor); { prior iMCU row too }
+      buffer := cinfo^.mem^.access_virt_barray
+  (j_common_ptr (cinfo), coef^.whole_image[ci],
+   (cinfo^.output_iMCU_row - 1) * compptr^.v_samp_factor,
+   JDIMENSION (access_rows), FALSE);
+      Inc(JBLOCKROW_PTR(buffer), compptr^.v_samp_factor); { point to current iMCU row }
+      first_row := FALSE;
+    end
+    else
+    begin
+      buffer := cinfo^.mem^.access_virt_barray
+  (j_common_ptr (cinfo), coef^.whole_image[ci],
+   JDIMENSION (0), JDIMENSION (access_rows), FALSE);
+      first_row := TRUE;
+    end;
+    { Fetch component-dependent info }
+    coef_bits := coef^.coef_bits_latch;
+    Inc(coef_bits,  ci);                        { ci * SAVED_COEFS}
+    quanttbl := compptr^.quant_table;
+    Q00 := quanttbl^.quantval[0];
+    Q01 := quanttbl^.quantval[Q01_POS];
+    Q10 := quanttbl^.quantval[Q10_POS];
+    Q20 := quanttbl^.quantval[Q20_POS];
+    Q11 := quanttbl^.quantval[Q11_POS];
+    Q02 := quanttbl^.quantval[Q02_POS];
+    inverse_DCT := cinfo^.idct^.inverse_DCT[ci];
+    output_ptr := output_buf^[ci];
+    { Loop over all DCT blocks to be processed. }
+    for block_row := 0 to (block_rows-1) do
+    begin
+      buffer_ptr := buffer^[block_row];
+      if (first_row) and (block_row = 0) then
+  prev_block_row := buffer_ptr
+      else
+  prev_block_row := buffer^[block_row-1];
+      if (last_row) and (block_row = block_rows-1) then
+  next_block_row := buffer_ptr
+      else
+  next_block_row := buffer^[block_row+1];
+      { We fetch the surrounding DC values using a sliding-register approach.
+        Initialize all nine here so as to do the right thing on narrow pics.}
+
+      DC3 := int(prev_block_row^[0][0]);
+      DC2 := DC3;
+      DC1 := DC2;
+      DC6 := int(buffer_ptr^[0][0]);
+      DC5 := DC6;
+      DC4 := DC5;
+      DC9 := int(next_block_row^[0][0]);
+      DC8 := DC9;
+      DC7 := DC8 ;
+      output_col := 0;
+      last_block_column := compptr^.width_in_blocks - 1;
+      for block_num := 0 to last_block_column do
+      begin
+  { Fetch current DCT block into workspace so we can modify it. }
+  jcopy_block_row(buffer_ptr, JBLOCKROW (@workspace), JDIMENSION(1));
+  { Update DC values }
+  if (block_num < last_block_column) then
+        begin
+    DC3 := int (prev_block_row^[1][0]);
+    DC6 := int (buffer_ptr^[1][0]);
+    DC9 := int (next_block_row^[1][0]);
+  end;
+  { Compute coefficient estimates per K.8.
+    An estimate is applied only if coefficient is still zero,
+    and is not known to be fully accurate. }
+
+  { AC01 }
+  Al := coef_bits^[1];
+  if (Al <> 0) and (workspace[1] = 0) then
+        begin
+    num := 36 * Q00 * (DC4 - DC6);
+    if (num >= 0) then
+          begin
+      pred := int (((Q01 shl 7) + num) div (Q01 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+    end
+          else
+          begin
+      pred := int (((Q01 shl 7) - num) div (Q01 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+      pred := -pred;
+    end;
+    workspace[1] := JCOEF (pred);
+  end;
+  { AC10 }
+  Al := coef_bits^[2];
+  if (Al <> 0) and (workspace[8] = 0) then
+        begin
+    num := 36 * Q00 * (DC2 - DC8);
+    if (num >= 0) then
+          begin
+      pred := int (((Q10 shl 7) + num) div (Q10 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+    end
+          else
+          begin
+      pred := int (((Q10 shl 7) - num) div (Q10 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+      pred := -pred;
+    end;
+    workspace[8] := JCOEF (pred);
+  end;
+  { AC20 }
+  Al := coef_bits^[3];
+  if (Al <> 0) and (workspace[16] = 0) then
+        begin
+    num := 9 * Q00 * (DC2 + DC8 - 2*DC5);
+    if (num >= 0) then
+          begin
+      pred := int (((Q20 shl 7) + num) div (Q20 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+    end
+          else
+          begin
+      pred := int (((Q20 shl 7) - num) div (Q20 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+      pred := -pred;
+    end;
+    workspace[16] := JCOEF (pred);
+  end;
+  { AC11 }
+  Al := coef_bits^[4];
+  if (Al <> 0) and (workspace[9] = 0) then
+        begin
+    num := 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
+    if (num >= 0) then
+          begin
+      pred := int (((Q11 shl 7) + num) div (Q11 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+    end
+          else
+          begin
+      pred := int (((Q11 shl 7) - num) div (Q11 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+      pred := -pred;
+    end;
+    workspace[9] := JCOEF (pred);
+  end;
+  { AC02 }
+  Al := coef_bits^[5];
+  if (Al <> 0) and (workspace[2] = 0) then
+        begin
+    num := 9 * Q00 * (DC4 + DC6 - 2*DC5);
+    if (num >= 0) then
+          begin
+      pred := int (((Q02 shl 7) + num) div (Q02 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+    end
+          else
+          begin
+      pred := int (((Q02 shl 7) - num) div (Q02 shl 8));
+      if (Al > 0) and (pred >= (1 shl Al)) then
+        pred := (1 shl Al)-1;
+      pred := -pred;
+    end;
+    workspace[2] := JCOEF (pred);
+  end;
+  { OK, do the IDCT }
+  inverse_DCT (cinfo, compptr, JCOEFPTR (@workspace),
+      output_ptr, output_col);
+  { Advance for next column }
+  DC1 := DC2; DC2 := DC3;
+  DC4 := DC5; DC5 := DC6;
+  DC7 := DC8; DC8 := DC9;
+  Inc(JBLOCK_PTR(buffer_ptr));
+        Inc(JBLOCK_PTR(prev_block_row));
+        Inc(JBLOCK_PTR(next_block_row));
+  Inc(output_col, compptr^.DCT_scaled_size);
+      end;
+      Inc(JSAMPROW_PTR(output_ptr), compptr^.DCT_scaled_size);
+    end;
+    Inc(compptr);
+  end;
+
+  Inc(cinfo^.output_iMCU_row);
+  if (cinfo^.output_iMCU_row < LongInt(cinfo^.total_iMCU_rows)) then
+  begin
+    decompress_smooth_data := JPEG_ROW_COMPLETED;
+    exit;
+  end;
+  decompress_smooth_data := JPEG_SCAN_COMPLETED;
+end;
+
+{$endif} { BLOCK_SMOOTHING_SUPPORTED }
+
+
+{ Initialize coefficient buffer controller. }
+
+{GLOBAL}
+procedure jinit_d_coef_controller (cinfo : j_decompress_ptr;
+                                   need_full_buffer : boolean);
+var
+  coef : my_coef_ptr;
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+var
+  ci, access_rows : int;
+  compptr : jpeg_component_info_ptr;
+{$endif}
+var
+  buffer : JBLOCK_PTR;
+  i : int;
+begin
+  coef := my_coef_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
+        SIZEOF(my_coef_controller)) );
+  cinfo^.coef := jpeg_d_coef_controller_ptr(coef);
+  coef^.pub.start_input_pass := start_input_pass;
+  coef^.pub.start_output_pass := start_output_pass;
+{$ifdef BLOCK_SMOOTHING_SUPPORTED}
+  coef^.coef_bits_latch := NIL;
+{$endif}
+
+  { Create the coefficient buffer. }
+  if (need_full_buffer) then
+  begin
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+    { Allocate a full-image virtual array for each component, }
+    { padded to a multiple of samp_factor DCT blocks in each direction. }
+    { Note we ask for a pre-zeroed array. }
+
+    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      access_rows := compptr^.v_samp_factor;
+{$ifdef BLOCK_SMOOTHING_SUPPORTED}
+      { If block smoothing could be used, need a bigger window }
+      if (cinfo^.progressive_mode) then
+  access_rows := access_rows * 3;
+{$endif}
+      coef^.whole_image[ci] := cinfo^.mem^.request_virt_barray
+  (j_common_ptr (cinfo), JPOOL_IMAGE, TRUE,
+   JDIMENSION (jround_up( long(compptr^.width_in_blocks),
+                                long(compptr^.h_samp_factor) )),
+   JDIMENSION (jround_up( long(compptr^.height_in_blocks),
+        long(compptr^.v_samp_factor) )),
+   JDIMENSION (access_rows));
+      Inc(compptr);
+    end;
+    coef^.pub.consume_data := consume_data;
+    coef^.pub.decompress_data := decompress_data;
+    coef^.pub.coef_arrays := @(coef^.whole_image);
+                          { link to virtual arrays }
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+  end
+  else
+  begin
+    { We only need a single-MCU buffer. }
+    buffer := JBLOCK_PTR (
+      cinfo^.mem^.alloc_large (j_common_ptr (cinfo), JPOOL_IMAGE,
+          D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) );
+    for i := 0 to pred(D_MAX_BLOCKS_IN_MCU) do
+    begin
+      coef^.MCU_buffer[i] := JBLOCKROW(buffer);
+      Inc(buffer);
+    end;
+    coef^.pub.consume_data := dummy_consume_data;
+    coef^.pub.decompress_data := decompress_onepass;
+    coef^.pub.coef_arrays := NIL; { flag for no virtual arrays }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdcolor.pas b/src/lib/vampimg/JpegLib/imjdcolor.pas
new file mode 100644 (file)
index 0000000..f27fa5c
--- /dev/null
@@ -0,0 +1,501 @@
+unit imjdcolor;
+
+{ This file contains output colorspace conversion routines. }
+
+{ Original: jdcolor.c ; Copyright (C) 1991-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjutils,
+  imjdeferr,
+  imjerror,
+  imjpeglib;
+
+{ Module initialization routine for output colorspace conversion. }
+
+{GLOBAL}
+procedure jinit_color_deconverter (cinfo : j_decompress_ptr);
+
+implementation
+
+{ Private subobject }
+type
+  int_Color_Table = array[0..MAXJSAMPLE+1-1] of int;
+  int_table_ptr = ^int_Color_Table;
+  INT32_Color_Table = array[0..MAXJSAMPLE+1-1] of INT32;
+  INT32_table_ptr = ^INT32_Color_Table;
+type
+  my_cconvert_ptr = ^my_color_deconverter;
+  my_color_deconverter = record
+    pub : jpeg_color_deconverter; { public fields }
+
+    { Private state for YCC^.RGB conversion }
+    Cr_r_tab : int_table_ptr; { => table for Cr to R conversion }
+    Cb_b_tab : int_table_ptr; { => table for Cb to B conversion }
+    Cr_g_tab : INT32_table_ptr; { => table for Cr to G conversion }
+    Cb_g_tab : INT32_table_ptr; { => table for Cb to G conversion }
+  end;
+
+
+
+
+{*************** YCbCr ^. RGB conversion: most common case *************}
+
+{ YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+  normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+  The conversion equations to be implemented are therefore
+  R = Y                + 1.40200 * Cr
+  G = Y - 0.34414 * Cb - 0.71414 * Cr
+  B = Y + 1.77200 * Cb
+  where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+  (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+
+  To avoid floating-point arithmetic, we represent the fractional constants
+  as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+  the products by 2^16, with appropriate rounding, to get the correct answer.
+  Notice that Y, being an integral input, does not contribute any fraction
+  so it need not participate in the rounding.
+
+  For even more speed, we avoid doing any multiplications in the inner loop
+  by precalculating the constants times Cb and Cr for all possible values.
+  For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+  for 12-bit samples it is still acceptable.  It's not very reasonable for
+  16-bit samples, but if you want lossless storage you shouldn't be changing
+  colorspace anyway.
+  The Cr=>R and Cb=>B values can be rounded to integers in advance; the
+  values for the G calculation are left scaled up, since we must add them
+  together before rounding. }
+
+const
+  SCALEBITS = 16;      { speediest right-shift on some machines }
+  ONE_HALF  = (INT32(1) shl (SCALEBITS-1));
+
+
+{ Initialize tables for YCC->RGB colorspace conversion. }
+
+{LOCAL}
+procedure build_ycc_rgb_table (cinfo : j_decompress_ptr);
+const
+  FIX_1_40200 = INT32(Round( 1.40200  * (1 shl SCALEBITS)));
+  FIX_1_77200 = INT32(Round( 1.77200  * (1 shl SCALEBITS)));
+  FIX_0_71414 = INT32(Round( 0.71414  * (1 shl SCALEBITS)));
+  FIX_0_34414 = INT32(Round( 0.34414  * (1 shl SCALEBITS)));
+
+var
+  cconvert : my_cconvert_ptr;
+  i : int;
+  x : INT32;
+var
+  shift_temp : INT32;
+begin
+  cconvert := my_cconvert_ptr (cinfo^.cconvert);
+
+
+  cconvert^.Cr_r_tab := int_table_ptr(
+    cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(int)) );
+  cconvert^.Cb_b_tab := int_table_ptr (
+    cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(int)) );
+  cconvert^.Cr_g_tab := INT32_table_ptr (
+    cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(INT32)) );
+  cconvert^.Cb_g_tab := INT32_table_ptr (
+    cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(INT32)) );
+
+
+  x := -CENTERJSAMPLE;
+  for i := 0 to MAXJSAMPLE do
+  begin
+    { i is the actual input pixel value, in the range 0..MAXJSAMPLE }
+    { The Cb or Cr value we are thinking of is x := i - CENTERJSAMPLE }
+    { Cr=>R value is nearest int to 1.40200 * x }
+
+    shift_temp := FIX_1_40200  * x + ONE_HALF;
+    if shift_temp < 0 then  { SHIFT arithmetic RIGHT }
+      cconvert^.Cr_r_tab^[i] := int((shift_temp shr SCALEBITS)
+                             or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      cconvert^.Cr_r_tab^[i] := int(shift_temp shr SCALEBITS);
+
+    { Cb=>B value is nearest int to 1.77200 * x }
+    shift_temp := FIX_1_77200  * x + ONE_HALF;
+    if shift_temp < 0 then   { SHIFT arithmetic RIGHT }
+      cconvert^.Cb_b_tab^[i] := int((shift_temp shr SCALEBITS)
+                                or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      cconvert^.Cb_b_tab^[i] := int(shift_temp shr SCALEBITS);
+
+    { Cr=>G value is scaled-up -0.71414 * x }
+    cconvert^.Cr_g_tab^[i] := (- FIX_0_71414 ) * x;
+    { Cb=>G value is scaled-up -0.34414 * x }
+    { We also add in ONE_HALF so that need not do it in inner loop }
+    cconvert^.Cb_g_tab^[i] := (- FIX_0_34414 ) * x + ONE_HALF;
+    Inc(x);
+  end;
+end;
+
+
+{ Convert some rows of samples to the output colorspace.
+
+  Note that we change from noninterleaved, one-plane-per-component format
+  to interleaved-pixel format.  The output buffer is therefore three times
+  as wide as the input buffer.
+  A starting row offset is provided only for the input buffer.  The caller
+  can easily adjust the passed output_buf value to accommodate any row
+  offset required on that side. }
+
+{METHODDEF}
+procedure ycc_rgb_convert (cinfo : j_decompress_ptr;
+               input_buf : JSAMPIMAGE;
+                           input_row : JDIMENSION;
+                           output_buf : JSAMPARRAY;
+                           num_rows : int);
+var
+  cconvert : my_cconvert_ptr;
+  {register} y, cb, cr : int;
+  {register} outptr : JSAMPROW;
+  {register} inptr0, inptr1, inptr2 : JSAMPROW;
+  {register} col : JDIMENSION;
+  num_cols : JDIMENSION;
+  { copy these pointers into registers if possible }
+  {register} range_limit : range_limit_table_ptr;
+  {register} Crrtab : int_table_ptr;
+  {register} Cbbtab : int_table_ptr;
+  {register} Crgtab : INT32_table_ptr;
+  {register} Cbgtab : INT32_table_ptr;
+var
+  shift_temp : INT32;
+begin
+  cconvert := my_cconvert_ptr (cinfo^.cconvert);
+  num_cols := cinfo^.output_width;
+  range_limit := cinfo^.sample_range_limit;
+  Crrtab := cconvert^.Cr_r_tab;
+  Cbbtab := cconvert^.Cb_b_tab;
+  Crgtab := cconvert^.Cr_g_tab;
+  Cbgtab := cconvert^.Cb_g_tab;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    inptr0 := input_buf^[0]^[input_row];
+    inptr1 := input_buf^[1]^[input_row];
+    inptr2 := input_buf^[2]^[input_row];
+    Inc(input_row);
+    outptr := output_buf^[0];
+    Inc(JSAMPROW_PTR(output_buf));
+    for col := 0 to pred(num_cols) do
+    begin
+      y  := GETJSAMPLE(inptr0^[col]);
+      cb := GETJSAMPLE(inptr1^[col]);
+      cr := GETJSAMPLE(inptr2^[col]);
+      { Range-limiting is essential due to noise introduced by DCT losses. }
+      outptr^[RGB_RED] :=   range_limit^[y + Crrtab^[cr]];
+      shift_temp := Cbgtab^[cb] + Crgtab^[cr];
+      if shift_temp < 0 then   { SHIFT arithmetic RIGHT }
+        outptr^[RGB_GREEN] := range_limit^[y + int((shift_temp shr SCALEBITS)
+                              or ( (not INT32(0)) shl (32-SCALEBITS)))]
+      else
+        outptr^[RGB_GREEN] := range_limit^[y + int(shift_temp shr SCALEBITS)];
+
+      outptr^[RGB_BLUE] :=  range_limit^[y + Cbbtab^[cb]];
+      Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE);
+    end;
+  end;
+end;
+
+
+{*************** Cases other than YCbCr -> RGB *************}
+
+
+{ Color conversion for no colorspace change: just copy the data,
+  converting from separate-planes to interleaved representation. }
+
+{METHODDEF}
+procedure null_convert (cinfo : j_decompress_ptr;
+                  input_buf : JSAMPIMAGE;
+                        input_row : JDIMENSION;
+                  output_buf : JSAMPARRAY;
+                        num_rows : int);
+var
+  {register} inptr,
+             outptr : JSAMPLE_PTR;
+  {register} count : JDIMENSION;
+  {register} num_components : int;
+  num_cols : JDIMENSION;
+  ci : int;
+begin
+  num_components := cinfo^.num_components;
+  num_cols := cinfo^.output_width;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    for ci := 0 to pred(num_components) do
+    begin
+      inptr := JSAMPLE_PTR(input_buf^[ci]^[input_row]);
+      outptr := JSAMPLE_PTR(@(output_buf^[0]^[ci]));
+
+      for count := pred(num_cols) downto 0 do
+      begin
+  outptr^ := inptr^;  { needn't bother with GETJSAMPLE() here }
+        Inc(inptr);
+  Inc(outptr, num_components);
+      end;
+    end;
+    Inc(input_row);
+    Inc(JSAMPROW_PTR(output_buf));
+  end;
+end;
+
+
+{ Color conversion for grayscale: just copy the data.
+  This also works for YCbCr -> grayscale conversion, in which
+  we just copy the Y (luminance) component and ignore chrominance. }
+
+{METHODDEF}
+procedure grayscale_convert (cinfo : j_decompress_ptr;
+                       input_buf : JSAMPIMAGE;
+                             input_row : JDIMENSION;
+                 output_buf : JSAMPARRAY;
+                             num_rows : int);
+begin
+  jcopy_sample_rows(input_buf^[0], int(input_row), output_buf, 0,
+        num_rows, cinfo^.output_width);
+end;
+
+{ Convert grayscale to RGB: just duplicate the graylevel three times.
+  This is provided to support applications that don't want to cope
+  with grayscale as a separate case. }
+
+{METHODDEF}
+procedure gray_rgb_convert (cinfo : j_decompress_ptr;
+                      input_buf : JSAMPIMAGE;
+                            input_row : JDIMENSION;
+                output_buf : JSAMPARRAY;
+                            num_rows : int);
+var
+  {register} inptr, outptr : JSAMPLE_PTR;
+  {register} col : JDIMENSION;
+  num_cols : JDIMENSION;
+begin
+  num_cols := cinfo^.output_width;
+  while (num_rows > 0) do
+  begin
+    inptr := JSAMPLE_PTR(input_buf^[0]^[input_row]);
+    Inc(input_row);
+    outptr := JSAMPLE_PTR(@output_buf^[0]);
+    Inc(JSAMPROW_PTR(output_buf));
+    for col := 0 to pred(num_cols) do
+    begin
+      { We can dispense with GETJSAMPLE() here }
+      JSAMPROW(outptr)^[RGB_RED] := inptr^;
+      JSAMPROW(outptr)^[RGB_GREEN] := inptr^;
+      JSAMPROW(outptr)^[RGB_BLUE] := inptr^;
+      Inc(inptr);
+      Inc(outptr, RGB_PIXELSIZE);
+    end;
+    Dec(num_rows);
+  end;
+end;
+
+
+{ Adobe-style YCCK -> CMYK conversion.
+  We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
+  conversion as above, while passing K (black) unchanged.
+  We assume build_ycc_rgb_table has been called. }
+
+{METHODDEF}
+procedure ycck_cmyk_convert (cinfo : j_decompress_ptr;
+                 input_buf : JSAMPIMAGE;
+                             input_row : JDIMENSION;
+                             output_buf : JSAMPARRAY;
+                             num_rows : int);
+var
+  cconvert : my_cconvert_ptr;
+  {register} y, cb, cr : int;
+  {register} outptr : JSAMPROW;
+  {register} inptr0, inptr1, inptr2, inptr3 : JSAMPROW;
+  {register} col : JDIMENSION;
+  num_cols : JDIMENSION;
+  { copy these pointers into registers if possible }
+  {register} range_limit : range_limit_table_ptr;
+  {register} Crrtab : int_table_ptr;
+  {register} Cbbtab : int_table_ptr;
+  {register} Crgtab : INT32_table_ptr;
+  {register} Cbgtab : INT32_table_ptr;
+var
+  shift_temp : INT32;
+begin
+  cconvert := my_cconvert_ptr (cinfo^.cconvert);
+  num_cols := cinfo^.output_width;
+  { copy these pointers into registers if possible }
+  range_limit := cinfo^.sample_range_limit;
+  Crrtab := cconvert^.Cr_r_tab;
+  Cbbtab := cconvert^.Cb_b_tab;
+  Crgtab := cconvert^.Cr_g_tab;
+  Cbgtab := cconvert^.Cb_g_tab;
+
+  while (num_rows > 0) do
+  begin
+    Dec(num_rows);
+    inptr0 := input_buf^[0]^[input_row];
+    inptr1 := input_buf^[1]^[input_row];
+    inptr2 := input_buf^[2]^[input_row];
+    inptr3 := input_buf^[3]^[input_row];
+    Inc(input_row);
+    outptr := output_buf^[0];
+    Inc(JSAMPROW_PTR(output_buf));
+    for col := 0 to pred(num_cols) do
+    begin
+      y  := GETJSAMPLE(inptr0^[col]);
+      cb := GETJSAMPLE(inptr1^[col]);
+      cr := GETJSAMPLE(inptr2^[col]);
+      { Range-limiting is essential due to noise introduced by DCT losses. }
+      outptr^[0] := range_limit^[MAXJSAMPLE - (y + Crrtab^[cr])]; { red }
+      shift_temp := Cbgtab^[cb] + Crgtab^[cr];
+      if shift_temp < 0 then
+        outptr^[1] := range_limit^[MAXJSAMPLE - (y + int(
+          (shift_temp shr SCALEBITS) or ((not INT32(0)) shl (32-SCALEBITS))
+                                                        ) )]
+      else
+        outptr^[1] := range_limit^[MAXJSAMPLE -             { green }
+                    (y + int(shift_temp shr SCALEBITS) )];
+      outptr^[2] := range_limit^[MAXJSAMPLE - (y + Cbbtab^[cb])]; { blue }
+      { K passes through unchanged }
+      outptr^[3] := inptr3^[col]; { don't need GETJSAMPLE here }
+      Inc(JSAMPLE_PTR(outptr), 4);
+    end;
+  end;
+end;
+
+
+{ Empty method for start_pass. }
+
+{METHODDEF}
+procedure start_pass_dcolor (cinfo : j_decompress_ptr);
+begin
+  { no work needed }
+end;
+
+
+{ Module initialization routine for output colorspace conversion. }
+
+{GLOBAL}
+procedure jinit_color_deconverter (cinfo : j_decompress_ptr);
+var
+  cconvert : my_cconvert_ptr;
+  ci : int;
+begin
+  cconvert := my_cconvert_ptr (
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_color_deconverter)) );
+  cinfo^.cconvert := jpeg_color_deconverter_ptr (cconvert);
+  cconvert^.pub.start_pass := start_pass_dcolor;
+
+  { Make sure num_components agrees with jpeg_color_space }
+  case (cinfo^.jpeg_color_space) of
+  JCS_GRAYSCALE:
+    if (cinfo^.num_components <> 1) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+
+  JCS_RGB,
+  JCS_YCbCr:
+    if (cinfo^.num_components <> 3) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+
+  JCS_CMYK,
+  JCS_YCCK:
+    if (cinfo^.num_components <> 4) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+
+  else                     { JCS_UNKNOWN can be anything }
+    if (cinfo^.num_components < 1) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
+  end;
+
+  { Set out_color_components and conversion method based on requested space.
+    Also clear the component_needed flags for any unused components,
+    so that earlier pipeline stages can avoid useless computation. }
+
+  case (cinfo^.out_color_space) of
+  JCS_GRAYSCALE:
+    begin
+      cinfo^.out_color_components := 1;
+      if (cinfo^.jpeg_color_space = JCS_GRAYSCALE)
+        or (cinfo^.jpeg_color_space = JCS_YCbCr) then
+      begin
+        cconvert^.pub.color_convert := grayscale_convert;
+        { For color -> grayscale conversion, only the
+          Y (0) component is needed }
+        for ci := 1 to pred(cinfo^.num_components) do
+    cinfo^.comp_info^[ci].component_needed := FALSE;
+      end
+      else
+        ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  JCS_RGB:
+    begin
+      cinfo^.out_color_components := RGB_PIXELSIZE;
+      if (cinfo^.jpeg_color_space = JCS_YCbCr) then
+      begin
+        cconvert^.pub.color_convert := ycc_rgb_convert;
+        build_ycc_rgb_table(cinfo);
+      end
+      else
+        if (cinfo^.jpeg_color_space = JCS_GRAYSCALE) then
+        begin
+          cconvert^.pub.color_convert := gray_rgb_convert;
+        end
+        else
+          if (cinfo^.jpeg_color_space = JCS_RGB) and (RGB_PIXELSIZE = 3) then
+          begin
+            cconvert^.pub.color_convert := null_convert;
+          end
+          else
+            ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  JCS_CMYK:
+    begin
+      cinfo^.out_color_components := 4;
+      if (cinfo^.jpeg_color_space = JCS_YCCK) then
+      begin
+        cconvert^.pub.color_convert := ycck_cmyk_convert;
+        build_ycc_rgb_table(cinfo);
+      end
+      else
+        if (cinfo^.jpeg_color_space = JCS_CMYK) then
+        begin
+          cconvert^.pub.color_convert := null_convert;
+        end
+        else
+          ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+
+  else
+    begin { Permit null conversion to same output space }
+      if (cinfo^.out_color_space = cinfo^.jpeg_color_space) then
+      begin
+        cinfo^.out_color_components := cinfo^.num_components;
+        cconvert^.pub.color_convert := null_convert;
+      end
+      else      { unsupported non-null conversion }
+        ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
+    end;
+  end;
+
+  if (cinfo^.quantize_colors) then
+    cinfo^.output_components := 1 { single colormapped output component }
+  else
+    cinfo^.output_components := cinfo^.out_color_components;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdct.pas b/src/lib/vampimg/JpegLib/imjdct.pas
new file mode 100644 (file)
index 0000000..30d3356
--- /dev/null
@@ -0,0 +1,109 @@
+unit imjdct;
+
+{ Orignal: jdct.h; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+{ This include file contains common declarations for the forward and
+  inverse DCT modules.  These declarations are private to the DCT managers
+  (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
+  The individual DCT algorithms are kept in separate files to ease
+  machine-dependent tuning (e.g., assembly coding). }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg;
+
+
+{ A forward DCT routine is given a pointer to a work area of type DCTELEM[];
+  the DCT is to be performed in-place in that buffer.  Type DCTELEM is int
+  for 8-bit samples, INT32 for 12-bit samples.  (NOTE: Floating-point DCT
+  implementations use an array of type FAST_FLOAT, instead.)
+  The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
+  The DCT outputs are returned scaled up by a factor of 8; they therefore
+  have a range of +-8K for 8-bit data, +-128K for 12-bit data.  This
+  convention improves accuracy in integer implementations and saves some
+  work in floating-point ones.
+  Quantization of the output coefficients is done by jcdctmgr.c. }
+
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+type
+  DCTELEM = int;                { 16 or 32 bits is fine }
+{$else}
+type                            { must have 32 bits }
+  DCTELEM = INT32;
+{$endif}
+type
+  jTDctElem = 0..(MaxInt div SizeOf(DCTELEM))-1;
+  DCTELEM_FIELD = array[jTDctElem] of DCTELEM;
+  DCTELEM_FIELD_PTR = ^DCTELEM_FIELD;
+  DCTELEMPTR = ^DCTELEM;
+
+type
+  forward_DCT_method_ptr = procedure(var data : array of DCTELEM);
+  float_DCT_method_ptr = procedure(var data : array of FAST_FLOAT);
+
+
+{ An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
+  to an output sample array.  The routine must dequantize the input data as
+  well as perform the IDCT; for dequantization, it uses the multiplier table
+  pointed to by compptr->dct_table.  The output data is to be placed into the
+  sample array starting at a specified column.  (Any row offset needed will
+  be applied to the array pointer before it is passed to the IDCT code.)
+  Note that the number of samples emitted by the IDCT routine is
+  DCT_scaled_size * DCT_scaled_size. }
+
+
+{ typedef inverse_DCT_method_ptr is declared in jpegint.h }
+
+
+{ Each IDCT routine has its own ideas about the best dct_table element type. }
+
+
+type
+  ISLOW_MULT_TYPE = MULTIPLIER;  { short or int, whichever is faster }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+type
+  IFAST_MULT_TYPE = MULTIPLIER;  { 16 bits is OK, use short if faster }
+const
+  IFAST_SCALE_BITS = 2;         { fractional bits in scale factors }
+{$else}
+type
+  IFAST_MULT_TYPE = INT32;      {  need 32 bits for scaled quantizers }
+const
+  IFAST_SCALE_BITS = 13;        { fractional bits in scale factors }
+{$endif}
+type
+  FLOAT_MULT_TYPE = FAST_FLOAT; { preferred floating type }
+
+const
+  RANGE_MASK = (MAXJSAMPLE * 4 + 3); { 2 bits wider than legal samples }
+
+type
+  jTMultType = 0..(MaxInt div SizeOf(ISLOW_MULT_TYPE))-1;
+  ISLOW_MULT_TYPE_FIELD = array[jTMultType] of ISLOW_MULT_TYPE;
+  ISLOW_MULT_TYPE_FIELD_PTR = ^ISLOW_MULT_TYPE_FIELD;
+  ISLOW_MULT_TYPE_PTR = ^ISLOW_MULT_TYPE;
+
+  jTFloatType = 0..(MaxInt div SizeOf(FLOAT_MULT_TYPE))-1;
+  FLOAT_MULT_TYPE_FIELD = array[jTFloatType] of FLOAT_MULT_TYPE;
+  FLOAT_MULT_TYPE_FIELD_PTR = ^FLOAT_MULT_TYPE_FIELD;
+  FLOAT_MULT_TYPE_PTR = ^FLOAT_MULT_TYPE;
+
+  jTFastType = 0..(MaxInt div SizeOf(IFAST_MULT_TYPE))-1;
+  IFAST_MULT_TYPE_FIELD = array[jTFastType] of IFAST_MULT_TYPE;
+  IFAST_MULT_TYPE_FIELD_PTR = ^IFAST_MULT_TYPE_FIELD;
+  IFAST_MULT_TYPE_PTR = ^IFAST_MULT_TYPE;
+
+type
+  jTFastFloat = 0..(MaxInt div SizeOf(FAST_FLOAT))-1;
+  FAST_FLOAT_FIELD = array[jTFastFloat] of FAST_FLOAT;
+  FAST_FLOAT_FIELD_PTR = ^FAST_FLOAT_FIELD;
+  FAST_FLOAT_PTR = ^FAST_FLOAT;
+
+implementation
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjddctmgr.pas b/src/lib/vampimg/JpegLib/imjddctmgr.pas
new file mode 100644 (file)
index 0000000..42ae295
--- /dev/null
@@ -0,0 +1,330 @@
+unit imjddctmgr;
+
+{ Original : jddctmgr.c ;  Copyright (C) 1994-1996, Thomas G. Lane. }
+
+{ This file contains the inverse-DCT management logic.
+  This code selects a particular IDCT implementation to be used,
+  and it performs related housekeeping chores.  No code in this file
+  is executed per IDCT step, only during output pass setup.
+
+  Note that the IDCT routines are responsible for performing coefficient
+  dequantization as well as the IDCT proper.  This module sets up the
+  dequantization multiplier table needed by the IDCT routine. }
+
+interface
+
+{$I imjconfig.inc}
+
+{$N+}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjpeglib,
+  imjdct,   { Private declarations for DCT subsystem }
+  imjidctfst,
+  {$IFDEF BASM}
+  imjidctasm,
+  {$ELSE}
+  imjidctint,
+  {$ENDIF}
+  imjidctflt,
+  imjidctred;
+
+
+
+{ Initialize IDCT manager. }
+
+{GLOBAL}
+procedure jinit_inverse_dct (cinfo : j_decompress_ptr);
+
+
+implementation
+
+{ The decompressor input side (jdinput.c) saves away the appropriate
+  quantization table for each component at the start of the first scan
+  involving that component.  (This is necessary in order to correctly
+  decode files that reuse Q-table slots.)
+  When we are ready to make an output pass, the saved Q-table is converted
+  to a multiplier table that will actually be used by the IDCT routine.
+  The multiplier table contents are IDCT-method-dependent.  To support
+  application changes in IDCT method between scans, we can remake the
+  multiplier tables if necessary.
+  In buffered-image mode, the first output pass may occur before any data
+  has been seen for some components, and thus before their Q-tables have
+  been saved away.  To handle this case, multiplier tables are preset
+  to zeroes; the result of the IDCT will be a neutral gray level. }
+
+
+{ Private subobject for this module }
+
+type
+  my_idct_ptr = ^my_idct_controller;
+  my_idct_controller = record
+    pub : jpeg_inverse_dct; { public fields }
+
+    { This array contains the IDCT method code that each multiplier table
+      is currently set up for, or -1 if it's not yet set up.
+      The actual multiplier tables are pointed to by dct_table in the
+      per-component comp_info structures. }
+
+    cur_method : array[0..MAX_COMPONENTS-1] of int;
+  end; {my_idct_controller;}
+
+
+{ Allocated multiplier tables: big enough for any supported variant }
+
+type
+  multiplier_table = record
+  case byte of
+    0:(islow_array : array[0..DCTSIZE2-1] of ISLOW_MULT_TYPE);
+  {$ifdef DCT_IFAST_SUPPORTED}
+    1:(ifast_array : array[0..DCTSIZE2-1] of IFAST_MULT_TYPE);
+  {$endif}
+  {$ifdef DCT_FLOAT_SUPPORTED}
+    2:(float_array : array[0..DCTSIZE2-1] of FLOAT_MULT_TYPE);
+  {$endif}
+  end;
+
+
+{ The current scaled-IDCT routines require ISLOW-style multiplier tables,
+  so be sure to compile that code if either ISLOW or SCALING is requested. }
+
+{$ifdef DCT_ISLOW_SUPPORTED}
+  {$define PROVIDE_ISLOW_TABLES}
+{$else}
+  {$ifdef IDCT_SCALING_SUPPORTED}
+    {$define PROVIDE_ISLOW_TABLES}
+  {$endif}
+{$endif}
+
+
+{ Prepare for an output pass.
+  Here we select the proper IDCT routine for each component and build
+  a matching multiplier table. }
+
+{METHODDEF}
+procedure start_pass (cinfo : j_decompress_ptr);
+var
+  idct : my_idct_ptr;
+  ci, i : int;
+  compptr : jpeg_component_info_ptr;
+  method : J_DCT_METHOD;
+  method_ptr : inverse_DCT_method_ptr;
+  qtbl : JQUANT_TBL_PTR;
+{$ifdef PROVIDE_ISLOW_TABLES}
+var
+  ismtbl : ISLOW_MULT_TYPE_FIELD_PTR;
+{$endif}
+{$ifdef DCT_IFAST_SUPPORTED}
+const
+  CONST_BITS = 14;
+const
+  aanscales : array[0..DCTSIZE2-1] of INT16 =
+    ({ precomputed values scaled up by 14 bits }
+     16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+     22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
+     21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
+     19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
+     16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
+     12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
+     8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
+     4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247);
+var
+  ifmtbl : IFAST_MULT_TYPE_FIELD_PTR;
+  {SHIFT_TEMPS}
+
+  { Descale and correctly round an INT32 value that's scaled by N bits.
+    We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+    the fudge factor is correct for either sign of X. }
+
+  function DESCALE(x : INT32; n : int) : INT32;
+  var
+    shift_temp : INT32;
+  begin
+  {$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+    shift_temp := x + (INT32(1) shl (n-1));
+    if shift_temp < 0 then
+      Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+    else
+      Descale :=  (shift_temp shr n);
+  {$else}
+    Descale := (x + (INT32(1) shl (n-1)) shr n;
+  {$endif}
+  end;
+
+{$endif}
+{$ifdef DCT_FLOAT_SUPPORTED}
+const
+  aanscalefactor : array[0..DCTSIZE-1] of double =
+  (1.0, 1.387039845, 1.306562965, 1.175875602,
+    1.0, 0.785694958, 0.541196100, 0.275899379);
+var
+  fmtbl : FLOAT_MULT_TYPE_FIELD_PTR;
+  row, col : int;
+{$endif}
+begin
+  idct := my_idct_ptr (cinfo^.idct);
+  method := J_DCT_METHOD(0);
+  method_ptr := NIL;
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Select the proper IDCT routine for this component's scaling }
+    case (compptr^.DCT_scaled_size) of
+{$ifdef IDCT_SCALING_SUPPORTED}
+    1:begin
+        method_ptr := jpeg_idct_1x1;
+        method := JDCT_ISLOW; { jidctred uses islow-style table }
+      end;
+    2:begin
+        method_ptr := jpeg_idct_2x2;
+        method := JDCT_ISLOW; { jidctred uses islow-style table }
+      end;
+    4:begin
+        method_ptr := jpeg_idct_4x4;
+        method := JDCT_ISLOW; { jidctred uses islow-style table }
+      end;
+{$endif}
+    DCTSIZE:
+      case (cinfo^.dct_method) of
+{$ifdef DCT_ISLOW_SUPPORTED}
+      JDCT_ISLOW:
+        begin
+          method_ptr := @jpeg_idct_islow;
+          method := JDCT_ISLOW;
+  end;
+{$endif}
+{$ifdef DCT_IFAST_SUPPORTED}
+      JDCT_IFAST:
+        begin
+          method_ptr := @jpeg_idct_ifast;
+          method := JDCT_IFAST;
+        end;
+{$endif}
+{$ifdef DCT_FLOAT_SUPPORTED}
+      JDCT_FLOAT:
+        begin
+          method_ptr := @jpeg_idct_float;
+          method := JDCT_FLOAT;
+        end;
+{$endif}
+      else
+        ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+      end;
+    else
+      ERREXIT1(j_common_ptr(cinfo), JERR_BAD_DCTSIZE, compptr^.DCT_scaled_size);
+    end;
+    idct^.pub.inverse_DCT[ci] := method_ptr;
+    { Create multiplier table from quant table.
+      However, we can skip this if the component is uninteresting
+      or if we already built the table.  Also, if no quant table
+      has yet been saved for the component, we leave the
+      multiplier table all-zero; we'll be reading zeroes from the
+      coefficient controller's buffer anyway. }
+
+    if (not compptr^.component_needed) or (idct^.cur_method[ci] = int(method)) then
+      continue;
+    qtbl := compptr^.quant_table;
+    if (qtbl = NIL) then  { happens if no data yet for component }
+      continue;
+    idct^.cur_method[ci] := int(method);
+    case (method) of
+{$ifdef PROVIDE_ISLOW_TABLES}
+    JDCT_ISLOW:
+      begin
+  { For LL&M IDCT method, multipliers are equal to raw quantization
+    coefficients, but are stored as ints to ensure access efficiency. }
+
+  ismtbl := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table);
+  for i := 0 to pred(DCTSIZE2) do
+        begin
+    ismtbl^[i] := ISLOW_MULT_TYPE (qtbl^.quantval[i]);
+  end;
+      end;
+{$endif}
+{$ifdef DCT_IFAST_SUPPORTED}
+    JDCT_IFAST:
+      begin
+  { For AA&N IDCT method, multipliers are equal to quantization
+    coefficients scaled by scalefactor[row]*scalefactor[col], where
+      scalefactor[0] := 1
+      scalefactor[k] := cos(k*PI/16) * sqrt(2)    for k=1..7
+    For integer operation, the multiplier table is to be scaled by
+    IFAST_SCALE_BITS. }
+
+  ifmtbl := IFAST_MULT_TYPE_FIELD_PTR (compptr^.dct_table);
+
+  for i := 0 to pred(DCTSIZE2) do
+        begin
+    ifmtbl^[i] := IFAST_MULT_TYPE(
+      DESCALE(  INT32 (qtbl^.quantval[i]) * INT32 (aanscales[i]),
+        CONST_BITS-IFAST_SCALE_BITS) );
+  end;
+      end;
+{$endif}
+{$ifdef DCT_FLOAT_SUPPORTED}
+    JDCT_FLOAT:
+      begin
+  { For float AA&N IDCT method, multipliers are equal to quantization
+    coefficients scaled by scalefactor[row]*scalefactor[col], where
+      scalefactor[0] := 1
+      scalefactor[k] := cos(k*PI/16) * sqrt(2)    for k=1..7 }
+
+  fmtbl := FLOAT_MULT_TYPE_FIELD_PTR(compptr^.dct_table);
+
+  i := 0;
+  for row := 0 to pred(DCTSIZE) do
+        begin
+    for col := 0 to pred(DCTSIZE) do
+          begin
+      fmtbl^[i] := {FLOAT_MULT_TYPE} (
+         {double} qtbl^.quantval[i] *
+         aanscalefactor[row] * aanscalefactor[col] );
+      Inc(i);
+    end;
+  end;
+      end;
+{$endif}
+    else
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+      break;
+    end;
+    Inc(compptr);
+  end;
+end;
+
+
+{ Initialize IDCT manager. }
+
+{GLOBAL}
+procedure jinit_inverse_dct (cinfo : j_decompress_ptr);
+var
+  idct : my_idct_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  idct := my_idct_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_idct_controller)) );
+  cinfo^.idct := jpeg_inverse_dct_ptr (idct);
+  idct^.pub.start_pass := start_pass;
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Allocate and pre-zero a multiplier table for each component }
+    compptr^.dct_table :=
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          SIZEOF(multiplier_table));
+    MEMZERO(compptr^.dct_table, SIZEOF(multiplier_table));
+    { Mark multiplier table not yet set up for any method }
+    idct^.cur_method[ci] := -1;
+    Inc(compptr);
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdeferr.pas b/src/lib/vampimg/JpegLib/imjdeferr.pas
new file mode 100644 (file)
index 0000000..61fe305
--- /dev/null
@@ -0,0 +1,497 @@
+unit imjdeferr;
+
+{ This file defines the error and message codes for the cjpeg/djpeg
+  applications.  These strings are not needed as part of the JPEG library
+  proper.
+  Edit this file to add new codes, or to translate the message strings to
+  some other language. }
+
+{ Original cderror.h  ; Copyright (C) 1994, Thomas G. Lane.  }
+
+interface
+
+{$I imjconfig.inc}
+
+{ To define the enum list of message codes, include this file without
+  defining macro JMESSAGE.  To create a message string table, include it
+  again with a suitable JMESSAGE definition (see jerror.c for an example). }
+
+
+{ Original: jversion.h ; Copyright (C) 1991-1996, Thomas G. Lane. }
+{ This file contains software version identification. }
+
+const
+  JVERSION   = '6a  7-Feb-96';
+
+  JCOPYRIGHT = 'Copyright (C) 1996, Thomas G. Lane';
+
+  JNOTICE = 'Pascal Translation, Copyright (C) 1996, Jacques Nomssi Nzali';
+
+{ Create the message string table.
+  We do this from the master message list in jerror.h by re-reading
+  jerror.h with a suitable definition for macro JMESSAGE.
+  The message table is made an external symbol just in case any applications
+  want to refer to it directly. }
+
+type
+  J_MESSAGE_CODE  =(
+    JMSG_NOMESSAGE,
+    JERR_ARITH_NOTIMPL,
+    JERR_BAD_ALIGN_TYPE,
+    JERR_BAD_ALLOC_CHUNK,
+    JERR_BAD_BUFFER_MODE,
+    JERR_BAD_COMPONENT_ID,
+    JERR_BAD_DCT_COEF,
+    JERR_BAD_DCTSIZE,
+    JERR_BAD_HUFF_TABLE,
+    JERR_BAD_IN_COLORSPACE,
+    JERR_BAD_J_COLORSPACE,
+    JERR_BAD_LENGTH,
+    JERR_BAD_LIB_VERSION,
+    JERR_BAD_MCU_SIZE,
+    JERR_BAD_POOL_ID,
+    JERR_BAD_PRECISION,
+    JERR_BAD_PROGRESSION,
+    JERR_BAD_PROG_SCRIPT,
+    JERR_BAD_SAMPLING,
+    JERR_BAD_SCAN_SCRIPT,
+    JERR_BAD_STATE,
+    JERR_BAD_STRUCT_SIZE,
+    JERR_BAD_VIRTUAL_ACCESS,
+    JERR_BUFFER_SIZE,
+    JERR_CANT_SUSPEND,
+    JERR_CCIR601_NOTIMPL,
+    JERR_COMPONENT_COUNT,
+    JERR_CONVERSION_NOTIMPL,
+    JERR_DAC_INDEX,
+    JERR_DAC_VALUE,
+    JERR_DHT_COUNTS,
+    JERR_DHT_INDEX,
+    JERR_DQT_INDEX,
+    JERR_EMPTY_IMAGE,
+    JERR_EMS_READ,
+    JERR_EMS_WRITE,
+    JERR_EOI_EXPECTED,
+    JERR_FILE_READ,
+    JERR_FILE_WRITE,
+    JERR_FRACT_SAMPLE_NOTIMPL,
+    JERR_HUFF_CLEN_OVERFLOW,
+    JERR_HUFF_MISSING_CODE,
+    JERR_IMAGE_TOO_BIG,
+    JERR_INPUT_EMPTY,
+    JERR_INPUT_EOF,
+    JERR_MISMATCHED_QUANT_TABLE,
+    JERR_MISSING_DATA,
+    JERR_MODE_CHANGE,
+    JERR_NOTIMPL,
+    JERR_NOT_COMPILED,
+    JERR_NO_BACKING_STORE,
+    JERR_NO_HUFF_TABLE,
+    JERR_NO_IMAGE,
+    JERR_NO_QUANT_TABLE,
+    JERR_NO_SOI,
+    JERR_OUT_OF_MEMORY,
+    JERR_QUANT_COMPONENTS,
+    JERR_QUANT_FEW_COLORS,
+    JERR_QUANT_MANY_COLORS,
+    JERR_SOF_DUPLICATE,
+    JERR_SOF_NO_SOS,
+    JERR_SOF_UNSUPPORTED,
+    JERR_SOI_DUPLICATE,
+    JERR_SOS_NO_SOF,
+    JERR_TFILE_CREATE,
+    JERR_TFILE_READ,
+    JERR_TFILE_SEEK,
+    JERR_TFILE_WRITE,
+    JERR_TOO_LITTLE_DATA,
+    JERR_UNKNOWN_MARKER,
+    JERR_VIRTUAL_BUG,
+    JERR_WIDTH_OVERFLOW,
+    JERR_XMS_READ,
+    JERR_XMS_WRITE,
+    JMSG_COPYRIGHT,
+    JMSG_VERSION,
+    JTRC_16BIT_TABLES,
+    JTRC_ADOBE,
+    JTRC_APP0,
+    JTRC_APP14,
+    JTRC_DAC,
+    JTRC_DHT,
+    JTRC_DQT,
+    JTRC_DRI,
+    JTRC_EMS_CLOSE,
+    JTRC_EMS_OPEN,
+    JTRC_EOI,
+    JTRC_HUFFBITS,
+    JTRC_JFIF,
+    JTRC_JFIF_BADTHUMBNAILSIZE,
+    JTRC_JFIF_EXTENSION,
+    JTRC_JFIF_THUMBNAIL,
+    JTRC_MISC_MARKER,
+    JTRC_PARMLESS_MARKER,
+    JTRC_QUANTVALS,
+    JTRC_QUANT_3_NCOLORS,
+    JTRC_QUANT_NCOLORS,
+    JTRC_QUANT_SELECTED,
+    JTRC_RECOVERY_ACTION,
+    JTRC_RST,
+    JTRC_SMOOTH_NOTIMPL,
+    JTRC_SOF,
+    JTRC_SOF_COMPONENT,
+    JTRC_SOI,
+    JTRC_SOS,
+    JTRC_SOS_COMPONENT,
+    JTRC_SOS_PARAMS,
+    JTRC_TFILE_CLOSE,
+    JTRC_TFILE_OPEN,
+    JTRC_THUMB_JPEG,
+    JTRC_THUMB_PALETTE,
+    JTRC_THUMB_RGB,
+    JTRC_UNKNOWN_IDS,
+    JTRC_XMS_CLOSE,
+    JTRC_XMS_OPEN,
+    JWRN_ADOBE_XFORM,
+    JWRN_BOGUS_PROGRESSION,
+    JWRN_EXTRANEOUS_DATA,
+    JWRN_HIT_MARKER,
+    JWRN_HUFF_BAD_CODE,
+    JWRN_JFIF_MAJOR,
+    JWRN_JPEG_EOF,
+    JWRN_MUST_RESYNC,
+    JWRN_NOT_SEQUENTIAL,
+    JWRN_TOO_MUCH_DATA,
+
+
+     JMSG_FIRSTADDONCODE,  { Must be first entry! }
+
+   {$ifdef BMP_SUPPORTED}
+     JERR_BMP_BADCMAP,  { Unsupported BMP colormap format }
+     JERR_BMP_BADDEPTH,  { Only 8- and 24-bit BMP files are supported }
+     JERR_BMP_BADHEADER,  { Invalid BMP file: bad header length }
+     JERR_BMP_BADPLANES,  { Invalid BMP file: biPlanes not equal to 1 }
+     JERR_BMP_COLORSPACE,  { BMP output must be grayscale or RGB }
+     JERR_BMP_COMPRESSED,  { Sorry, compressed BMPs not yet supported }
+     JERR_BMP_NOT,  { Not a BMP file - does not start with BM }
+     JTRC_BMP,  { %dx%d 24-bit BMP image }
+     JTRC_BMP_MAPPED,  { %dx%d 8-bit colormapped BMP image }
+     JTRC_BMP_OS2,  { %dx%d 24-bit OS2 BMP image }
+     JTRC_BMP_OS2_MAPPED,  { %dx%d 8-bit colormapped OS2 BMP image }
+   {$endif} { BMP_SUPPORTED }
+
+   {$ifdef GIF_SUPPORTED}
+     JERR_GIF_BUG,  { GIF output got confused }
+     JERR_GIF_CODESIZE,  { Bogus GIF codesize %d }
+     JERR_GIF_COLORSPACE,  { GIF output must be grayscale or RGB }
+     JERR_GIF_IMAGENOTFOUND,  { Too few images in GIF file }
+     JERR_GIF_NOT,  { Not a GIF file }
+     JTRC_GIF,  { %dx%dx%d GIF image }
+     JTRC_GIF_BADVERSION,
+        { Warning: unexpected GIF version number '%c%c%c' }
+     JTRC_GIF_EXTENSION,  { Ignoring GIF extension block of type 0x%02x }
+     JTRC_GIF_NONSQUARE,  { Caution: nonsquare pixels in input }
+     JWRN_GIF_BADDATA,  { Corrupt data in GIF file }
+     JWRN_GIF_CHAR,  { Bogus char 0x%02x in GIF file, ignoring }
+     JWRN_GIF_ENDCODE,  { Premature end of GIF image }
+     JWRN_GIF_NOMOREDATA,  { Ran out of GIF bits }
+   {$endif} { GIF_SUPPORTED }
+
+   {$ifdef PPM_SUPPORTED}
+     JERR_PPM_COLORSPACE,  { PPM output must be grayscale or RGB }
+     JERR_PPM_NONNUMERIC,  { Nonnumeric data in PPM file }
+     JERR_PPM_NOT,  { Not a PPM file }
+     JTRC_PGM,  { %dx%d PGM image }
+     JTRC_PGM_TEXT,  { %dx%d text PGM image }
+     JTRC_PPM,  { %dx%d PPM image }
+     JTRC_PPM_TEXT,  { %dx%d text PPM image }
+   {$endif} { PPM_SUPPORTED }
+
+   {$ifdef RLE_SUPPORTED}
+     JERR_RLE_BADERROR,  { Bogus error code from RLE library }
+     JERR_RLE_COLORSPACE,  { RLE output must be grayscale or RGB }
+     JERR_RLE_DIMENSIONS,  { Image dimensions (%dx%d) too large for RLE }
+     JERR_RLE_EMPTY,  { Empty RLE file }
+     JERR_RLE_EOF,  { Premature EOF in RLE header }
+     JERR_RLE_MEM,  { Insufficient memory for RLE header }
+     JERR_RLE_NOT,  { Not an RLE file }
+     JERR_RLE_TOOMANYCHANNELS,  { Cannot handle %d output channels for RLE }
+     JERR_RLE_UNSUPPORTED,  { Cannot handle this RLE setup }
+     JTRC_RLE,  { %dx%d full-color RLE file }
+     JTRC_RLE_FULLMAP,  { %dx%d full-color RLE file with map of length %d }
+     JTRC_RLE_GRAY,  { %dx%d grayscale RLE file }
+     JTRC_RLE_MAPGRAY,  { %dx%d grayscale RLE file with map of length %d }
+     JTRC_RLE_MAPPED,  { %dx%d colormapped RLE file with map of length %d }
+   {$endif} { RLE_SUPPORTED }
+
+   {$ifdef TARGA_SUPPORTED}
+     JERR_TGA_BADCMAP,  { Unsupported Targa colormap format }
+     JERR_TGA_BADPARMS,  { Invalid or unsupported Targa file }
+     JERR_TGA_COLORSPACE,  { Targa output must be grayscale or RGB }
+     JTRC_TGA,  { %dx%d RGB Targa image }
+     JTRC_TGA_GRAY,  { %dx%d grayscale Targa image }
+     JTRC_TGA_MAPPED,  { %dx%d colormapped Targa image }
+   {$else}
+     JERR_TGA_NOTCOMP,  { Targa support was not compiled }
+   {$endif} { TARGA_SUPPORTED }
+
+     JERR_BAD_CMAP_FILE,
+      { Color map file is invalid or of unsupported format }
+     JERR_TOO_MANY_COLORS,
+      { Output file format cannot handle %d colormap entries }
+     JERR_UNGETC_FAILED,  { ungetc failed }
+   {$ifdef TARGA_SUPPORTED}
+     JERR_UNKNOWN_FORMAT,
+      { Unrecognized input file format --- perhaps you need -targa }
+   {$else}
+     JERR_UNKNOWN_FORMAT,  { Unrecognized input file format }
+   {$endif}
+     JERR_UNSUPPORTED_FORMAT,  { Unsupported output file format }
+
+     JMSG_LASTADDONCODE
+   );
+
+
+const
+  JMSG_LASTMSGCODE : J_MESSAGE_CODE = JMSG_LASTADDONCODE;
+
+type
+  msg_table = Array[J_MESSAGE_CODE] of string[80];
+const
+  jpeg_std_message_table : msg_table = (
+
+  { JMSG_NOMESSAGE } 'Bogus message code %d', { Must be first entry! }
+
+{ For maintenance convenience, list is alphabetical by message code name }
+  { JERR_ARITH_NOTIMPL }
+   'Sorry, there are legal restrictions on arithmetic coding',
+  { JERR_BAD_ALIGN_TYPE } 'ALIGN_TYPE is wrong, please fix',
+  { JERR_BAD_ALLOC_CHUNK } 'MAX_ALLOC_CHUNK is wrong, please fix',
+  { JERR_BAD_BUFFER_MODE } 'Bogus buffer control mode',
+  { JERR_BAD_COMPONENT_ID } 'Invalid component ID %d in SOS',
+  { JERR_BAD_DCT_COEF } 'DCT coefficient out of range',
+  { JERR_BAD_DCTSIZE } 'IDCT output block size %d not supported',
+  { JERR_BAD_HUFF_TABLE } 'Bogus Huffman table definition',
+  { JERR_BAD_IN_COLORSPACE } 'Bogus input colorspace',
+  { JERR_BAD_J_COLORSPACE } 'Bogus JPEG colorspace',
+  { JERR_BAD_LENGTH } 'Bogus marker length',
+  { JERR_BAD_LIB_VERSION }
+   'Wrong JPEG library version: library is %d, caller expects %d',
+  { JERR_BAD_MCU_SIZE } 'Sampling factors too large for interleaved scan',
+  { JERR_BAD_POOL_ID } 'Invalid memory pool code %d',
+  { JERR_BAD_PRECISION } 'Unsupported JPEG data precision %d',
+  { JERR_BAD_PROGRESSION }
+   'Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d',
+  { JERR_BAD_PROG_SCRIPT }
+   'Invalid progressive parameters at scan script entry %d',
+  { JERR_BAD_SAMPLING } 'Bogus sampling factors',
+  { JERR_BAD_SCAN_SCRIPT } 'Invalid scan script at entry %d',
+  { JERR_BAD_STATE } 'Improper call to JPEG library in state %d',
+  { JERR_BAD_STRUCT_SIZE }
+   'JPEG parameter struct mismatch: library thinks size is %d, caller expects %d',
+  { JERR_BAD_VIRTUAL_ACCESS } 'Bogus virtual array access',
+  { JERR_BUFFER_SIZE } 'Buffer passed to JPEG library is too small',
+  { JERR_CANT_SUSPEND } 'Suspension not allowed here',
+  { JERR_CCIR601_NOTIMPL } 'CCIR601 sampling not implemented yet',
+  { JERR_COMPONENT_COUNT } 'Too many color components: %d, max %d',
+  { JERR_CONVERSION_NOTIMPL } 'Unsupported color conversion request',
+  { JERR_DAC_INDEX } 'Bogus DAC index %d',
+  { JERR_DAC_VALUE } 'Bogus DAC value $%x',
+  { JERR_DHT_COUNTS } 'Bogus DHT counts',
+  { JERR_DHT_INDEX } 'Bogus DHT index %d',
+  { JERR_DQT_INDEX } 'Bogus DQT index %d',
+  { JERR_EMPTY_IMAGE } 'Empty JPEG image (DNL not supported)',
+  { JERR_EMS_READ } 'Read from EMS failed',
+  { JERR_EMS_WRITE } 'Write to EMS failed',
+  { JERR_EOI_EXPECTED } 'Didn''t expect more than one scan',
+  { JERR_FILE_READ } 'Input file read error',
+  { JERR_FILE_WRITE } 'Output file write error --- out of disk space?',
+  { JERR_FRACT_SAMPLE_NOTIMPL } 'Fractional sampling not implemented yet',
+  { JERR_HUFF_CLEN_OVERFLOW } 'Huffman code size table overflow',
+  { JERR_HUFF_MISSING_CODE } 'Missing Huffman code table entry',
+  { JERR_IMAGE_TOO_BIG } 'Maximum supported image dimension is %d pixels',
+  { JERR_INPUT_EMPTY } 'Empty input file',
+  { JERR_INPUT_EOF } 'Premature end of input file',
+  { JERR_MISMATCHED_QUANT_TABLE }
+   'Cannot transcode due to multiple use of quantization table %d',
+  { JERR_MISSING_DATA } 'Scan script does not transmit all data',
+  { JERR_MODE_CHANGE } 'Invalid color quantization mode change',
+  { JERR_NOTIMPL } 'Not implemented yet',
+  { JERR_NOT_COMPILED } 'Requested feature was omitted at compile time',
+  { JERR_NO_BACKING_STORE } 'Backing store not supported',
+  { JERR_NO_HUFF_TABLE } 'Huffman table $%02x was not defined',
+  { JERR_NO_IMAGE } 'JPEG datastream contains no image',
+  { JERR_NO_QUANT_TABLE } 'Quantization table $%02x was not defined',
+  { JERR_NO_SOI } 'Not a JPEG file: starts with $%02x $%02x',
+  { JERR_OUT_OF_MEMORY } 'Insufficient memory (case %d)',
+  { JERR_QUANT_COMPONENTS }
+   'Cannot quantize more than %d color components',
+  { JERR_QUANT_FEW_COLORS } 'Cannot quantize to fewer than %d colors',
+  { JERR_QUANT_MANY_COLORS } 'Cannot quantize to more than %d colors',
+  { JERR_SOF_DUPLICATE } 'Invalid JPEG file structure: two SOF markers',
+  { JERR_SOF_NO_SOS } 'Invalid JPEG file structure: missing SOS marker',
+  { JERR_SOF_UNSUPPORTED } 'Unsupported JPEG process: SOF type $%02x',
+  { JERR_SOI_DUPLICATE } 'Invalid JPEG file structure: two SOI markers',
+  { JERR_SOS_NO_SOF } 'Invalid JPEG file structure: SOS before SOF',
+  { JERR_TFILE_CREATE } 'Failed to create temporary file %s',
+  { JERR_TFILE_READ } 'Read failed on temporary file',
+  { JERR_TFILE_SEEK } 'Seek failed on temporary file',
+  { JERR_TFILE_WRITE }
+   'Write failed on temporary file --- out of disk space?',
+  { JERR_TOO_LITTLE_DATA } 'Application transferred too few scanlines',
+  { JERR_UNKNOWN_MARKER } 'Unsupported marker type $%02x',
+  { JERR_VIRTUAL_BUG } 'Virtual array controller messed up',
+  { JERR_WIDTH_OVERFLOW } 'Image too wide for this implementation',
+  { JERR_XMS_READ } 'Read from XMS failed',
+  { JERR_XMS_WRITE } 'Write to XMS failed',
+  { JMSG_COPYRIGHT }  JCOPYRIGHT,
+  { JMSG_VERSION } JVERSION,
+  { JTRC_16BIT_TABLES }
+   'Caution: quantization tables are too coarse for baseline JPEG',
+  { JTRC_ADOBE }
+   'Adobe APP14 marker: version %d, flags $%04x $%04x, transform %d',
+  { JTRC_APP0 } 'Unknown APP0 marker (not JFIF), length %d',
+  { JTRC_APP14 } 'Unknown APP14 marker (not Adobe), length %d',
+  { JTRC_DAC } 'Define Arithmetic Table $%02x: $%02x',
+  { JTRC_DHT } 'Define Huffman Table $%02x',
+  { JTRC_DQT } 'Define Quantization Table %d  precision %d',
+  { JTRC_DRI } 'Define Restart Interval %d',
+  { JTRC_EMS_CLOSE } 'Freed EMS handle %d',
+  { JTRC_EMS_OPEN } 'Obtained EMS handle %d',
+  { JTRC_EOI } 'End Of Image',
+  { JTRC_HUFFBITS } '        %3d %3d %3d %3d %3d %3d %3d %3d',
+  { JTRC_JFIF } 'JFIF APP0 marker, density %dx%d  %d',
+  { JTRC_JFIF_BADTHUMBNAILSIZE }
+   'Warning: thumbnail image size does not match data length %d',
+  { JTRC_JFIF_EXTENSION } 'JFIF extension marker: type 0x%02x, length %u',
+  { JTRC_JFIF_THUMBNAIL } '    with %d x %d thumbnail image',
+  { JTRC_MISC_MARKER } 'Skipping marker $%02x, length %d',
+  { JTRC_PARMLESS_MARKER } 'Unexpected marker $%02x',
+  { JTRC_QUANTVALS } '        %4d %4d %4d %4d %4d %4d %4d %4d',
+  { JTRC_QUANT_3_NCOLORS } 'Quantizing to %d = %d*%d*%d colors',
+  { JTRC_QUANT_NCOLORS } 'Quantizing to %d colors',
+  { JTRC_QUANT_SELECTED } 'Selected %d colors for quantization',
+  { JTRC_RECOVERY_ACTION } 'At marker $%02x, recovery action %d',
+  { JTRC_RST } 'RST%d',
+  { JTRC_SMOOTH_NOTIMPL }
+   'Smoothing not supported with nonstandard sampling ratios',
+  { JTRC_SOF } 'Start Of Frame $%02x: width=%d, height=%d, components=%d',
+  { JTRC_SOF_COMPONENT } '    Component %d: %dhx%dv q=%d',
+  { JTRC_SOI } 'Start of Image',
+  { JTRC_SOS } 'Start Of Scan: %d components',
+  { JTRC_SOS_COMPONENT } '    Component %d: dc=%d ac=%d',
+  { JTRC_SOS_PARAMS } '  Ss=%d, Se=%d, Ah=%d, Al=%d',
+  { JTRC_TFILE_CLOSE } 'Closed temporary file %s',
+  { JTRC_TFILE_OPEN } 'Opened temporary file %s',
+  { JTRC_THUMB_JPEG }
+   'JFIF extension marker: JPEG-compressed thumbnail image, length %u',
+  { JMESSAGE(JTRC_THUMB_PALETTE }
+   'JFIF extension marker: palette thumbnail image, length %u',
+  { JMESSAGE(JTRC_THUMB_RGB }
+   'JFIF extension marker: RGB thumbnail image, length %u',
+  { JTRC_UNKNOWN_IDS }
+   'Unrecognized component IDs %d %d %d, assuming YCbCr',
+  { JTRC_XMS_CLOSE } 'Freed XMS handle %d',
+  { JTRC_XMS_OPEN } 'Obtained XMS handle %d',
+  { JWRN_ADOBE_XFORM } 'Unknown Adobe color transform code %d',
+  { JWRN_BOGUS_PROGRESSION }
+   'Inconsistent progression sequence for component %d coefficient %d',
+  { JWRN_EXTRANEOUS_DATA }
+   'Corrupt JPEG data: %d extraneous bytes before marker $%02x',
+  { JWRN_HIT_MARKER } 'Corrupt JPEG data: premature end of data segment',
+  { JWRN_HUFF_BAD_CODE } 'Corrupt JPEG data: bad Huffman code',
+  { JWRN_JFIF_MAJOR } 'Warning: unknown JFIF revision number %d.%02d',
+  { JWRN_JPEG_EOF } 'Premature end of JPEG file',
+  { JWRN_MUST_RESYNC }
+   'Corrupt JPEG data: found marker $%02x instead of RST%d',
+  { JWRN_NOT_SEQUENTIAL } 'Invalid SOS parameters for sequential JPEG',
+  { JWRN_TOO_MUCH_DATA } 'Application transferred too many scanlines',
+
+  { JMSG_FIRSTADDONCODE }  '', { Must be first entry! }
+
+{$ifdef BMP_SUPPORTED}
+  { JERR_BMP_BADCMAP } 'Unsupported BMP colormap format',
+  { JERR_BMP_BADDEPTH } 'Only 8- and 24-bit BMP files are supported',
+  { JERR_BMP_BADHEADER } 'Invalid BMP file: bad header length',
+  { JERR_BMP_BADPLANES } 'Invalid BMP file: biPlanes not equal to 1',
+  { JERR_BMP_COLORSPACE } 'BMP output must be grayscale or RGB',
+  { JERR_BMP_COMPRESSED } 'Sorry, compressed BMPs not yet supported',
+  { JERR_BMP_NOT } 'Not a BMP file - does not start with BM',
+  { JTRC_BMP } '%dx%d 24-bit BMP image',
+  { JTRC_BMP_MAPPED } '%dx%d 8-bit colormapped BMP image',
+  { JTRC_BMP_OS2 } '%dx%d 24-bit OS2 BMP image',
+  { JTRC_BMP_OS2_MAPPED } '%dx%d 8-bit colormapped OS2 BMP image',
+{$endif} { BMP_SUPPORTED }
+
+{$ifdef GIF_SUPPORTED}
+  { JERR_GIF_BUG } 'GIF output got confused',
+  { JERR_GIF_CODESIZE } 'Bogus GIF codesize %d',
+  { JERR_GIF_COLORSPACE } 'GIF output must be grayscale or RGB',
+  { JERR_GIF_IMAGENOTFOUND } 'Too few images in GIF file',
+  { JERR_GIF_NOT } 'Not a GIF file',
+  { JTRC_GIF } '%dx%dx%d GIF image',
+  { JTRC_GIF_BADVERSION }
+     'Warning: unexpected GIF version number "%c%c%c"',
+  { JTRC_GIF_EXTENSION } 'Ignoring GIF extension block of type 0x%02x',
+  { JTRC_GIF_NONSQUARE } 'Caution: nonsquare pixels in input',
+  { JWRN_GIF_BADDATA } 'Corrupt data in GIF file',
+  { JWRN_GIF_CHAR } 'Bogus char 0x%02x in GIF file, ignoring',
+  { JWRN_GIF_ENDCODE } 'Premature end of GIF image',
+  { JWRN_GIF_NOMOREDATA } 'Ran out of GIF bits',
+{$endif} { GIF_SUPPORTED }
+
+{$ifdef PPM_SUPPORTED}
+  { JERR_PPM_COLORSPACE } 'PPM output must be grayscale or RGB',
+  { JERR_PPM_NONNUMERIC } 'Nonnumeric data in PPM file',
+  { JERR_PPM_NOT } 'Not a PPM file',
+  { JTRC_PGM } '%dx%d PGM image',
+  { JTRC_PGM_TEXT } '%dx%d text PGM image',
+  { JTRC_PPM } '%dx%d PPM image',
+  { JTRC_PPM_TEXT } '%dx%d text PPM image',
+{$endif} { PPM_SUPPORTED }
+
+{$ifdef RLE_SUPPORTED}
+  { JERR_RLE_BADERROR } 'Bogus error code from RLE library',
+  { JERR_RLE_COLORSPACE } 'RLE output must be grayscale or RGB',
+  { JERR_RLE_DIMENSIONS } 'Image dimensions (%dx%d) too large for RLE',
+  { JERR_RLE_EMPTY } 'Empty RLE file',
+  { JERR_RLE_EOF } 'Premature EOF in RLE header',
+  { JERR_RLE_MEM } 'Insufficient memory for RLE header',
+  { JERR_RLE_NOT } 'Not an RLE file',
+  { JERR_RLE_TOOMANYCHANNELS } 'Cannot handle %d output channels for RLE',
+  { JERR_RLE_UNSUPPORTED } 'Cannot handle this RLE setup',
+  { JTRC_RLE } '%dx%d full-color RLE file',
+  { JTRC_RLE_FULLMAP } '%dx%d full-color RLE file with map of length %d',
+  { JTRC_RLE_GRAY } '%dx%d grayscale RLE file',
+  { JTRC_RLE_MAPGRAY } '%dx%d grayscale RLE file with map of length %d',
+  { JTRC_RLE_MAPPED } '%dx%d colormapped RLE file with map of length %d',
+{$endif} { RLE_SUPPORTED }
+
+{$ifdef TARGA_SUPPORTED}
+  { JERR_TGA_BADCMAP } 'Unsupported Targa colormap format',
+  { JERR_TGA_BADPARMS } 'Invalid or unsupported Targa file',
+  { JERR_TGA_COLORSPACE } 'Targa output must be grayscale or RGB',
+  { JTRC_TGA } '%dx%d RGB Targa image',
+  { JTRC_TGA_GRAY } '%dx%d grayscale Targa image',
+  { JTRC_TGA_MAPPED } '%dx%d colormapped Targa image',
+{$else}
+  { JERR_TGA_NOTCOMP } 'Targa support was not compiled',
+{$endif} { TARGA_SUPPORTED }
+
+  { JERR_BAD_CMAP_FILE }
+   'Color map file is invalid or of unsupported format',
+  { JERR_TOO_MANY_COLORS }
+   'Output file format cannot handle %d colormap entries',
+  { JERR_UNGETC_FAILED } 'ungetc failed',
+{$ifdef TARGA_SUPPORTED}
+  { JERR_UNKNOWN_FORMAT }
+   'Unrecognized input file format --- perhaps you need -targa',
+{$else}
+  { JERR_UNKNOWN_FORMAT } 'Unrecognized input file format',
+{$endif}
+  { JERR_UNSUPPORTED_FORMAT } 'Unsupported output file format',
+
+
+  { JMSG_LASTADDONCODE } '');
+
+implementation
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdhuff.pas b/src/lib/vampimg/JpegLib/imjdhuff.pas
new file mode 100644 (file)
index 0000000..09f0e66
--- /dev/null
@@ -0,0 +1,1204 @@
+unit imjdhuff;
+
+{ This file contains declarations for Huffman entropy decoding routines
+  that are shared between the sequential decoder (jdhuff.c) and the
+  progressive decoder (jdphuff.c).  No other modules need to see these. }
+
+{ This file contains Huffman entropy decoding routines.
+
+  Much of the complexity here has to do with supporting input suspension.
+  If the data source module demands suspension, we want to be able to back
+  up to the start of the current MCU.  To do this, we copy state variables
+  into local working storage, and update them back to the permanent
+  storage only upon successful completion of an MCU. }
+
+{ Original: jdhuff.h+jdhuff.c;  Copyright (C) 1991-1997, Thomas G. Lane. }
+
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjpeglib;
+
+
+{ Declarations shared with jdphuff.c }
+
+
+
+{ Derived data constructed for each Huffman table }
+
+const
+  HUFF_LOOKAHEAD  = 8;          { # of bits of lookahead }
+
+type
+  d_derived_tbl_ptr = ^d_derived_tbl;
+  d_derived_tbl = record
+    { Basic tables: (element [0] of each array is unused) }
+    maxcode : array[0..18-1] of INT32;       { largest code of length k (-1 if none) }
+    { (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) }
+    valoffset : array[0..17-1] of INT32;     { huffval[] offset for codes of length k }
+    { valoffset[k] = huffval[] index of 1st symbol of code length k, less
+      the smallest code of length k; so given a code of length k, the
+      corresponding symbol is huffval[code + valoffset[k]] }
+
+    { Link to public Huffman table (needed only in jpeg_huff_decode) }
+    pub : JHUFF_TBL_PTR;
+
+    { Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
+      the input data stream.  If the next Huffman code is no more
+      than HUFF_LOOKAHEAD bits long, we can obtain its length and
+      the corresponding symbol directly from these tables. }
+
+    look_nbits : array[0..(1 shl HUFF_LOOKAHEAD)-1] of int;
+                                { # bits, or 0 if too long }
+    look_sym : array[0..(1 shl HUFF_LOOKAHEAD)-1] of UINT8;
+                                { symbol, or unused }
+  end;
+
+{ Fetching the next N bits from the input stream is a time-critical operation
+  for the Huffman decoders.  We implement it with a combination of inline
+  macros and out-of-line subroutines.  Note that N (the number of bits
+  demanded at one time) never exceeds 15 for JPEG use.
+
+  We read source bytes into get_buffer and dole out bits as needed.
+  If get_buffer already contains enough bits, they are fetched in-line
+  by the macros CHECK_BIT_BUFFER and GET_BITS.  When there aren't enough
+  bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer
+  as full as possible (not just to the number of bits needed; this
+  prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer).
+  Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension.
+  On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains
+  at least the requested number of bits --- dummy zeroes are inserted if
+  necessary. }
+
+
+type
+  bit_buf_type = INT32 ;        { type of bit-extraction buffer }
+const
+  BIT_BUF_SIZE = 32;            { size of buffer in bits }
+
+{ If long is > 32 bits on your machine, and shifting/masking longs is
+  reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
+  appropriately should be a win.  Unfortunately we can't define the size
+  with something like  #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)
+  because not all machines measure sizeof in 8-bit bytes. }
+
+type
+  bitread_perm_state = record   { Bitreading state saved across MCUs }
+    get_buffer : bit_buf_type;  { current bit-extraction buffer }
+    bits_left : int;            { # of unused bits in it }
+  end;
+
+type
+  bitread_working_state = record
+    { Bitreading working state within an MCU }
+    { current data source location }
+    { We need a copy, rather than munging the original, in case of suspension }
+    next_input_byte : JOCTETptr;  { => next byte to read from source }
+    bytes_in_buffer : size_t;     { # of bytes remaining in source buffer }
+    { Bit input buffer --- note these values are kept in register variables,
+      not in this struct, inside the inner loops. }
+
+    get_buffer : bit_buf_type;  { current bit-extraction buffer }
+    bits_left : int;            { # of unused bits in it }
+    { Pointer needed by jpeg_fill_bit_buffer }
+    cinfo : j_decompress_ptr;   { back link to decompress master record }
+  end;
+
+{ Module initialization routine for Huffman entropy decoding. }
+
+{GLOBAL}
+procedure jinit_huff_decoder (cinfo : j_decompress_ptr);
+
+{GLOBAL}
+function jpeg_huff_decode(var state : bitread_working_state;
+                          get_buffer : bit_buf_type; {register}
+                          bits_left : int; {register}
+                          htbl : d_derived_tbl_ptr;
+                          min_bits : int) : int;
+
+{ Compute the derived values for a Huffman table.
+  Note this is also used by jdphuff.c. }
+
+{GLOBAL}
+procedure jpeg_make_d_derived_tbl (cinfo : j_decompress_ptr;
+                                   isDC : boolean;
+                                   tblno : int;
+                 var pdtbl : d_derived_tbl_ptr);
+
+{ Load up the bit buffer to a depth of at least nbits }
+
+function jpeg_fill_bit_buffer (var state : bitread_working_state;
+                                 get_buffer : bit_buf_type;  {register}
+                           bits_left : int; {register}
+                                 nbits : int) : boolean;
+
+implementation
+
+{$IFDEF MACRO}
+
+{ Macros to declare and load/save bitread local variables. }
+{$define BITREAD_STATE_VARS}
+  get_buffer : bit_buf_type ; {register}
+  bits_left : int; {register}
+  br_state : bitread_working_state;
+
+{$define BITREAD_LOAD_STATE(cinfop,permstate)}
+  br_state.cinfo := cinfop;
+  br_state.next_input_byte := cinfop^.src^.next_input_byte;
+  br_state.bytes_in_buffer := cinfop^.src^.bytes_in_buffer;
+  get_buffer := permstate.get_buffer;
+  bits_left := permstate.bits_left;
+
+{$define BITREAD_SAVE_STATE(cinfop,permstate) }
+  cinfop^.src^.next_input_byte := br_state.next_input_byte;
+  cinfop^.src^.bytes_in_buffer := br_state.bytes_in_buffer;
+  permstate.get_buffer := get_buffer;
+  permstate.bits_left := bits_left;
+
+
+{ These macros provide the in-line portion of bit fetching.
+  Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer
+  before using GET_BITS, PEEK_BITS, or DROP_BITS.
+  The variables get_buffer and bits_left are assumed to be locals,
+  but the state struct might not be (jpeg_huff_decode needs this).
+  CHECK_BIT_BUFFER(state,n,action);
+    Ensure there are N bits in get_buffer; if suspend, take action.
+       val = GET_BITS(n);
+    Fetch next N bits.
+       val = PEEK_BITS(n);
+    Fetch next N bits without removing them from the buffer.
+  DROP_BITS(n);
+    Discard next N bits.
+  The value N should be a simple variable, not an expression, because it
+  is evaluated multiple times. }
+
+
+{$define CHECK_BIT_BUFFER(state,nbits,action)}
+  if (bits_left < (nbits)) then
+  begin
+    if (not jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) then
+    begin
+      action;
+      exit;
+    end;
+    get_buffer := state.get_buffer;
+    bits_left := state.bits_left;
+  end;
+
+
+{$define GET_BITS(nbits)}
+  Dec(bits_left, (nbits));
+  ( (int(get_buffer shr bits_left)) and ( pred(1 shl (nbits)) ) )
+
+{$define PEEK_BITS(nbits)}
+  int(get_buffer shr (bits_left -  (nbits))) and pred(1 shl (nbits))
+
+{$define DROP_BITS(nbits)}
+  Dec(bits_left, nbits);
+
+
+
+
+{ Code for extracting next Huffman-coded symbol from input bit stream.
+  Again, this is time-critical and we make the main paths be macros.
+
+  We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
+  without looping.  Usually, more than 95% of the Huffman codes will be 8
+  or fewer bits long.  The few overlength codes are handled with a loop,
+  which need not be inline code.
+
+  Notes about the HUFF_DECODE macro:
+  1. Near the end of the data segment, we may fail to get enough bits
+     for a lookahead.  In that case, we do it the hard way.
+  2. If the lookahead table contains no entry, the next code must be
+     more than HUFF_LOOKAHEAD bits long.
+  3. jpeg_huff_decode returns -1 if forced to suspend. }
+
+
+
+
+macro HUFF_DECODE(s,br_state,htbl,return FALSE,slowlabel);
+label showlabel;
+var
+ nb, look : int; {register}
+begin
+  if (bits_left < HUFF_LOOKAHEAD) then
+  begin
+    if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then
+    begin
+      decode_mcu := FALSE;
+      exit;
+    end;
+    get_buffer := br_state.get_buffer;
+    bits_left := br_state.bits_left;
+    if (bits_left < HUFF_LOOKAHEAD) then
+    begin
+      nb := 1;
+      goto slowlabel;
+    end;
+  end;
+  {look := PEEK_BITS(HUFF_LOOKAHEAD);}
+  look := int(get_buffer shr (bits_left -  HUFF_LOOKAHEAD)) and
+                 pred(1 shl HUFF_LOOKAHEAD);
+
+  nb := htbl^.look_nbits[look];
+  if (nb <> 0) then
+  begin
+    {DROP_BITS(nb);}
+    Dec(bits_left, nb);
+
+    s := htbl^.look_sym[look];
+  end
+  else
+  begin
+    nb := HUFF_LOOKAHEAD+1;
+slowlabel:
+    s := jpeg_huff_decode(br_state,get_buffer,bits_left,htbl,nb));
+    if (s < 0) then
+    begin
+      result := FALSE;
+      exit;
+    end;
+    get_buffer := br_state.get_buffer;
+    bits_left := br_state.bits_left;
+  end;
+end;
+
+
+{$ENDIF} {MACRO}
+
+{ Expanded entropy decoder object for Huffman decoding.
+
+  The savable_state subrecord contains fields that change within an MCU,
+  but must not be updated permanently until we complete the MCU. }
+
+type
+  savable_state = record
+    last_dc_val : array[0..MAX_COMPS_IN_SCAN-1] of int; { last DC coef for each component }
+  end;
+
+
+type
+  huff_entropy_ptr = ^huff_entropy_decoder;
+  huff_entropy_decoder = record
+    pub : jpeg_entropy_decoder; { public fields }
+
+    { These fields are loaded into local variables at start of each MCU.
+      In case of suspension, we exit WITHOUT updating them. }
+
+    bitstate : bitread_perm_state;  { Bit buffer at start of MCU }
+    saved : savable_state;    { Other state at start of MCU }
+
+    { These fields are NOT loaded into local working state. }
+    restarts_to_go : uInt;              { MCUs left in this restart interval }
+
+    { Pointers to derived tables (these workspaces have image lifespan) }
+    dc_derived_tbls : array[0..NUM_HUFF_TBLS] of d_derived_tbl_ptr;
+    ac_derived_tbls : array[0..NUM_HUFF_TBLS] of d_derived_tbl_ptr;
+
+    { Precalculated info set up by start_pass for use in decode_mcu: }
+
+    { Pointers to derived tables to be used for each block within an MCU }
+    dc_cur_tbls : array[0..D_MAX_BLOCKS_IN_MCU-1] of d_derived_tbl_ptr;
+    ac_cur_tbls : array[0..D_MAX_BLOCKS_IN_MCU-1] of d_derived_tbl_ptr;
+    { Whether we care about the DC and AC coefficient values for each block }
+    dc_needed : array[0..D_MAX_BLOCKS_IN_MCU-1] of boolean;
+    ac_needed : array[0..D_MAX_BLOCKS_IN_MCU-1] of boolean;
+  end;
+
+
+
+{ Initialize for a Huffman-compressed scan. }
+
+{METHODDEF}
+procedure start_pass_huff_decoder (cinfo : j_decompress_ptr);
+var
+  entropy : huff_entropy_ptr;
+  ci, blkn, dctbl, actbl : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+
+  { Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+    This ought to be an error condition, but we make it a warning because
+    there are some baseline files out there with all zeroes in these bytes. }
+
+  if (cinfo^.Ss <> 0) or (cinfo^.Se <> DCTSIZE2-1) or
+     (cinfo^.Ah <> 0) or (cinfo^.Al <> 0) then
+    WARNMS(j_common_ptr(cinfo), JWRN_NOT_SEQUENTIAL);
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    dctbl := compptr^.dc_tbl_no;
+    actbl := compptr^.ac_tbl_no;
+    { Compute derived values for Huffman tables }
+    { We may do this more than once for a table, but it's not expensive }
+    jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl,
+          entropy^.dc_derived_tbls[dctbl]);
+    jpeg_make_d_derived_tbl(cinfo, FALSE, actbl,
+          entropy^.ac_derived_tbls[actbl]);
+    { Initialize DC predictions to 0 }
+    entropy^.saved.last_dc_val[ci] := 0;
+  end;
+
+  { Precalculate decoding info for each block in an MCU of this scan }
+  for blkn := 0 to pred(cinfo^.blocks_in_MCU) do
+  begin
+    ci := cinfo^.MCU_membership[blkn];
+    compptr := cinfo^.cur_comp_info[ci];
+    { Precalculate which table to use for each block }
+    entropy^.dc_cur_tbls[blkn] := entropy^.dc_derived_tbls[compptr^.dc_tbl_no];
+    entropy^.ac_cur_tbls[blkn] := entropy^.ac_derived_tbls[compptr^.ac_tbl_no];
+    { Decide whether we really care about the coefficient values }
+    if (compptr^.component_needed) then
+    begin
+      entropy^.dc_needed[blkn] := TRUE;
+      { we don't need the ACs if producing a 1/8th-size image }
+      entropy^.ac_needed[blkn] := (compptr^.DCT_scaled_size > 1);
+    end
+    else
+    begin
+      entropy^.ac_needed[blkn] := FALSE;
+      entropy^.dc_needed[blkn] := FALSE;
+    end;
+  end;
+
+  { Initialize bitread state variables }
+  entropy^.bitstate.bits_left := 0;
+  entropy^.bitstate.get_buffer := 0; { unnecessary, but keeps Purify quiet }
+  entropy^.pub.insufficient_data := FALSE;
+
+  { Initialize restart counter }
+  entropy^.restarts_to_go := cinfo^.restart_interval;
+end;
+
+
+{ Compute the derived values for a Huffman table.
+  This routine also performs some validation checks on the table.
+
+  Note this is also used by jdphuff.c. }
+
+{GLOBAL}
+procedure jpeg_make_d_derived_tbl (cinfo : j_decompress_ptr;
+                                   isDC : boolean;
+                                   tblno : int;
+                             var pdtbl : d_derived_tbl_ptr);
+var
+  htbl : JHUFF_TBL_PTR;
+  dtbl : d_derived_tbl_ptr;
+  p, i, l, si, numsymbols : int;
+  lookbits, ctr : int;
+  huffsize : array[0..257-1] of byte;
+  huffcode : array[0..257-1] of uInt;
+  code : uInt;
+var
+  sym : int;
+begin
+  { Note that huffsize[] and huffcode[] are filled in code-length order,
+    paralleling the order of the symbols themselves in htbl^.huffval[]. }
+
+  { Find the input Huffman table }
+  if (tblno < 0) or (tblno >= NUM_HUFF_TBLS) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno);
+  if isDC then
+    htbl := cinfo^.dc_huff_tbl_ptrs[tblno]
+  else
+    htbl := cinfo^.ac_huff_tbl_ptrs[tblno];
+  if (htbl = NIL) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno);
+
+  { Allocate a workspace if we haven't already done so. }
+  if (pdtbl = NIL) then
+    pdtbl := d_derived_tbl_ptr(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          SIZEOF(d_derived_tbl)) );
+  dtbl := pdtbl;
+  dtbl^.pub := htbl;    { fill in back link }
+
+  { Figure C.1: make table of Huffman code length for each symbol }
+
+  p := 0;
+  for l := 1 to 16 do
+  begin
+    i := int(htbl^.bits[l]);
+    if (i < 0) or (p + i > 256) then  { protect against table overrun }
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+    while (i > 0) do
+    begin
+      huffsize[p] := byte(l);
+      Inc(p);
+      Dec(i);
+    end;
+  end;
+  huffsize[p] := 0;
+  numsymbols := p;
+
+  { Figure C.2: generate the codes themselves }
+  { We also validate that the counts represent a legal Huffman code tree. }
+
+  code := 0;
+  si := huffsize[0];
+  p := 0;
+  while (huffsize[p] <> 0) do
+  begin
+    while (( int (huffsize[p]) ) = si) do
+    begin
+      huffcode[p] := code;
+      Inc(p);
+      Inc(code);
+    end;
+    { code is now 1 more than the last code used for codelength si; but
+      it must still fit in si bits, since no code is allowed to be all ones. }
+
+    if (INT32(code) >= (INT32(1) shl si)) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+
+    code := code shl 1;
+    Inc(si);
+  end;
+
+  { Figure F.15: generate decoding tables for bit-sequential decoding }
+
+  p := 0;
+  for l := 1 to 16 do
+  begin
+    if (htbl^.bits[l] <> 0) then
+    begin
+      { valoffset[l] = huffval[] index of 1st symbol of code length l,
+        minus the minimum code of length l }
+
+      dtbl^.valoffset[l] := INT32(p) - INT32(huffcode[p]);
+      Inc(p, htbl^.bits[l]);
+      dtbl^.maxcode[l] := huffcode[p-1]; { maximum code of length l }
+    end
+    else
+    begin
+      dtbl^.maxcode[l] := -1; { -1 if no codes of this length }
+    end;
+  end;
+  dtbl^.maxcode[17] := long($FFFFF); { ensures jpeg_huff_decode terminates }
+
+  { Compute lookahead tables to speed up decoding.
+    First we set all the table entries to 0, indicating "too long";
+    then we iterate through the Huffman codes that are short enough and
+    fill in all the entries that correspond to bit sequences starting
+    with that code. }
+
+  MEMZERO(@dtbl^.look_nbits, SIZEOF(dtbl^.look_nbits));
+
+  p := 0;
+  for l := 1 to HUFF_LOOKAHEAD do
+  begin
+    for i := 1 to int (htbl^.bits[l]) do
+    begin
+      { l := current code's length, p := its index in huffcode[] & huffval[]. }
+      { Generate left-justified code followed by all possible bit sequences }
+      lookbits := huffcode[p] shl (HUFF_LOOKAHEAD-l);
+      for ctr := pred(1 shl (HUFF_LOOKAHEAD-l)) downto 0 do
+      begin
+  dtbl^.look_nbits[lookbits] := l;
+  dtbl^.look_sym[lookbits] := htbl^.huffval[p];
+  Inc(lookbits);
+      end;
+      Inc(p);
+    end;
+  end;
+
+  { Validate symbols as being reasonable.
+    For AC tables, we make no check, but accept all byte values 0..255.
+    For DC tables, we require the symbols to be in range 0..15.
+    (Tighter bounds could be applied depending on the data depth and mode,
+    but this is sufficient to ensure safe decoding.) }
+
+  if (isDC) then
+  begin
+    for i := 0 to pred(numsymbols) do
+    begin
+      sym := htbl^.huffval[i];
+      if (sym < 0) or (sym > 15) then
+  ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+    end;
+  end;
+end;
+
+
+{ Out-of-line code for bit fetching (shared with jdphuff.c).
+  See jdhuff.h for info about usage.
+  Note: current values of get_buffer and bits_left are passed as parameters,
+  but are returned in the corresponding fields of the state struct.
+
+  On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
+  of get_buffer to be used.  (On machines with wider words, an even larger
+  buffer could be used.)  However, on some machines 32-bit shifts are
+  quite slow and take time proportional to the number of places shifted.
+  (This is true with most PC compilers, for instance.)  In this case it may
+  be a win to set MIN_GET_BITS to the minimum value of 15.  This reduces the
+  average shift distance at the cost of more calls to jpeg_fill_bit_buffer. }
+
+{$ifdef SLOW_SHIFT_32}
+const
+  MIN_GET_BITS = 15;  { minimum allowable value }
+{$else}
+const
+  MIN_GET_BITS = (BIT_BUF_SIZE-7);
+{$endif}
+
+
+{GLOBAL}
+function jpeg_fill_bit_buffer (var state : bitread_working_state;
+                  {register} get_buffer : bit_buf_type;
+                              {register} bits_left : int;
+                  nbits  : int) : boolean;
+label
+  no_more_bytes;
+{ Load up the bit buffer to a depth of at least nbits }
+var
+  { Copy heavily used state fields into locals (hopefully registers) }
+  {register} next_input_byte : {const} JOCTETptr;
+  {register} bytes_in_buffer : size_t;
+var
+  {register} c : int;
+var
+  cinfo : j_decompress_ptr;
+begin
+  next_input_byte := state.next_input_byte;
+  bytes_in_buffer := state.bytes_in_buffer;
+  cinfo := state.cinfo;
+
+  { Attempt to load at least MIN_GET_BITS bits into get_buffer. }
+  { (It is assumed that no request will be for more than that many bits.) }
+  { We fail to do so only if we hit a marker or are forced to suspend. }
+
+  if (cinfo^.unread_marker = 0) then  { cannot advance past a marker }
+  begin
+    while (bits_left < MIN_GET_BITS) do
+    begin
+      { Attempt to read a byte }
+      if (bytes_in_buffer = 0) then
+      begin
+  if not cinfo^.src^.fill_input_buffer(cinfo) then
+        begin
+    jpeg_fill_bit_buffer := FALSE;
+          exit;
+        end;
+  next_input_byte := cinfo^.src^.next_input_byte;
+  bytes_in_buffer := cinfo^.src^.bytes_in_buffer;
+      end;
+      Dec(bytes_in_buffer);
+      c := GETJOCTET(next_input_byte^);
+      Inc(next_input_byte);
+
+
+      { If it's $FF, check and discard stuffed zero byte }
+      if (c = $FF) then
+      begin
+        { Loop here to discard any padding FF's on terminating marker,
+    so that we can save a valid unread_marker value.  NOTE: we will
+    accept multiple FF's followed by a 0 as meaning a single FF data
+    byte.  This data pattern is not valid according to the standard. }
+
+        repeat
+    if (bytes_in_buffer = 0) then
+          begin
+      if (not state.cinfo^.src^.fill_input_buffer (state.cinfo)) then
+            begin
+        jpeg_fill_bit_buffer := FALSE;
+              exit;
+            end;
+      next_input_byte := state.cinfo^.src^.next_input_byte;
+      bytes_in_buffer := state.cinfo^.src^.bytes_in_buffer;
+    end;
+    Dec(bytes_in_buffer);
+    c := GETJOCTET(next_input_byte^);
+          Inc(next_input_byte);
+        Until (c <> $FF);
+
+        if (c = 0) then
+        begin
+    { Found FF/00, which represents an FF data byte }
+    c := $FF;
+        end
+        else
+        begin
+    { Oops, it's actually a marker indicating end of compressed data.
+            Save the marker code for later use.
+      Fine point: it might appear that we should save the marker into
+      bitread working state, not straight into permanent state.  But
+      once we have hit a marker, we cannot need to suspend within the
+      current MCU, because we will read no more bytes from the data
+      source.  So it is OK to update permanent state right away. }
+
+    cinfo^.unread_marker := c;
+          { See if we need to insert some fake zero bits. }
+    goto no_more_bytes;
+  end;
+      end;
+
+      { OK, load c into get_buffer }
+      get_buffer := (get_buffer shl 8) or c;
+      Inc(bits_left, 8);
+    end { end while }
+  end
+  else
+  begin
+  no_more_bytes:
+    { We get here if we've read the marker that terminates the compressed
+      data segment.  There should be enough bits in the buffer register
+      to satisfy the request; if so, no problem. }
+
+    if (nbits > bits_left) then
+    begin
+      { Uh-oh.  Report corrupted data to user and stuff zeroes into
+        the data stream, so that we can produce some kind of image.
+        We use a nonvolatile flag to ensure that only one warning message
+        appears per data segment. }
+
+      if not cinfo^.entropy^.insufficient_data then
+      begin
+  WARNMS(j_common_ptr(cinfo), JWRN_HIT_MARKER);
+  cinfo^.entropy^.insufficient_data := TRUE;
+      end;
+      { Fill the buffer with zero bits }
+      get_buffer := get_buffer shl (MIN_GET_BITS - bits_left);
+      bits_left := MIN_GET_BITS;
+    end;
+  end;
+
+  { Unload the local registers }
+  state.next_input_byte := next_input_byte;
+  state.bytes_in_buffer := bytes_in_buffer;
+  state.get_buffer := get_buffer;
+  state.bits_left := bits_left;
+
+  jpeg_fill_bit_buffer := TRUE;
+end;
+
+
+{ Out-of-line code for Huffman code decoding.
+  See jdhuff.h for info about usage. }
+
+{GLOBAL}
+function jpeg_huff_decode (var state : bitread_working_state;
+              {register} get_buffer : bit_buf_type;
+                          {register} bits_left : int;
+              htbl : d_derived_tbl_ptr;
+                          min_bits : int) : int;
+var
+  {register} l : int;
+  {register} code : INT32;
+begin
+  l := min_bits;
+
+  { HUFF_DECODE has determined that the code is at least min_bits }
+  { bits long, so fetch that many bits in one swoop. }
+
+  {CHECK_BIT_BUFFER(state, l, return -1);}
+  if (bits_left < l) then
+  begin
+    if (not jpeg_fill_bit_buffer(state, get_buffer, bits_left, l)) then
+    begin
+      jpeg_huff_decode := -1;
+      exit;
+    end;
+    get_buffer := state.get_buffer;
+    bits_left := state.bits_left;
+  end;
+
+  {code := GET_BITS(l);}
+  Dec(bits_left, l);
+  code := (int(get_buffer shr bits_left)) and ( pred(1 shl l) );
+
+  { Collect the rest of the Huffman code one bit at a time. }
+  { This is per Figure F.16 in the JPEG spec. }
+
+  while (code > htbl^.maxcode[l]) do
+  begin
+    code := code shl 1;
+    {CHECK_BIT_BUFFER(state, 1, return -1);}
+    if (bits_left < 1) then
+    begin
+      if (not jpeg_fill_bit_buffer(state, get_buffer, bits_left, 1)) then
+      begin
+        jpeg_huff_decode := -1;
+        exit;
+      end;
+      get_buffer := state.get_buffer;
+      bits_left := state.bits_left;
+    end;
+
+    {code := code or GET_BITS(1);}
+    Dec(bits_left);
+    code := code or ( (int(get_buffer shr bits_left)) and pred(1 shl 1) );
+
+    Inc(l);
+  end;
+
+  { Unload the local registers }
+  state.get_buffer := get_buffer;
+  state.bits_left := bits_left;
+
+  { With garbage input we may reach the sentinel value l := 17. }
+
+  if (l > 16) then
+  begin
+    WARNMS(j_common_ptr(state.cinfo), JWRN_HUFF_BAD_CODE);
+    jpeg_huff_decode := 0;  { fake a zero as the safest result }
+    exit;
+  end;
+
+  jpeg_huff_decode := htbl^.pub^.huffval[ int (code + htbl^.valoffset[l]) ];
+end;
+
+
+{ Figure F.12: extend sign bit.
+  On some machines, a shift and add will be faster than a table lookup. }
+
+{$ifdef AVOID_TABLES}
+
+#define HUFF_EXTEND(x,s)  ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
+
+{$else}
+
+{$define HUFF_EXTEND(x,s)
+  if (x < extend_test[s]) then
+    := x + extend_offset[s]
+  else
+   x;}
+
+const
+  extend_test : array[0..16-1] of int =   { entry n is 2**(n-1) }
+  ($0000, $0001, $0002, $0004, $0008, $0010, $0020, $0040,
+   $0080, $0100, $0200, $0400, $0800, $1000, $2000, $4000);
+
+const
+  extend_offset : array[0..16-1] of int = { entry n is (-1 << n) + 1 }
+(0, ((-1) shl 1) + 1, ((-1) shl 2) + 1, ((-1) shl 3) + 1, ((-1) shl 4) + 1,
+    ((-1) shl 5) + 1, ((-1) shl 6) + 1, ((-1) shl 7) + 1, ((-1) shl 8) + 1,
+    ((-1) shl 9) + 1, ((-1) shl 10) + 1, ((-1) shl 11) + 1,((-1) shl 12) + 1,
+   ((-1) shl 13) + 1, ((-1) shl 14) + 1, ((-1) shl 15) + 1);
+
+{$endif} { AVOID_TABLES }
+
+
+{ Check for a restart marker & resynchronize decoder.
+  Returns FALSE if must suspend. }
+
+{LOCAL}
+function process_restart (cinfo : j_decompress_ptr) : boolean;
+var
+  entropy : huff_entropy_ptr;
+  ci : int;
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+
+  { Throw away any unused bits remaining in bit buffer; }
+  { include any full bytes in next_marker's count of discarded bytes }
+  Inc(cinfo^.marker^.discarded_bytes, entropy^.bitstate.bits_left div 8);
+  entropy^.bitstate.bits_left := 0;
+
+  { Advance past the RSTn marker }
+  if (not cinfo^.marker^.read_restart_marker (cinfo)) then
+  begin
+    process_restart := FALSE;
+    exit;
+  end;
+
+  { Re-initialize DC predictions to 0 }
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+    entropy^.saved.last_dc_val[ci] := 0;
+
+  { Reset restart counter }
+  entropy^.restarts_to_go := cinfo^.restart_interval;
+
+  { Reset out-of-data flag, unless read_restart_marker left us smack up
+    against a marker.  In that case we will end up treating the next data
+    segment as empty, and we can avoid producing bogus output pixels by
+    leaving the flag set. }
+
+  if (cinfo^.unread_marker = 0) then
+    entropy^.pub.insufficient_data := FALSE;
+
+  process_restart := TRUE;
+end;
+
+
+{ Decode and return one MCU's worth of Huffman-compressed coefficients.
+  The coefficients are reordered from zigzag order into natural array order,
+  but are not dequantized.
+
+  The i'th block of the MCU is stored into the block pointed to by
+  MCU_data[i].  WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER.
+  (Wholesale zeroing is usually a little faster than retail...)
+
+  Returns FALSE if data source requested suspension.  In that case no
+  changes have been made to permanent state.  (Exception: some output
+  coefficients may already have been assigned.  This is harmless for
+  this module, since we'll just re-assign them on the next call.) }
+
+{METHODDEF}
+function decode_mcu (cinfo : j_decompress_ptr;
+                     var MCU_data : array of JBLOCKROW) : boolean;
+label
+  label1, label2, label3;
+var
+  entropy : huff_entropy_ptr;
+  {register} s, k, r : int;
+  blkn, ci : int;
+  block : JBLOCK_PTR;
+  {BITREAD_STATE_VARS}
+  get_buffer : bit_buf_type ; {register}
+  bits_left : int; {register}
+  br_state : bitread_working_state;
+
+  state : savable_state;
+  dctbl : d_derived_tbl_ptr;
+  actbl : d_derived_tbl_ptr;
+var
+  nb, look : int; {register}
+begin
+  entropy := huff_entropy_ptr (cinfo^.entropy);
+
+  { Process restart marker if needed; may have to suspend }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+      if (not process_restart(cinfo)) then
+      begin
+        decode_mcu := FALSE;
+        exit;
+      end;
+  end;
+
+  { If we've run out of data, just leave the MCU set to zeroes.
+    This way, we return uniform gray for the remainder of the segment. }
+
+  if not entropy^.pub.insufficient_data then
+  begin
+
+    { Load up working state }
+    {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);}
+    br_state.cinfo := cinfo;
+    br_state.next_input_byte := cinfo^.src^.next_input_byte;
+    br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer;
+    get_buffer := entropy^.bitstate.get_buffer;
+    bits_left := entropy^.bitstate.bits_left;
+
+    {ASSIGN_STATE(state, entropy^.saved);}
+    state := entropy^.saved;
+
+    { Outer loop handles each block in the MCU }
+
+    for blkn := 0 to pred(cinfo^.blocks_in_MCU) do
+    begin
+      block := JBLOCK_PTR(MCU_data[blkn]);
+      dctbl := entropy^.dc_cur_tbls[blkn];
+      actbl := entropy^.ac_cur_tbls[blkn];
+
+      { Decode a single block's worth of coefficients }
+
+      { Section F.2.2.1: decode the DC coefficient difference }
+      {HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);}
+      if (bits_left < HUFF_LOOKAHEAD) then
+      begin
+        if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then
+        begin
+          decode_mcu := False;
+          exit;
+        end;
+        get_buffer := br_state.get_buffer;
+        bits_left := br_state.bits_left;
+        if (bits_left < HUFF_LOOKAHEAD) then
+        begin
+          nb := 1;
+          goto label1;
+        end;
+      end;
+      {look := PEEK_BITS(HUFF_LOOKAHEAD);}
+      look := int(get_buffer shr (bits_left -  HUFF_LOOKAHEAD)) and
+                   pred(1 shl HUFF_LOOKAHEAD);
+
+      nb := dctbl^.look_nbits[look];
+      if (nb <> 0) then
+      begin
+        {DROP_BITS(nb);}
+        Dec(bits_left, nb);
+
+        s := dctbl^.look_sym[look];
+      end
+      else
+      begin
+        nb := HUFF_LOOKAHEAD+1;
+    label1:
+        s := jpeg_huff_decode(br_state,get_buffer,bits_left,dctbl,nb);
+        if (s < 0) then
+        begin
+          decode_mcu := FALSE;
+          exit;
+        end;
+        get_buffer := br_state.get_buffer;
+        bits_left := br_state.bits_left;
+      end;
+
+      if (s <> 0) then
+      begin
+        {CHECK_BIT_BUFFER(br_state, s, return FALSE);}
+        if (bits_left < s) then
+        begin
+          if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then
+          begin
+            decode_mcu := FALSE;
+            exit;
+          end;
+          get_buffer := br_state.get_buffer;
+          bits_left := br_state.bits_left;
+        end;
+
+        {r := GET_BITS(s);}
+        Dec(bits_left, s);
+        r := ( int(get_buffer shr bits_left)) and ( pred(1 shl s) );
+
+        {s := HUFF_EXTEND(r, s);}
+        if (r < extend_test[s]) then
+          s := r + extend_offset[s]
+        else
+          s := r;
+      end;
+
+      if (entropy^.dc_needed[blkn]) then
+      begin
+  { Convert DC difference to actual value, update last_dc_val }
+        ci := cinfo^.MCU_membership[blkn];
+  Inc(s, state.last_dc_val[ci]);
+        state.last_dc_val[ci] := s;
+        { Output the DC coefficient (assumes jpeg_natural_order[0] := 0) }
+        block^[0] := JCOEF (s);
+      end;
+
+      if (entropy^.ac_needed[blkn]) then
+      begin
+
+  { Section F.2.2.2: decode the AC coefficients }
+  { Since zeroes are skipped, output area must be cleared beforehand }
+  k := 1;
+        while (k < DCTSIZE2) do         { Nomssi: k is incr. in the loop }
+        begin
+          {HUFF_DECODE(s, br_state, actbl, return FALSE, label2);}
+          if (bits_left < HUFF_LOOKAHEAD) then
+          begin
+            if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then
+            begin
+              decode_mcu := False;
+              exit;
+            end;
+            get_buffer := br_state.get_buffer;
+            bits_left := br_state.bits_left;
+            if (bits_left < HUFF_LOOKAHEAD) then
+            begin
+              nb := 1;
+              goto label2;
+            end;
+          end;
+          {look := PEEK_BITS(HUFF_LOOKAHEAD);}
+          look := int(get_buffer shr (bits_left -  HUFF_LOOKAHEAD)) and
+                       pred(1 shl HUFF_LOOKAHEAD);
+
+          nb := actbl^.look_nbits[look];
+          if (nb <> 0) then
+          begin
+            {DROP_BITS(nb);}
+            Dec(bits_left, nb);
+
+            s := actbl^.look_sym[look];
+          end
+          else
+          begin
+            nb := HUFF_LOOKAHEAD+1;
+        label2:
+            s := jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb);
+            if (s < 0) then
+            begin
+              decode_mcu := FALSE;
+              exit;
+            end;
+            get_buffer := br_state.get_buffer;
+            bits_left := br_state.bits_left;
+          end;
+
+    r := s shr 4;
+    s := s and 15;
+
+          if (s <> 0) then
+          begin
+            Inc(k, r);
+            {CHECK_BIT_BUFFER(br_state, s, return FALSE);}
+            if (bits_left < s) then
+            begin
+              if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then
+              begin
+                decode_mcu := FALSE;
+                exit;
+              end;
+              get_buffer := br_state.get_buffer;
+              bits_left := br_state.bits_left;
+            end;
+
+            {r := GET_BITS(s);}
+            Dec(bits_left, s);
+            r := (int(get_buffer shr bits_left)) and ( pred(1 shl s) );
+
+            {s := HUFF_EXTEND(r, s);}
+            if (r < extend_test[s]) then
+              s := r + extend_offset[s]
+            else
+              s := r;
+            { Output coefficient in natural (dezigzagged) order.
+              Note: the extra entries in jpeg_natural_order[] will save us
+              if k >= DCTSIZE2, which could happen if the data is corrupted. }
+
+            block^[jpeg_natural_order[k]] := JCOEF (s);
+          end
+          else
+          begin
+            if (r <> 15) then
+              break;
+            Inc(k, 15);
+          end;
+          Inc(k);
+        end;
+      end
+      else
+      begin
+
+        { Section F.2.2.2: decode the AC coefficients }
+        { In this path we just discard the values }
+        k := 1;
+        while (k < DCTSIZE2) do
+        begin
+    {HUFF_DECODE(s, br_state, actbl, return FALSE, label3);}
+          if (bits_left < HUFF_LOOKAHEAD) then
+          begin
+            if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then
+            begin
+              decode_mcu := False;
+              exit;
+            end;
+            get_buffer := br_state.get_buffer;
+            bits_left := br_state.bits_left;
+            if (bits_left < HUFF_LOOKAHEAD) then
+            begin
+              nb := 1;
+              goto label3;
+            end;
+          end;
+          {look := PEEK_BITS(HUFF_LOOKAHEAD);}
+          look := int(get_buffer shr (bits_left -  HUFF_LOOKAHEAD)) and
+                       pred(1 shl HUFF_LOOKAHEAD);
+
+          nb := actbl^.look_nbits[look];
+          if (nb <> 0) then
+          begin
+            {DROP_BITS(nb);}
+      Dec(bits_left, nb);
+
+            s := actbl^.look_sym[look];
+          end
+          else
+          begin
+            nb := HUFF_LOOKAHEAD+1;
+        label3:
+            s := jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb);
+            if (s < 0) then
+            begin
+              decode_mcu := FALSE;
+              exit;
+            end;
+            get_buffer := br_state.get_buffer;
+            bits_left := br_state.bits_left;
+          end;
+
+    r := s shr 4;
+    s := s and 15;
+
+    if (s <> 0) then
+          begin
+      Inc(k, r);
+      {CHECK_BIT_BUFFER(br_state, s, return FALSE);}
+            if (bits_left < s) then
+            begin
+              if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then
+              begin
+                decode_mcu := FALSE;
+                exit;
+              end;
+              get_buffer := br_state.get_buffer;
+              bits_left := br_state.bits_left;
+            end;
+
+      {DROP_BITS(s);}
+            Dec(bits_left, s);
+    end
+          else
+          begin
+      if (r <> 15) then
+        break;
+      Inc(k, 15);
+    end;
+          Inc(k);
+        end;
+
+      end;
+    end;
+
+    { Completed MCU, so update state }
+    {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);}
+    cinfo^.src^.next_input_byte := br_state.next_input_byte;
+    cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer;
+    entropy^.bitstate.get_buffer := get_buffer;
+    entropy^.bitstate.bits_left := bits_left;
+
+    {ASSIGN_STATE(entropy^.saved, state);}
+    entropy^.saved := state;
+
+  end;
+
+  { Account for restart interval (no-op if not using restarts) }
+  Dec(entropy^.restarts_to_go);
+
+  decode_mcu := TRUE;
+end;
+
+
+{ Module initialization routine for Huffman entropy decoding. }
+
+{GLOBAL}
+procedure jinit_huff_decoder (cinfo : j_decompress_ptr);
+var
+  entropy : huff_entropy_ptr;
+  i : int;
+begin
+  entropy := huff_entropy_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(huff_entropy_decoder)) );
+  cinfo^.entropy := jpeg_entropy_decoder_ptr (entropy);
+  entropy^.pub.start_pass := start_pass_huff_decoder;
+  entropy^.pub.decode_mcu := decode_mcu;
+
+  { Mark tables unallocated }
+  for i := 0 to pred(NUM_HUFF_TBLS) do
+  begin
+    entropy^.dc_derived_tbls[i] := NIL;
+    entropy^.ac_derived_tbls[i] := NIL;
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdinput.pas b/src/lib/vampimg/JpegLib/imjdinput.pas
new file mode 100644 (file)
index 0000000..98347d2
--- /dev/null
@@ -0,0 +1,416 @@
+unit imjdinput;
+
+{ Original: jdinput.c ; Copyright (C) 1991-1997, Thomas G. Lane. }
+
+{ This file is part of the Independent JPEG Group's software.
+  For conditions of distribution and use, see the accompanying README file.
+
+  This file contains input control logic for the JPEG decompressor.
+  These routines are concerned with controlling the decompressor's input
+  processing (marker reading and coefficient decoding).  The actual input
+  reading is done in jdmarker.c, jdhuff.c, and jdphuff.c. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjpeglib,
+  imjdeferr,
+  imjerror,
+  imjinclude, imjutils;
+
+{ Initialize the input controller module.
+  This is called only once, when the decompression object is created. }
+
+{GLOBAL}
+procedure jinit_input_controller (cinfo : j_decompress_ptr);
+
+implementation
+
+{ Private state }
+
+type
+  my_inputctl_ptr = ^my_input_controller;
+  my_input_controller = record
+    pub : jpeg_input_controller; { public fields }
+
+    inheaders : boolean;    { TRUE until first SOS is reached }
+  end; {my_input_controller;}
+
+
+
+{ Forward declarations }
+{METHODDEF}
+function consume_markers (cinfo : j_decompress_ptr) : int; forward;
+
+
+{ Routines to calculate various quantities related to the size of the image. }
+
+{LOCAL}
+procedure initial_setup (cinfo : j_decompress_ptr);
+{ Called once, when first SOS marker is reached }
+var
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  { Make sure image isn't bigger than I can handle }
+  if (long(cinfo^.image_height) > long (JPEG_MAX_DIMENSION)) or
+     (long(cinfo^.image_width) > long(JPEG_MAX_DIMENSION)) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_IMAGE_TOO_BIG, uInt(JPEG_MAX_DIMENSION));
+
+  { For now, precision must match compiled-in value... }
+  if (cinfo^.data_precision <> BITS_IN_JSAMPLE) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PRECISION, cinfo^.data_precision);
+
+  { Check that number of components won't exceed internal array sizes }
+  if (cinfo^.num_components > MAX_COMPONENTS) then
+    ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.num_components,
+       MAX_COMPONENTS);
+
+  { Compute maximum sampling factors; check factor validity }
+  cinfo^.max_h_samp_factor := 1;
+  cinfo^.max_v_samp_factor := 1;
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    if (compptr^.h_samp_factor<=0) or (compptr^.h_samp_factor>MAX_SAMP_FACTOR) or
+       (compptr^.v_samp_factor<=0) or (compptr^.v_samp_factor>MAX_SAMP_FACTOR) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_SAMPLING);
+    {cinfo^.max_h_samp_factor := MAX(cinfo^.max_h_samp_factor,
+           compptr^.h_samp_factor);
+    cinfo^.max_v_samp_factor := MAX(cinfo^.max_v_samp_factor,
+           compptr^.v_samp_factor);}
+    if cinfo^.max_h_samp_factor < compptr^.h_samp_factor then
+      cinfo^.max_h_samp_factor := compptr^.h_samp_factor;
+    if cinfo^.max_v_samp_factor < compptr^.v_samp_factor then
+      cinfo^.max_v_samp_factor := compptr^.v_samp_factor;
+    Inc(compptr);
+  end;
+
+  { We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
+    In the full decompressor, this will be overridden by jdmaster.c;
+    but in the transcoder, jdmaster.c is not used, so we must do it here. }
+
+  cinfo^.min_DCT_scaled_size := DCTSIZE;
+
+  { Compute dimensions of components }
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    compptr^.DCT_scaled_size := DCTSIZE;
+    { Size in DCT blocks }
+    compptr^.width_in_blocks := JDIMENSION(
+      jdiv_round_up( long(cinfo^.image_width) * long(compptr^.h_samp_factor),
+         long(cinfo^.max_h_samp_factor * DCTSIZE)) );
+    compptr^.height_in_blocks := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_height) * long(compptr^.v_samp_factor),
+        long (cinfo^.max_v_samp_factor * DCTSIZE)) );
+    { downsampled_width and downsampled_height will also be overridden by
+      jdmaster.c if we are doing full decompression.  The transcoder library
+      doesn't use these values, but the calling application might. }
+
+    { Size in samples }
+    compptr^.downsampled_width := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_width) * long(compptr^.h_samp_factor),
+        long (cinfo^.max_h_samp_factor)) );
+    compptr^.downsampled_height := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_height) * long(compptr^.v_samp_factor),
+        long (cinfo^.max_v_samp_factor)) );
+    { Mark component needed, until color conversion says otherwise }
+    compptr^.component_needed := TRUE;
+    { Mark no quantization table yet saved for component }
+    compptr^.quant_table := NIL;
+    Inc(compptr);
+  end;
+
+  { Compute number of fully interleaved MCU rows. }
+  cinfo^.total_iMCU_rows := JDIMENSION(
+    jdiv_round_up(long(cinfo^.image_height),
+      long(cinfo^.max_v_samp_factor*DCTSIZE)) );
+
+  { Decide whether file contains multiple scans }
+  if (cinfo^.comps_in_scan < cinfo^.num_components) or
+     (cinfo^.progressive_mode) then
+    cinfo^.inputctl^.has_multiple_scans := TRUE
+  else
+    cinfo^.inputctl^.has_multiple_scans := FALSE;
+end;
+
+
+{LOCAL}
+procedure per_scan_setup (cinfo : j_decompress_ptr);
+{ Do computations that are needed before processing a JPEG scan }
+{ cinfo^.comps_in_scan and cinfo^.cur_comp_info[] were set from SOS marker }
+var
+  ci, mcublks, tmp : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  if (cinfo^.comps_in_scan = 1) then
+  begin
+    { Noninterleaved (single-component) scan }
+    compptr := cinfo^.cur_comp_info[0];
+
+    { Overall image size in MCUs }
+    cinfo^.MCUs_per_row := compptr^.width_in_blocks;
+    cinfo^.MCU_rows_in_scan := compptr^.height_in_blocks;
+
+    { For noninterleaved scan, always one block per MCU }
+    compptr^.MCU_width := 1;
+    compptr^.MCU_height := 1;
+    compptr^.MCU_blocks := 1;
+    compptr^.MCU_sample_width := compptr^.DCT_scaled_size;
+    compptr^.last_col_width := 1;
+    { For noninterleaved scans, it is convenient to define last_row_height
+      as the number of block rows present in the last iMCU row. }
+
+    tmp := int (LongInt(compptr^.height_in_blocks) mod compptr^.v_samp_factor);
+    if (tmp = 0) then
+      tmp := compptr^.v_samp_factor;
+    compptr^.last_row_height := tmp;
+
+    { Prepare array describing MCU composition }
+    cinfo^.blocks_in_MCU := 1;
+    cinfo^.MCU_membership[0] := 0;
+
+  end
+  else
+  begin
+
+    { Interleaved (multi-component) scan }
+    if (cinfo^.comps_in_scan <= 0) or (cinfo^.comps_in_scan > MAX_COMPS_IN_SCAN) then
+      ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.comps_in_scan,
+         MAX_COMPS_IN_SCAN);
+
+    { Overall image size in MCUs }
+    cinfo^.MCUs_per_row := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_width),
+        long (cinfo^.max_h_samp_factor*DCTSIZE)) );
+    cinfo^.MCU_rows_in_scan := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_height),
+        long (cinfo^.max_v_samp_factor*DCTSIZE)) );
+
+    cinfo^.blocks_in_MCU := 0;
+
+    for ci := 0 to pred(cinfo^.comps_in_scan) do
+    begin
+      compptr := cinfo^.cur_comp_info[ci];
+      { Sampling factors give # of blocks of component in each MCU }
+      compptr^.MCU_width := compptr^.h_samp_factor;
+      compptr^.MCU_height := compptr^.v_samp_factor;
+      compptr^.MCU_blocks := compptr^.MCU_width * compptr^.MCU_height;
+      compptr^.MCU_sample_width := compptr^.MCU_width * compptr^.DCT_scaled_size;
+      { Figure number of non-dummy blocks in last MCU column & row }
+      tmp := int (LongInt(compptr^.width_in_blocks) mod compptr^.MCU_width);
+      if (tmp = 0) then
+        tmp := compptr^.MCU_width;
+      compptr^.last_col_width := tmp;
+      tmp := int (LongInt(compptr^.height_in_blocks) mod compptr^.MCU_height);
+      if (tmp = 0) then
+        tmp := compptr^.MCU_height;
+      compptr^.last_row_height := tmp;
+      { Prepare array describing MCU composition }
+      mcublks := compptr^.MCU_blocks;
+      if (LongInt(cinfo^.blocks_in_MCU) + mcublks > D_MAX_BLOCKS_IN_MCU) then
+  ERREXIT(j_common_ptr(cinfo), JERR_BAD_MCU_SIZE);
+      while (mcublks > 0) do
+      begin
+        Dec(mcublks);
+  cinfo^.MCU_membership[cinfo^.blocks_in_MCU] := ci;
+        Inc(cinfo^.blocks_in_MCU);
+      end;
+    end;
+
+  end;
+end;
+
+
+{ Save away a copy of the Q-table referenced by each component present
+  in the current scan, unless already saved during a prior scan.
+
+  In a multiple-scan JPEG file, the encoder could assign different components
+  the same Q-table slot number, but change table definitions between scans
+  so that each component uses a different Q-table.  (The IJG encoder is not
+  currently capable of doing this, but other encoders might.)  Since we want
+  to be able to dequantize all the components at the end of the file, this
+  means that we have to save away the table actually used for each component.
+  We do this by copying the table at the start of the first scan containing
+  the component.
+  The JPEG spec prohibits the encoder from changing the contents of a Q-table
+  slot between scans of a component using that slot.  If the encoder does so
+  anyway, this decoder will simply use the Q-table values that were current
+  at the start of the first scan for the component.
+
+  The decompressor output side looks only at the saved quant tables,
+  not at the current Q-table slots. }
+
+{LOCAL}
+procedure latch_quant_tables (cinfo : j_decompress_ptr);
+var
+  ci, qtblno : int;
+  compptr : jpeg_component_info_ptr;
+  qtbl : JQUANT_TBL_PTR;
+begin
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    { No work if we already saved Q-table for this component }
+    if (compptr^.quant_table <> NIL) then
+      continue;
+    { Make sure specified quantization table is present }
+    qtblno := compptr^.quant_tbl_no;
+    if (qtblno < 0) or (qtblno >= NUM_QUANT_TBLS) or
+       (cinfo^.quant_tbl_ptrs[qtblno] = NIL) then
+      ERREXIT1(j_common_ptr(cinfo), JERR_NO_QUANT_TABLE, qtblno);
+    { OK, save away the quantization table }
+    qtbl := JQUANT_TBL_PTR(
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          SIZEOF(JQUANT_TBL)) );
+    MEMCOPY(qtbl, cinfo^.quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
+    compptr^.quant_table := qtbl;
+  end;
+end;
+
+
+{ Initialize the input modules to read a scan of compressed data.
+  The first call to this is done by jdmaster.c after initializing
+  the entire decompressor (during jpeg_start_decompress).
+  Subsequent calls come from consume_markers, below. }
+
+{METHODDEF}
+procedure start_input_pass (cinfo : j_decompress_ptr);
+begin
+  per_scan_setup(cinfo);
+  latch_quant_tables(cinfo);
+  cinfo^.entropy^.start_pass (cinfo);
+  cinfo^.coef^.start_input_pass (cinfo);
+  cinfo^.inputctl^.consume_input := cinfo^.coef^.consume_data;
+end;
+
+
+{ Finish up after inputting a compressed-data scan.
+  This is called by the coefficient controller after it's read all
+  the expected data of the scan. }
+
+{METHODDEF}
+procedure finish_input_pass (cinfo : j_decompress_ptr);
+begin
+  cinfo^.inputctl^.consume_input := consume_markers;
+end;
+
+
+{ Read JPEG markers before, between, or after compressed-data scans.
+  Change state as necessary when a new scan is reached.
+  Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+
+  The consume_input method pointer points either here or to the
+  coefficient controller's consume_data routine, depending on whether
+  we are reading a compressed data segment or inter-segment markers. }
+
+{METHODDEF}
+function consume_markers (cinfo : j_decompress_ptr) : int;
+var
+  val : int;
+  inputctl : my_inputctl_ptr;
+begin
+  inputctl := my_inputctl_ptr (cinfo^.inputctl);
+
+  if (inputctl^.pub.eoi_reached) then { After hitting EOI, read no further }
+  begin
+    consume_markers := JPEG_REACHED_EOI;
+    exit;
+  end;
+
+  val := cinfo^.marker^.read_markers (cinfo);
+
+  case (val) of
+  JPEG_REACHED_SOS: { Found SOS }
+    begin
+      if (inputctl^.inheaders) then
+      begin { 1st SOS }
+        initial_setup(cinfo);
+        inputctl^.inheaders := FALSE;
+        { Note: start_input_pass must be called by jdmaster.c
+          before any more input can be consumed.  jdapimin.c is
+          responsible for enforcing this sequencing. }
+      end
+      else
+      begin     { 2nd or later SOS marker }
+        if (not inputctl^.pub.has_multiple_scans) then
+    ERREXIT(j_common_ptr(cinfo), JERR_EOI_EXPECTED); { Oops, I wasn't expecting this! }
+        start_input_pass(cinfo);
+      end;
+    end;
+  JPEG_REACHED_EOI: { Found EOI }
+    begin
+      inputctl^.pub.eoi_reached := TRUE;
+      if (inputctl^.inheaders) then
+      begin { Tables-only datastream, apparently }
+        if (cinfo^.marker^.saw_SOF) then
+    ERREXIT(j_common_ptr(cinfo), JERR_SOF_NO_SOS);
+      end
+      else
+      begin
+        { Prevent infinite loop in coef ctlr's decompress_data routine
+          if user set output_scan_number larger than number of scans. }
+
+        if (cinfo^.output_scan_number > cinfo^.input_scan_number) then
+    cinfo^.output_scan_number := cinfo^.input_scan_number;
+      end;
+    end;
+  JPEG_SUSPENDED:;
+  end;
+
+  consume_markers := val;
+end;
+
+
+{ Reset state to begin a fresh datastream. }
+
+{METHODDEF}
+procedure reset_input_controller (cinfo : j_decompress_ptr);
+var
+  inputctl : my_inputctl_ptr;
+begin
+  inputctl := my_inputctl_ptr (cinfo^.inputctl);
+
+  inputctl^.pub.consume_input := consume_markers;
+  inputctl^.pub.has_multiple_scans := FALSE; { "unknown" would be better }
+  inputctl^.pub.eoi_reached := FALSE;
+  inputctl^.inheaders := TRUE;
+  { Reset other modules }
+  cinfo^.err^.reset_error_mgr (j_common_ptr(cinfo));
+  cinfo^.marker^.reset_marker_reader (cinfo);
+  { Reset progression state -- would be cleaner if entropy decoder did this }
+  cinfo^.coef_bits := NIL;
+end;
+
+
+{ Initialize the input controller module.
+  This is called only once, when the decompression object is created. }
+
+{GLOBAL}
+procedure jinit_input_controller (cinfo : j_decompress_ptr);
+var
+  inputctl : my_inputctl_ptr;
+begin
+  { Create subobject in permanent pool }
+  inputctl := my_inputctl_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT,
+        SIZEOF(my_input_controller)) );
+  cinfo^.inputctl := jpeg_input_controller_ptr(inputctl);
+  { Initialize method pointers }
+  inputctl^.pub.consume_input := consume_markers;
+  inputctl^.pub.reset_input_controller := reset_input_controller;
+  inputctl^.pub.start_input_pass := start_input_pass;
+  inputctl^.pub.finish_input_pass := finish_input_pass;
+  { Initialize state: can't use reset_input_controller since we don't
+    want to try to reset other modules yet. }
+
+  inputctl^.pub.has_multiple_scans := FALSE; { "unknown" would be better }
+  inputctl^.pub.eoi_reached := FALSE;
+  inputctl^.inheaders := TRUE;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdmainct.pas b/src/lib/vampimg/JpegLib/imjdmainct.pas
new file mode 100644 (file)
index 0000000..037f099
--- /dev/null
@@ -0,0 +1,610 @@
+unit imjdmainct;
+
+
+{ This file is part of the Independent JPEG Group's software.
+  For conditions of distribution and use, see the accompanying README file.
+
+  This file contains the main buffer controller for decompression.
+  The main buffer lies between the JPEG decompressor proper and the
+  post-processor; it holds downsampled data in the JPEG colorspace.
+
+  Note that this code is bypassed in raw-data mode, since the application
+  supplies the equivalent of the main buffer in that case. }
+
+{ Original: jdmainct.c ; Copyright (C) 1994-1996, Thomas G. Lane.  }
+
+
+{ In the current system design, the main buffer need never be a full-image
+  buffer; any full-height buffers will be found inside the coefficient or
+  postprocessing controllers.  Nonetheless, the main controller is not
+  trivial.  Its responsibility is to provide context rows for upsampling/
+  rescaling, and doing this in an efficient fashion is a bit tricky.
+
+  Postprocessor input data is counted in "row groups".  A row group
+  is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
+  sample rows of each component.  (We require DCT_scaled_size values to be
+  chosen such that these numbers are integers.  In practice DCT_scaled_size
+  values will likely be powers of two, so we actually have the stronger
+  condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
+  Upsampling will typically produce max_v_samp_factor pixel rows from each
+  row group (times any additional scale factor that the upsampler is
+  applying).
+
+  The coefficient controller will deliver data to us one iMCU row at a time;
+  each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
+  exactly min_DCT_scaled_size row groups.  (This amount of data corresponds
+  to one row of MCUs when the image is fully interleaved.)  Note that the
+  number of sample rows varies across components, but the number of row
+  groups does not.  Some garbage sample rows may be included in the last iMCU
+  row at the bottom of the image.
+
+  Depending on the vertical scaling algorithm used, the upsampler may need
+  access to the sample row(s) above and below its current input row group.
+  The upsampler is required to set need_context_rows TRUE at global
+  selection
+  time if so.  When need_context_rows is FALSE, this controller can simply
+  obtain one iMCU row at a time from the coefficient controller and dole it
+  out as row groups to the postprocessor.
+
+  When need_context_rows is TRUE, this controller guarantees that the buffer
+  passed to postprocessing contains at least one row group's worth of samples
+  above and below the row group(s) being processed.  Note that the context
+  rows "above" the first passed row group appear at negative row offsets in
+  the passed buffer.  At the top and bottom of the image, the required
+  context rows are manufactured by duplicating the first or last real sample
+  row; this avoids having special cases in the upsampling inner loops.
+
+  The amount of context is fixed at one row group just because that's a
+  convenient number for this controller to work with.  The existing
+  upsamplers really only need one sample row of context.  An upsampler
+  supporting arbitrary output rescaling might wish for more than one row
+  group of context when shrinking the image; tough, we don't handle that.
+  (This is justified by the assumption that downsizing will be handled mostly
+  by adjusting the DCT_scaled_size values, so that the actual scale factor at
+  the upsample step needn't be much less than one.)
+
+  To provide the desired context, we have to retain the last two row groups
+  of one iMCU row while reading in the next iMCU row.  (The last row group
+  can't be processed until we have another row group for its below-context,
+  and so we have to save the next-to-last group too for its above-context.)
+  We could do this most simply by copying data around in our buffer, but
+  that'd be very slow.  We can avoid copying any data by creating a rather
+  strange pointer structure.  Here's how it works.  We allocate a workspace
+  consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
+  of row groups per iMCU row).  We create two sets of redundant pointers to
+  the workspace.  Labeling the physical row groups 0 to M+1, the synthesized
+  pointer lists look like this:
+                    M+1                          M-1
+  master pointer --> 0         master pointer --> 0
+                     1                            1
+                    ...                          ...
+                    M-3                          M-3
+                    M-2                           M
+                    M-1                          M+1
+                     M                           M-2
+                    M+1                          M-1
+                     0                            0
+  We read alternate iMCU rows using each master pointer; thus the last two
+  row groups of the previous iMCU row remain un-overwritten in the workspace.
+  The pointer lists are set up so that the required context rows appear to
+  be adjacent to the proper places when we pass the pointer lists to the
+  upsampler.
+
+  The above pictures describe the normal state of the pointer lists.
+  At top and bottom of the image, we diddle the pointer lists to duplicate
+  the first or last sample row as necessary (this is cheaper than copying
+  sample rows around).
+
+  This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1.  In that
+  situation each iMCU row provides only one row group so the buffering logic
+  must be different (eg, we must read two iMCU rows before we can emit the
+  first row group).  For now, we simply do not support providing context
+  rows when min_DCT_scaled_size is 1.  That combination seems unlikely to
+  be worth providing --- if someone wants a 1/8th-size preview, they probably
+  want it quick and dirty, so a context-free upsampler is sufficient. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+{$ifdef QUANT_2PASS_SUPPORTED}
+  imjquant2,
+{$endif}
+  imjdeferr,
+  imjerror,
+  imjpeglib;
+
+
+{GLOBAL}
+procedure jinit_d_main_controller (cinfo : j_decompress_ptr;
+                                   need_full_buffer : boolean);
+
+
+implementation
+
+{ Private buffer controller object }
+
+type
+  my_main_ptr = ^my_main_controller;
+  my_main_controller = record
+    pub : jpeg_d_main_controller; { public fields }
+
+    { Pointer to allocated workspace (M or M+2 row groups). }
+    buffer : array[0..MAX_COMPONENTS-1] of JSAMPARRAY;
+
+    buffer_full : boolean;  { Have we gotten an iMCU row from decoder? }
+    rowgroup_ctr : JDIMENSION ; { counts row groups output to postprocessor }
+
+    { Remaining fields are only used in the context case. }
+
+    { These are the master pointers to the funny-order pointer lists. }
+    xbuffer : array[0..2-1] of JSAMPIMAGE;  { pointers to weird pointer lists }
+
+    whichptr : int;     { indicates which pointer set is now in use }
+    context_state : int;    { process_data state machine status }
+    rowgroups_avail : JDIMENSION; { row groups available to postprocessor }
+    iMCU_row_ctr : JDIMENSION;  { counts iMCU rows to detect image top/bot }
+  end; { my_main_controller; }
+
+
+{ context_state values: }
+const
+  CTX_PREPARE_FOR_IMCU  = 0;  { need to prepare for MCU row }
+  CTX_PROCESS_IMCU      = 1;  { feeding iMCU to postprocessor }
+  CTX_POSTPONED_ROW     = 2;  { feeding postponed row group }
+
+
+{ Forward declarations }
+{METHODDEF}
+procedure process_data_simple_main(cinfo : j_decompress_ptr;
+                                   output_buf : JSAMPARRAY;
+                             var out_row_ctr : JDIMENSION;
+                                   out_rows_avail : JDIMENSION); forward;
+{METHODDEF}
+procedure process_data_context_main (cinfo : j_decompress_ptr;
+                                     output_buf : JSAMPARRAY;
+                               var out_row_ctr : JDIMENSION;
+                                     out_rows_avail : JDIMENSION); forward;
+
+{$ifdef QUANT_2PASS_SUPPORTED}
+{METHODDEF}
+procedure process_data_crank_post (cinfo : j_decompress_ptr;
+                                     output_buf : JSAMPARRAY;
+                               var out_row_ctr : JDIMENSION;
+                                     out_rows_avail : JDIMENSION); forward;
+{$endif}
+
+
+{LOCAL}
+procedure alloc_funny_pointers (cinfo : j_decompress_ptr);
+{ Allocate space for the funny pointer lists.
+  This is done only once, not once per pass. }
+var
+  main : my_main_ptr;
+  ci, rgroup : int;
+  M : int;
+  compptr : jpeg_component_info_ptr;
+  xbuf : JSAMPARRAY;
+begin
+  main := my_main_ptr (cinfo^.main);
+  M := cinfo^.min_DCT_scaled_size;
+
+  { Get top-level space for component array pointers.
+    We alloc both arrays with one call to save a few cycles. }
+
+  main^.xbuffer[0] := JSAMPIMAGE (
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+                      cinfo^.num_components * 2 * SIZEOF(JSAMPARRAY)) );
+  main^.xbuffer[1] := JSAMPIMAGE(@( main^.xbuffer[0]^[cinfo^.num_components] ));
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div
+      cinfo^.min_DCT_scaled_size; { height of a row group of component }
+    { Get space for pointer lists --- M+4 row groups in each list.
+      We alloc both pointer lists with one call to save a few cycles. }
+
+    xbuf := JSAMPARRAY (
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+         2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)) );
+    Inc(JSAMPROW_PTR(xbuf), rgroup); { want one row group at negative offsets }
+    main^.xbuffer[0]^[ci] := xbuf;
+    Inc(JSAMPROW_PTR(xbuf), rgroup * (M + 4));
+    main^.xbuffer[1]^[ci] := xbuf;
+    Inc(compptr);
+  end;
+end;
+
+{LOCAL}
+procedure make_funny_pointers (cinfo : j_decompress_ptr);
+{ Create the funny pointer lists discussed in the comments above.
+  The actual workspace is already allocated (in main^.buffer),
+  and the space for the pointer lists is allocated too.
+  This routine just fills in the curiously ordered lists.
+  This will be repeated at the beginning of each pass. }
+var
+  main : my_main_ptr;
+  ci, i, rgroup : int;
+  M : int;
+  compptr : jpeg_component_info_ptr;
+  buf, xbuf0, xbuf1 : JSAMPARRAY;
+var
+  help_xbuf0 : JSAMPARRAY;       { work around negative offsets }
+begin
+  main := my_main_ptr (cinfo^.main);
+  M := cinfo^.min_DCT_scaled_size;
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div
+      cinfo^.min_DCT_scaled_size; { height of a row group of component }
+    xbuf0 := main^.xbuffer[0]^[ci];
+    xbuf1 := main^.xbuffer[1]^[ci];
+    { First copy the workspace pointers as-is }
+    buf := main^.buffer[ci];
+    for i := 0 to pred(rgroup * (M + 2)) do
+    begin
+      xbuf0^[i] := buf^[i];
+      xbuf1^[i] := buf^[i];
+    end;
+    { In the second list, put the last four row groups in swapped order }
+    for i := 0 to pred(rgroup * 2) do
+    begin
+      xbuf1^[rgroup*(M-2) + i] := buf^[rgroup*M + i];
+      xbuf1^[rgroup*M + i] := buf^[rgroup*(M-2) + i];
+    end;
+    { The wraparound pointers at top and bottom will be filled later
+      (see set_wraparound_pointers, below).  Initially we want the "above"
+      pointers to duplicate the first actual data line.  This only needs
+      to happen in xbuffer[0]. }
+
+    help_xbuf0 := xbuf0;
+    Dec(JSAMPROW_PTR(help_xbuf0), rgroup);
+
+    for i := 0 to pred(rgroup) do
+    begin
+      {xbuf0^[i - rgroup] := xbuf0^[0];}
+      help_xbuf0^[i] := xbuf0^[0];
+    end;
+    Inc(compptr);
+  end;
+end;
+
+
+{LOCAL}
+procedure set_wraparound_pointers (cinfo : j_decompress_ptr);
+{ Set up the "wraparound" pointers at top and bottom of the pointer lists.
+  This changes the pointer list state from top-of-image to the normal state. }
+var
+  main : my_main_ptr;
+  ci, i, rgroup : int;
+  M : int;
+  compptr : jpeg_component_info_ptr;
+  xbuf0, xbuf1 : JSAMPARRAY;
+var
+  help_xbuf0,
+  help_xbuf1 : JSAMPARRAY;       { work around negative offsets }
+begin
+  main := my_main_ptr (cinfo^.main);
+  M := cinfo^.min_DCT_scaled_size;
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div
+      cinfo^.min_DCT_scaled_size; { height of a row group of component }
+    xbuf0 := main^.xbuffer[0]^[ci];
+    xbuf1 := main^.xbuffer[1]^[ci];
+
+    help_xbuf0 := xbuf0;
+    Dec(JSAMPROW_PTR(help_xbuf0), rgroup);
+    help_xbuf1 := xbuf1;
+    Dec(JSAMPROW_PTR(help_xbuf1), rgroup);
+
+    for i := 0 to pred(rgroup) do
+    begin
+      {xbuf0^[i - rgroup] := xbuf0^[rgroup*(M+1) + i];
+      xbuf1^[i - rgroup] := xbuf1^[rgroup*(M+1) + i];}
+
+      help_xbuf0^[i] := xbuf0^[rgroup*(M+1) + i];
+      help_xbuf1^[i] := xbuf1^[rgroup*(M+1) + i];
+
+      xbuf0^[rgroup*(M+2) + i] := xbuf0^[i];
+      xbuf1^[rgroup*(M+2) + i] := xbuf1^[i];
+    end;
+    Inc(compptr);
+  end;
+end;
+
+
+{LOCAL}
+procedure set_bottom_pointers (cinfo : j_decompress_ptr);
+{ Change the pointer lists to duplicate the last sample row at the bottom
+  of the image.  whichptr indicates which xbuffer holds the final iMCU row.
+  Also sets rowgroups_avail to indicate number of nondummy row groups in row. }
+var
+  main : my_main_ptr;
+  ci, i, rgroup, iMCUheight, rows_left : int;
+  compptr : jpeg_component_info_ptr;
+  xbuf : JSAMPARRAY;
+begin
+  main := my_main_ptr (cinfo^.main);
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Count sample rows in one iMCU row and in one row group }
+    iMCUheight := compptr^.v_samp_factor * compptr^.DCT_scaled_size;
+    rgroup := iMCUheight div cinfo^.min_DCT_scaled_size;
+    { Count nondummy sample rows remaining for this component }
+    rows_left := int (compptr^.downsampled_height mod JDIMENSION (iMCUheight));
+    if (rows_left = 0) then
+      rows_left := iMCUheight;
+    { Count nondummy row groups.  Should get same answer for each component,
+      so we need only do it once. }
+    if (ci = 0) then
+    begin
+      main^.rowgroups_avail := JDIMENSION ((rows_left-1) div rgroup + 1);
+    end;
+    { Duplicate the last real sample row rgroup*2 times; this pads out the
+      last partial rowgroup and ensures at least one full rowgroup of context. }
+
+    xbuf := main^.xbuffer[main^.whichptr]^[ci];
+    for i := 0 to pred(rgroup * 2) do
+    begin
+      xbuf^[rows_left + i] := xbuf^[rows_left-1];
+    end;
+    Inc(compptr);
+  end;
+end;
+
+
+{ Initialize for a processing pass. }
+
+{METHODDEF}
+procedure start_pass_main (cinfo : j_decompress_ptr;
+                           pass_mode : J_BUF_MODE);
+var
+  main : my_main_ptr;
+begin
+  main := my_main_ptr (cinfo^.main);
+
+  case (pass_mode) of
+  JBUF_PASS_THRU:
+    begin
+      if (cinfo^.upsample^.need_context_rows) then
+      begin
+        main^.pub.process_data := process_data_context_main;
+        make_funny_pointers(cinfo); { Create the xbuffer[] lists }
+        main^.whichptr := 0;  { Read first iMCU row into xbuffer[0] }
+        main^.context_state := CTX_PREPARE_FOR_IMCU;
+        main^.iMCU_row_ctr := 0;
+      end
+      else
+      begin
+        { Simple case with no context needed }
+        main^.pub.process_data := process_data_simple_main;
+      end;
+      main^.buffer_full := FALSE; { Mark buffer empty }
+      main^.rowgroup_ctr := 0;
+    end;
+{$ifdef QUANT_2PASS_SUPPORTED}
+  JBUF_CRANK_DEST:
+    { For last pass of 2-pass quantization, just crank the postprocessor }
+    main^.pub.process_data := process_data_crank_post;
+{$endif}
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+  end;
+end;
+
+
+{ Process some data.
+  This handles the simple case where no context is required. }
+
+{METHODDEF}
+procedure process_data_simple_main (cinfo : j_decompress_ptr;
+                  output_buf : JSAMPARRAY;
+                                    var out_row_ctr : JDIMENSION;
+                  out_rows_avail : JDIMENSION);
+var
+  main : my_main_ptr;
+  rowgroups_avail : JDIMENSION;
+var
+  main_buffer_ptr : JSAMPIMAGE;
+begin
+  main := my_main_ptr (cinfo^.main);
+  main_buffer_ptr := JSAMPIMAGE(@(main^.buffer));
+
+  { Read input data if we haven't filled the main buffer yet }
+  if (not main^.buffer_full) then
+  begin
+    if (cinfo^.coef^.decompress_data (cinfo, main_buffer_ptr)=0) then
+      exit;     { suspension forced, can do nothing more }
+    main^.buffer_full := TRUE;  { OK, we have an iMCU row to work with }
+  end;
+
+  { There are always min_DCT_scaled_size row groups in an iMCU row. }
+  rowgroups_avail := JDIMENSION (cinfo^.min_DCT_scaled_size);
+  { Note: at the bottom of the image, we may pass extra garbage row groups
+    to the postprocessor.  The postprocessor has to check for bottom
+    of image anyway (at row resolution), so no point in us doing it too. }
+
+  { Feed the postprocessor }
+  cinfo^.post^.post_process_data (cinfo, main_buffer_ptr,
+                                  main^.rowgroup_ctr, rowgroups_avail,
+          output_buf, out_row_ctr, out_rows_avail);
+
+  { Has postprocessor consumed all the data yet? If so, mark buffer empty }
+  if (main^.rowgroup_ctr >= rowgroups_avail) then
+  begin
+    main^.buffer_full := FALSE;
+    main^.rowgroup_ctr := 0;
+  end;
+end;
+
+
+{ Process some data.
+  This handles the case where context rows must be provided. }
+
+{METHODDEF}
+procedure process_data_context_main (cinfo : j_decompress_ptr;
+                   output_buf : JSAMPARRAY;
+                                     var out_row_ctr : JDIMENSION;
+                   out_rows_avail : JDIMENSION);
+var
+  main : my_main_ptr;
+begin
+  main := my_main_ptr (cinfo^.main);
+
+  { Read input data if we haven't filled the main buffer yet }
+  if (not main^.buffer_full) then
+  begin
+    if (cinfo^.coef^.decompress_data (cinfo,
+        main^.xbuffer[main^.whichptr])=0) then
+      exit;     { suspension forced, can do nothing more }
+    main^.buffer_full := TRUE;  { OK, we have an iMCU row to work with }
+    Inc(main^.iMCU_row_ctr);  { count rows received }
+  end;
+
+  { Postprocessor typically will not swallow all the input data it is handed
+    in one call (due to filling the output buffer first).  Must be prepared
+    to exit and restart.  This switch lets us keep track of how far we got.
+    Note that each case falls through to the next on successful completion. }
+
+  case (main^.context_state) of
+  CTX_POSTPONED_ROW:
+    begin
+      { Call postprocessor using previously set pointers for postponed row }
+      cinfo^.post^.post_process_data (cinfo, main^.xbuffer[main^.whichptr],
+        main^.rowgroup_ctr, main^.rowgroups_avail,
+        output_buf, out_row_ctr, out_rows_avail);
+      if (main^.rowgroup_ctr < main^.rowgroups_avail) then
+        exit;     { Need to suspend }
+      main^.context_state := CTX_PREPARE_FOR_IMCU;
+      if (out_row_ctr >= out_rows_avail) then
+        exit;     { Postprocessor exactly filled output buf }
+    end;
+  end;
+  case (main^.context_state) of
+  CTX_POSTPONED_ROW,
+  CTX_PREPARE_FOR_IMCU:  {FALLTHROUGH}
+    begin
+      { Prepare to process first M-1 row groups of this iMCU row }
+      main^.rowgroup_ctr := 0;
+      main^.rowgroups_avail := JDIMENSION (cinfo^.min_DCT_scaled_size - 1);
+      { Check for bottom of image: if so, tweak pointers to "duplicate"
+        the last sample row, and adjust rowgroups_avail to ignore padding rows. }
+
+      if (main^.iMCU_row_ctr = cinfo^.total_iMCU_rows) then
+        set_bottom_pointers(cinfo);
+      main^.context_state := CTX_PROCESS_IMCU;
+
+    end;
+  end;
+  case (main^.context_state) of
+  CTX_POSTPONED_ROW,
+  CTX_PREPARE_FOR_IMCU,  {FALLTHROUGH}
+  CTX_PROCESS_IMCU:
+    begin
+      { Call postprocessor using previously set pointers }
+      cinfo^.post^.post_process_data (cinfo, main^.xbuffer[main^.whichptr],
+        main^.rowgroup_ctr, main^.rowgroups_avail,
+        output_buf, out_row_ctr, out_rows_avail);
+      if (main^.rowgroup_ctr < main^.rowgroups_avail) then
+        exit;     { Need to suspend }
+      { After the first iMCU, change wraparound pointers to normal state }
+      if (main^.iMCU_row_ctr = 1) then
+        set_wraparound_pointers(cinfo);
+      { Prepare to load new iMCU row using other xbuffer list }
+      main^.whichptr := main^.whichptr xor 1; { 0=>1 or 1=>0 }
+      main^.buffer_full := FALSE;
+      { Still need to process last row group of this iMCU row, }
+      { which is saved at index M+1 of the other xbuffer }
+      main^.rowgroup_ctr := JDIMENSION (cinfo^.min_DCT_scaled_size + 1);
+      main^.rowgroups_avail := JDIMENSION (cinfo^.min_DCT_scaled_size + 2);
+      main^.context_state := CTX_POSTPONED_ROW;
+    end;
+  end;
+end;
+
+
+{ Process some data.
+  Final pass of two-pass quantization: just call the postprocessor.
+  Source data will be the postprocessor controller's internal buffer. }
+
+{$ifdef QUANT_2PASS_SUPPORTED}
+
+{METHODDEF}
+procedure process_data_crank_post (cinfo : j_decompress_ptr;
+                 output_buf : JSAMPARRAY;
+                                   var out_row_ctr : JDIMENSION;
+                 out_rows_avail : JDIMENSION);
+var
+  in_row_group_ctr : JDIMENSION;
+begin
+  in_row_group_ctr := 0;
+  cinfo^.post^.post_process_data (cinfo, JSAMPIMAGE (NIL),
+             in_row_group_ctr,
+                                     JDIMENSION(0),
+             output_buf,
+                                     out_row_ctr,
+                                     out_rows_avail);
+end;
+
+{$endif} { QUANT_2PASS_SUPPORTED }
+
+
+{ Initialize main buffer controller. }
+
+{GLOBAL}
+procedure jinit_d_main_controller (cinfo : j_decompress_ptr;
+                                   need_full_buffer : boolean);
+var
+  main : my_main_ptr;
+  ci, rgroup, ngroups : int;
+  compptr : jpeg_component_info_ptr;
+begin
+  main := my_main_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_main_controller)) );
+  cinfo^.main := jpeg_d_main_controller_ptr(main);
+  main^.pub.start_pass := start_pass_main;
+
+  if (need_full_buffer) then  { shouldn't happen }
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+
+  { Allocate the workspace.
+    ngroups is the number of row groups we need.}
+
+  if (cinfo^.upsample^.need_context_rows) then
+  begin
+    if (cinfo^.min_DCT_scaled_size < 2) then { unsupported, see comments above }
+      ERREXIT(j_common_ptr(cinfo), JERR_NOTIMPL);
+    alloc_funny_pointers(cinfo); { Alloc space for xbuffer[] lists }
+    ngroups := cinfo^.min_DCT_scaled_size + 2;
+  end
+  else
+  begin
+    ngroups := cinfo^.min_DCT_scaled_size;
+  end;
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div
+      cinfo^.min_DCT_scaled_size; { height of a row group of component }
+    main^.buffer[ci] := cinfo^.mem^.alloc_sarray
+      (j_common_ptr(cinfo), JPOOL_IMAGE,
+       compptr^.width_in_blocks * LongWord(compptr^.DCT_scaled_size),
+       JDIMENSION (rgroup * ngroups));
+    Inc(compptr);
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdmarker.pas b/src/lib/vampimg/JpegLib/imjdmarker.pas
new file mode 100644 (file)
index 0000000..b87a3dd
--- /dev/null
@@ -0,0 +1,2648 @@
+unit imjdmarker;
+
+{ This file contains routines to decode JPEG datastream markers.
+  Most of the complexity arises from our desire to support input
+  suspension: if not all of the data for a marker is available;
+  we must exit back to the application. On resumption; we reprocess
+  the marker. }
+
+{ Original: jdmarker.c;  Copyright (C) 1991-1998; Thomas G. Lane. }
+{ History
+   9.7.96                   Conversion to pascal started      jnn
+   22.3.98                  updated to 6b                     jnn }
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjcomapi,
+  imjpeglib;
+
+const                 { JPEG marker codes }
+  M_SOF0  = $c0;
+  M_SOF1  = $c1;
+  M_SOF2  = $c2;
+  M_SOF3  = $c3;
+
+  M_SOF5  = $c5;
+  M_SOF6  = $c6;
+  M_SOF7  = $c7;
+
+  M_JPG   = $c8;
+  M_SOF9  = $c9;
+  M_SOF10 = $ca;
+  M_SOF11 = $cb;
+
+  M_SOF13 = $cd;
+  M_SOF14 = $ce;
+  M_SOF15 = $cf;
+
+  M_DHT   = $c4;
+
+  M_DAC   = $cc;
+
+  M_RST0  = $d0;
+  M_RST1  = $d1;
+  M_RST2  = $d2;
+  M_RST3  = $d3;
+  M_RST4  = $d4;
+  M_RST5  = $d5;
+  M_RST6  = $d6;
+  M_RST7  = $d7;
+
+  M_SOI   = $d8;
+  M_EOI   = $d9;
+  M_SOS   = $da;
+  M_DQT   = $db;
+  M_DNL   = $dc;
+  M_DRI   = $dd;
+  M_DHP   = $de;
+  M_EXP   = $df;
+
+  M_APP0  = $e0;
+  M_APP1  = $e1;
+  M_APP2  = $e2;
+  M_APP3  = $e3;
+  M_APP4  = $e4;
+  M_APP5  = $e5;
+  M_APP6  = $e6;
+  M_APP7  = $e7;
+  M_APP8  = $e8;
+  M_APP9  = $e9;
+  M_APP10 = $ea;
+  M_APP11 = $eb;
+  M_APP12 = $ec;
+  M_APP13 = $ed;
+  M_APP14 = $ee;
+  M_APP15 = $ef;
+
+  M_JPG0  = $f0;
+  M_JPG13 = $fd;
+  M_COM   = $fe;
+
+  M_TEM   = $01;
+
+  M_ERROR = $100;
+
+type
+  JPEG_MARKER = uint;        { JPEG marker codes }
+
+{ Private state }
+
+type
+  my_marker_ptr = ^my_marker_reader;
+  my_marker_reader = record
+    pub : jpeg_marker_reader; { public fields }
+
+    { Application-overridable marker processing methods }
+    process_COM : jpeg_marker_parser_method;
+    process_APPn : array[0..16-1] of jpeg_marker_parser_method;
+
+    { Limit on marker data length to save for each marker type }
+    length_limit_COM : uint;
+    length_limit_APPn : array[0..16-1] of uint;
+
+    { Status of COM/APPn marker saving }
+    cur_marker : jpeg_saved_marker_ptr; { NIL if not processing a marker }
+    bytes_read : uint;    { data bytes read so far in marker }
+    { Note: cur_marker is not linked into marker_list until it's all read. }
+  end;
+
+{GLOBAL}
+function jpeg_resync_to_restart(cinfo : j_decompress_ptr;
+                                desired : int) : boolean;
+{GLOBAL}
+procedure jinit_marker_reader (cinfo : j_decompress_ptr);
+
+{$ifdef SAVE_MARKERS_SUPPORTED}
+
+{GLOBAL}
+procedure jpeg_save_markers (cinfo : j_decompress_ptr;
+                             marker_code : int;
+                 length_limit : uint);
+{$ENDIF}
+
+{GLOBAL}
+procedure jpeg_set_marker_processor (cinfo : j_decompress_ptr;
+                                     marker_code : int;
+                               routine : jpeg_marker_parser_method);
+
+implementation
+
+uses
+  imjutils;
+
+{ At all times, cinfo1.src.next_input_byte and .bytes_in_buffer reflect
+  the current restart point; we update them only when we have reached a
+  suitable place to restart if a suspension occurs. }
+
+
+{ Routines to process JPEG markers.
+
+  Entry condition: JPEG marker itself has been read and its code saved
+    in cinfo^.unread_marker; input restart point is just after the marker.
+
+  Exit: if return TRUE, have read and processed any parameters, and have
+    updated the restart point to point after the parameters.
+    If return FALSE, was forced to suspend before reaching end of
+    marker parameters; restart point has not been moved.  Same routine
+    will be called again after application supplies more input data.
+
+  This approach to suspension assumes that all of a marker's parameters
+  can fit into a single input bufferload.  This should hold for "normal"
+  markers.  Some COM/APPn markers might have large parameter segments
+  that might not fit.  If we are simply dropping such a marker, we use
+  skip_input_data to get past it, and thereby put the problem on the
+  source manager's shoulders.  If we are saving the marker's contents
+  into memory, we use a slightly different convention: when forced to
+  suspend, the marker processor updates the restart point to the end of
+  what it's consumed (ie, the end of the buffer) before returning FALSE.
+  On resumption, cinfo->unread_marker still contains the marker code,
+  but the data source will point to the next chunk of marker data.
+  The marker processor must retain internal state to deal with this.
+
+  Note that we don't bother to avoid duplicate trace messages if a
+  suspension occurs within marker parameters.  Other side effects
+  require more care. }
+
+{LOCAL}
+function get_soi (cinfo : j_decompress_ptr) : boolean;
+{ Process an SOI marker }
+var
+  i : int;
+begin
+  {$IFDEF DEBUG}
+  TRACEMS(j_common_ptr(cinfo), 1, JTRC_SOI);
+  {$ENDIF}
+
+  if (cinfo^.marker^.saw_SOI) then
+    ERREXIT(j_common_ptr(cinfo), JERR_SOI_DUPLICATE);
+
+  { Reset all parameters that are defined to be reset by SOI }
+
+  for i := 0 to Pred(NUM_ARITH_TBLS) do
+  with cinfo^ do
+  begin
+    arith_dc_L[i] := 0;
+    arith_dc_U[i] := 1;
+    arith_ac_K[i] := 5;
+  end;
+  cinfo^.restart_interval := 0;
+
+  { Set initial assumptions for colorspace etc }
+
+  with cinfo^ do
+  begin
+    jpeg_color_space := JCS_UNKNOWN;
+    CCIR601_sampling := FALSE; { Assume non-CCIR sampling??? }
+
+    saw_JFIF_marker := FALSE;
+    JFIF_major_version := 1; { set default JFIF APP0 values }
+    JFIF_minor_version := 1;
+    density_unit := 0;
+    X_density := 1;
+    Y_density := 1;
+    saw_Adobe_marker := FALSE;
+    Adobe_transform := 0;
+
+    marker^.saw_SOI := TRUE;
+  end;
+  get_soi := TRUE;
+end; { get_soi }
+
+
+{LOCAL}
+function get_sof(cinfo : j_decompress_ptr;
+                 is_prog : boolean;
+                 is_arith : boolean) : boolean;
+{ Process a SOFn marker }
+var
+  length : INT32;
+  c, ci : int;
+  compptr : jpeg_component_info_ptr;
+{ Declare and initialize local copies of input pointer/count }
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+{}
+  cinfo^.progressive_mode := is_prog;
+  cinfo^.arith_code := is_arith;
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sof := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sof := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+
+  { Read a byte into variable cinfo^.data_precision.
+    If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sof := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  cinfo^.data_precision := GETJOCTET(next_input_byte^);
+  Inc(next_input_byte);
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  cinfo^.image_height should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sof := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  cinfo^.image_height := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sof := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( cinfo^.image_height, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  cinfo^.image_width should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sof := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  cinfo^.image_width := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sof := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( cinfo^.image_width, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+  { Read a byte into variable cinfo^.num_components.
+    If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sof := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  cinfo^.num_components := GETJOCTET(next_input_byte^);
+  Inc(next_input_byte);
+
+  Dec(length, 8);
+
+  {$IFDEF DEBUG}
+  TRACEMS4(j_common_ptr(cinfo), 1, JTRC_SOF, cinfo^.unread_marker,
+     int(cinfo^.image_width), int(cinfo^.image_height),
+     cinfo^.num_components);
+  {$ENDIF}
+
+  if (cinfo^.marker^.saw_SOF) then
+    ERREXIT(j_common_ptr(cinfo), JERR_SOF_DUPLICATE);
+
+  { We don't support files in which the image height is initially specified }
+  { as 0 and is later redefined by DNL.  As long as we have to check that,  }
+  { might as well have a general sanity check. }
+  if (cinfo^.image_height <= 0) or (cinfo^.image_width <= 0)
+      or (cinfo^.num_components <= 0) then
+    ERREXIT(j_common_ptr(cinfo), JERR_EMPTY_IMAGE);
+
+  if (length <> (cinfo^.num_components * 3)) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
+
+  if (cinfo^.comp_info = NIL) then { do only once, even if suspend }
+    cinfo^.comp_info := jpeg_component_info_list_ptr(
+     cinfo^.mem^.alloc_small(j_common_ptr(cinfo), JPOOL_IMAGE,
+                  cinfo^.num_components * SIZEOF(jpeg_component_info)));
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    compptr^.component_index := ci;
+
+    { Read a byte into variable compptr^.component_id.
+      If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sof := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    compptr^.component_id := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    { Read a byte into variable c. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sof := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    c := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    compptr^.h_samp_factor := (c shr 4) and 15;
+    compptr^.v_samp_factor := (c      ) and 15;
+
+    { Read a byte into variable compptr^.quant_tbl_no.
+      If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sof := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    compptr^.quant_tbl_no := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    {$IFDEF DEBUG}
+    TRACEMS4(j_common_ptr(cinfo), 1, JTRC_SOF_COMPONENT,
+       compptr^.component_id, compptr^.h_samp_factor,
+       compptr^.v_samp_factor, compptr^.quant_tbl_no);
+    {$ENDIF}
+
+    Inc(compptr);
+  end;
+
+  cinfo^.marker^.saw_SOF := TRUE;
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  get_sof := TRUE;
+end;  { get_sof }
+
+
+{LOCAL}
+function get_sos (cinfo : j_decompress_ptr) : boolean;
+{ Process a SOS marker }
+label
+  id_found;
+var
+  length : INT32;
+  i, ci, n, c, cc : int;
+  compptr : jpeg_component_info_ptr;
+{ Declare and initialize local copies of input pointer/count }
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;    { Array[] of JOCTET; }
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+{}
+
+  if not cinfo^.marker^.saw_SOF then
+    ERREXIT(j_common_ptr(cinfo), JERR_SOS_NO_SOF);
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sos := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sos := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+
+  { Read a byte into variable n (Number of components).
+    If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sos := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  n := GETJOCTET(next_input_byte^);  { Number of components }
+  Inc(next_input_byte);
+
+  {$IFDEF DEBUG}
+  TRACEMS1(j_common_ptr(cinfo), 1, JTRC_SOS, n);
+  {$ENDIF}
+
+  if ((length <> (n * 2 + 6)) or (n < 1) or (n > MAX_COMPS_IN_SCAN)) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
+
+  cinfo^.comps_in_scan := n;
+
+  { Collect the component-spec parameters }
+
+  for i := 0 to Pred(n) do
+  begin
+    { Read a byte into variable cc. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sos := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    cc := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    { Read a byte into variable c. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_sos := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    c := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+    for ci := 0 to Pred(cinfo^.num_components) do
+    begin
+      if (cc = compptr^.component_id) then
+  goto id_found;
+      Inc(compptr);
+    end;
+
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_COMPONENT_ID, cc);
+
+  id_found:
+
+    cinfo^.cur_comp_info[i] := compptr;
+    compptr^.dc_tbl_no := (c shr 4) and 15;
+    compptr^.ac_tbl_no := (c      ) and 15;
+
+    {$IFDEF DEBUG}
+    TRACEMS3(j_common_ptr(cinfo), 1, JTRC_SOS_COMPONENT, cc,
+       compptr^.dc_tbl_no, compptr^.ac_tbl_no);
+    {$ENDIF}
+  end;
+
+  { Collect the additional scan parameters Ss, Se, Ah/Al. }
+  { Read a byte into variable c. If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sos := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  c := GETJOCTET(next_input_byte^);
+  Inc(next_input_byte);
+
+  cinfo^.Ss := c;
+
+  { Read a byte into variable c. If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sos := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  c := GETJOCTET(next_input_byte^);
+  Inc(next_input_byte);
+
+  cinfo^.Se := c;
+
+  { Read a byte into variable c. If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_sos := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  c := GETJOCTET(next_input_byte^);
+  Inc(next_input_byte);
+
+  cinfo^.Ah := (c shr 4) and 15;
+  cinfo^.Al := (c     ) and 15;
+
+  {$IFDEF DEBUG}
+  TRACEMS4(j_common_ptr(cinfo), 1, JTRC_SOS_PARAMS, cinfo^.Ss, cinfo^.Se,
+     cinfo^.Ah, cinfo^.Al);
+  {$ENDIF}
+
+  { Prepare to scan data & restart markers }
+  cinfo^.marker^.next_restart_num := 0;
+
+  { Count another SOS marker }
+  Inc( cinfo^.input_scan_number );
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  get_sos := TRUE;
+end;  { get_sos }
+
+
+{METHODDEF}
+function skip_variable (cinfo : j_decompress_ptr) : boolean;
+{ Skip over an unknown or uninteresting variable-length marker }
+var
+  length : INT32;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;    { Array[] of JOCTET; }
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      skip_variable := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := uint(GETJOCTET(next_input_byte^)) shl 8;
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      skip_variable := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET(next_input_byte^));
+  Inc( next_input_byte );
+
+  Dec(length, 2);
+
+  {$IFDEF DEBUG}
+  TRACEMS2(j_common_ptr(cinfo), 1, JTRC_MISC_MARKER,
+    cinfo^.unread_marker, int(length));
+  {$ENDIF}
+
+  { Unload the local copies --- do this only at a restart boundary }
+  { do before skip_input_data }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  if (length > 0) then
+    cinfo^.src^.skip_input_data(cinfo, long(length));
+
+  skip_variable := TRUE;
+end;  { skip_variable }
+
+
+{$IFDEF D_ARITH_CODING_SUPPORTED}
+
+{LOCAL}
+function get_dac (cinfo : j_decompress_ptr) : boolean;
+{ Process a DAC marker }
+var
+  length : INT32;
+  index, val : int;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_dac := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dac := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+  Dec(length,  2);
+
+  while (length > 0) do
+  begin
+    { Read a byte into variable index. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dac := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    index := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    { Read a byte into variable val. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dac := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    val := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    Dec( length, 2);
+
+    {$IFDEF DEBUG}
+    TRACEMS2(j_common_ptr(cinfo), 1, JTRC_DAC, index, val);
+    {$ENDIF}
+
+    if (index < 0) or (index >= (2*NUM_ARITH_TBLS)) then
+      ERREXIT1(j_common_ptr(cinfo) , JERR_DAC_INDEX, index);
+
+    if (index >= NUM_ARITH_TBLS) then
+    begin { define AC table }
+      cinfo^.arith_ac_K[index-NUM_ARITH_TBLS] := UINT8(val);
+    end
+    else
+    begin { define DC table }
+      cinfo^.arith_dc_L[index] := UINT8(val and $0F);
+      cinfo^.arith_dc_U[index] := UINT8(val shr 4);
+      if (cinfo^.arith_dc_L[index] > cinfo^.arith_dc_U[index]) then
+  ERREXIT1(j_common_ptr(cinfo) , JERR_DAC_VALUE, val);
+    end;
+  end;
+
+  if (length <> 0) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  get_dac := TRUE;
+end;  { get_dac }
+
+{$ELSE}
+
+{LOCAL}
+function get_dac (cinfo : j_decompress_ptr) : boolean;
+begin
+  get_dac := skip_variable(cinfo);
+end;
+
+{$ENDIF}
+
+{LOCAL}
+function get_dht (cinfo : j_decompress_ptr) : boolean;
+{ Process a DHT marker }
+var
+  length : INT32;
+  bits : Array[0..17-1] of UINT8;
+  huffval : Array[0..256-1] of UINT8;
+  i, index, count : int;
+  htblptr : ^JHUFF_TBL_PTR;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_dht := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dht := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+  Dec(length,  2);
+
+  while (length > 16) do
+  begin
+    { Read a byte into variable index. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dht := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    index := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    {$IFDEF DEBUG}
+    TRACEMS1(j_common_ptr(cinfo), 1, JTRC_DHT, index);
+    {$ENDIF}
+
+    bits[0] := 0;
+    count := 0;
+    for i := 1 to 16 do
+    begin
+      { Read a byte into variable bits[i]. If must suspend, return FALSE. }
+      { make a byte available.
+        Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+        but we must reload the local copies after a successful fill. }
+      if (bytes_in_buffer = 0) then
+      begin
+        if (not datasrc^.fill_input_buffer(cinfo)) then
+        begin
+          get_dht := FALSE;
+          exit;
+        end;
+        { Reload the local copies }
+        next_input_byte := datasrc^.next_input_byte;
+        bytes_in_buffer := datasrc^.bytes_in_buffer;
+      end;
+      Dec( bytes_in_buffer );
+
+      bits[i] := GETJOCTET(next_input_byte^);
+      Inc(next_input_byte);
+
+      Inc( count, bits[i] );
+    end;
+
+    Dec( length, (1 + 16) );
+
+    {$IFDEF DEBUG}
+    TRACEMS8(j_common_ptr(cinfo), 2, JTRC_HUFFBITS,
+       bits[1], bits[2], bits[3], bits[4],
+       bits[5], bits[6], bits[7], bits[8]);
+    TRACEMS8(j_common_ptr(cinfo), 2, JTRC_HUFFBITS,
+       bits[9], bits[10], bits[11], bits[12],
+       bits[13], bits[14], bits[15], bits[16]);
+    {$ENDIF}
+
+    { Here we just do minimal validation of the counts to avoid walking
+      off the end of our table space.  jdhuff.c will check more carefully. }
+
+    if (count > 256) or (INT32(count) > length) then
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE);
+
+    for i := 0 to Pred(count) do
+    begin
+    { Read a byte into variable huffval[i]. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+      if (bytes_in_buffer = 0) then
+      begin
+        if (not datasrc^.fill_input_buffer(cinfo)) then
+        begin
+          get_dht := FALSE;
+          exit;
+        end;
+        { Reload the local copies }
+        next_input_byte := datasrc^.next_input_byte;
+        bytes_in_buffer := datasrc^.bytes_in_buffer;
+      end;
+      Dec( bytes_in_buffer );
+
+      huffval[i] := GETJOCTET(next_input_byte^);
+      Inc(next_input_byte);
+    end;
+
+    Dec( length, count );
+
+    if (index and $10)<>0 then
+    begin  { AC table definition }
+      Dec( index, $10 );
+      htblptr := @cinfo^.ac_huff_tbl_ptrs[index];
+    end
+    else
+    begin { DC table definition }
+      htblptr := @cinfo^.dc_huff_tbl_ptrs[index];
+    end;
+
+    if (index < 0) or (index >= NUM_HUFF_TBLS) then
+      ERREXIT1(j_common_ptr(cinfo), JERR_DHT_INDEX, index);
+
+    if (htblptr^ = NIL) then
+      htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo));
+
+    MEMCOPY(@(htblptr^)^.bits, @bits, SIZEOF((htblptr^)^.bits));
+    MEMCOPY(@(htblptr^)^.huffval, @huffval, SIZEOF((htblptr^)^.huffval));
+  end;
+
+  if (length <> 0) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  get_dht := TRUE;
+end;  { get_dht }
+
+
+{LOCAL}
+function get_dqt (cinfo : j_decompress_ptr) : boolean;
+{ Process a DQT marker }
+var
+  length : INT32;
+  n, i, prec : int;
+  tmp : uint;
+  quant_ptr : JQUANT_TBL_PTR;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_dqt := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dqt := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+  Dec( length, 2 );
+
+  while (length > 0) do
+  begin
+    { Read a byte into variable n. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dqt := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    n := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+    prec := n shr 4;
+    n := n and $0F;
+
+    {$IFDEF DEBUG}
+    TRACEMS2(j_common_ptr(cinfo), 1, JTRC_DQT, n, prec);
+    {$ENDIF}
+
+    if (n >= NUM_QUANT_TBLS) then
+      ERREXIT1(j_common_ptr(cinfo) , JERR_DQT_INDEX, n);
+
+    if (cinfo^.quant_tbl_ptrs[n] = NIL) then
+      cinfo^.quant_tbl_ptrs[n] := jpeg_alloc_quant_table(j_common_ptr(cinfo));
+    quant_ptr := cinfo^.quant_tbl_ptrs[n];
+
+    for i := 0 to Pred(DCTSIZE2) do
+    begin
+      if (prec <> 0) then
+      begin
+      { Read two bytes interpreted as an unsigned 16-bit integer.
+        tmp should be declared unsigned int or perhaps INT32. }
+
+      { make a byte available.
+        Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+        but we must reload the local copies after a successful fill. }
+        if (bytes_in_buffer = 0) then
+        begin
+          if (not datasrc^.fill_input_buffer(cinfo)) then
+          begin
+            get_dqt := FALSE;
+            exit;
+          end;
+          { Reload the local copies }
+          next_input_byte := datasrc^.next_input_byte;
+          bytes_in_buffer := datasrc^.bytes_in_buffer;
+        end;
+        Dec( bytes_in_buffer );
+
+        tmp := (uint( GETJOCTET(next_input_byte^)) shl 8);
+        Inc( next_input_byte );
+        { make a byte available.
+          Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+          but we must reload the local copies after a successful fill. }
+          if (bytes_in_buffer = 0) then
+          begin
+            if (not datasrc^.fill_input_buffer(cinfo)) then
+            begin
+              get_dqt := FALSE;
+              exit;
+            end;
+            { Reload the local copies }
+            next_input_byte := datasrc^.next_input_byte;
+            bytes_in_buffer := datasrc^.bytes_in_buffer;
+          end;
+          Dec( bytes_in_buffer );
+
+        Inc( tmp, GETJOCTET( next_input_byte^));
+        Inc( next_input_byte );
+
+      end
+      else
+      begin
+      { Read a byte into variable tmp. If must suspend, return FALSE. }
+      { make a byte available.
+        Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+        but we must reload the local copies after a successful fill. }
+        if (bytes_in_buffer = 0) then
+        begin
+          if (not datasrc^.fill_input_buffer(cinfo)) then
+          begin
+            get_dqt := FALSE;
+            exit;
+          end;
+          { Reload the local copies }
+          next_input_byte := datasrc^.next_input_byte;
+          bytes_in_buffer := datasrc^.bytes_in_buffer;
+        end;
+        Dec( bytes_in_buffer );
+
+        tmp := GETJOCTET(next_input_byte^);
+        Inc(next_input_byte);
+      end;
+
+      { We convert the zigzag-order table to natural array order. }
+      quant_ptr^.quantval[jpeg_natural_order[i]] := UINT16(tmp);
+    end;
+
+    if (cinfo^.err^.trace_level >= 2) then
+    begin
+      i := 0;
+      while i < Pred(DCTSIZE2) do
+      begin
+        {$IFDEF DEBUG}
+  TRACEMS8(j_common_ptr(cinfo), 2, JTRC_QUANTVALS,
+     quant_ptr^.quantval[i],   quant_ptr^.quantval[i+1],
+     quant_ptr^.quantval[i+2], quant_ptr^.quantval[i+3],
+     quant_ptr^.quantval[i+4], quant_ptr^.quantval[i+5],
+     quant_ptr^.quantval[i+6], quant_ptr^.quantval[i+7]);
+        {$ENDIF}
+        Inc(i, 8);
+      end;
+    end;
+
+    Dec( length, DCTSIZE2+1 );
+    if (prec <> 0) then
+      Dec( length, DCTSIZE2 );
+  end;
+
+  if (length <> 0) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  get_dqt := TRUE;
+end;  { get_dqt }
+
+
+{LOCAL}
+function get_dri (cinfo : j_decompress_ptr) : boolean;
+{ Process a DRI marker }
+var
+  length : INT32;
+  tmp : uint;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_dri := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dri := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+  if (length <> 4) then
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH);
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  tmp should be declared unsigned int or perhaps INT32. }
+
+{ make a byte available.
+  Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+  but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_dri := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  tmp := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        get_dri := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+  Inc( tmp, GETJOCTET( next_input_byte^));
+  Inc( next_input_byte );
+
+  {$IFDEF DEBUG}
+  TRACEMS1(j_common_ptr(cinfo), 1, JTRC_DRI, tmp);
+  {$ENDIF}
+
+  cinfo^.restart_interval := tmp;
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  get_dri := TRUE;
+end;  { get_dri }
+
+
+{ Routines for processing APPn and COM markers.
+  These are either saved in memory or discarded, per application request.
+  APP0 and APP14 are specially checked to see if they are
+  JFIF and Adobe markers, respectively. }
+
+const
+  APP0_DATA_LEN = 14;   { Length of interesting data in APP0 }
+  APP14_DATA_LEN = 12;  { Length of interesting data in APP14 }
+  APPN_DATA_LEN = 14;   { Must be the largest of the above!! }
+
+
+{LOCAL}
+procedure examine_app0 (cinfo : j_decompress_ptr;
+                        var data : array of JOCTET;
+                        datalen : uint;
+                        remaining : INT32);
+
+{ Examine first few bytes from an APP0.
+  Take appropriate action if it is a JFIF marker.
+  datalen is # of bytes at data[], remaining is length of rest of marker data.
+}
+{$IFDEF DEBUG}
+var
+  totallen : INT32;
+{$ENDIF}
+begin
+  {$IFDEF DEBUG}
+  totallen := INT32(datalen) + remaining;
+  {$ENDIF}
+  if (datalen >= APP0_DATA_LEN) and
+     (GETJOCTET(data[0]) = $4A) and
+     (GETJOCTET(data[1]) = $46) and
+     (GETJOCTET(data[2]) = $49) and
+     (GETJOCTET(data[3]) = $46) and
+     (GETJOCTET(data[4]) = 0) then
+  begin
+    { Found JFIF APP0 marker: save info }
+    cinfo^.saw_JFIF_marker := TRUE;
+    cinfo^.JFIF_major_version := GETJOCTET(data[5]);
+    cinfo^.JFIF_minor_version := GETJOCTET(data[6]);
+    cinfo^.density_unit := GETJOCTET(data[7]);
+    cinfo^.X_density := (GETJOCTET(data[8]) shl 8) + GETJOCTET(data[9]);
+    cinfo^.Y_density := (GETJOCTET(data[10]) shl 8) + GETJOCTET(data[11]);
+    { Check version.
+      Major version must be 1, anything else signals an incompatible change.
+      (We used to treat this as an error, but now it's a nonfatal warning,
+      because some bozo at Hijaak couldn't read the spec.)
+      Minor version should be 0..2, but process anyway if newer. }
+
+    if (cinfo^.JFIF_major_version <> 1) then
+      WARNMS2(j_common_ptr(cinfo), JWRN_JFIF_MAJOR,
+        cinfo^.JFIF_major_version, cinfo^.JFIF_minor_version);
+    { Generate trace messages }
+    {$IFDEF DEBUG}
+    TRACEMS5(j_common_ptr(cinfo), 1, JTRC_JFIF,
+       cinfo^.JFIF_major_version, cinfo^.JFIF_minor_version,
+       cinfo^.X_density, cinfo^.Y_density, cinfo^.density_unit);
+    { Validate thumbnail dimensions and issue appropriate messages }
+    if (GETJOCTET(data[12]) or GETJOCTET(data[13])) <> 0 then
+      TRACEMS2(j_common_ptr(cinfo), 1, JTRC_JFIF_THUMBNAIL,
+         GETJOCTET(data[12]), GETJOCTET(data[13]));
+    Dec(totallen, APP0_DATA_LEN);
+    if (totallen <>
+  ( INT32(GETJOCTET(data[12])) * INT32(GETJOCTET(data[13])) * INT32(3) )) then
+      TRACEMS1(j_common_ptr(cinfo), 1, JTRC_JFIF_BADTHUMBNAILSIZE, int(totallen));
+    {$ENDIF}
+  end
+  else
+    if (datalen >= 6) and
+      (GETJOCTET(data[0]) = $4A) and
+      (GETJOCTET(data[1]) = $46) and
+      (GETJOCTET(data[2]) = $58) and
+      (GETJOCTET(data[3]) = $58) and
+      (GETJOCTET(data[4]) = 0) then
+    begin
+    { Found JFIF "JFXX" extension APP0 marker }
+    { The library doesn't actually do anything with these,
+      but we try to produce a helpful trace message. }
+      {$IFDEF DEBUG}
+      case (GETJOCTET(data[5])) of
+        $10:
+          TRACEMS1(j_common_ptr(cinfo), 1, JTRC_THUMB_JPEG, int(totallen));
+        $11:
+          TRACEMS1(j_common_ptr(cinfo), 1, JTRC_THUMB_PALETTE, int(totallen));
+        $13:
+          TRACEMS1(j_common_ptr(cinfo), 1, JTRC_THUMB_RGB, int(totallen));
+        else
+          TRACEMS2(j_common_ptr(cinfo), 1, JTRC_JFIF_EXTENSION,
+             GETJOCTET(data[5]), int(totallen));
+      end;
+      {$ENDIF}
+    end
+    else
+    begin
+      { Start of APP0 does not match "JFIF" or "JFXX", or too short }
+      {$IFDEF DEBUG}
+      TRACEMS1(j_common_ptr(cinfo), 1, JTRC_APP0, int(totallen));
+      {$ENDIF}
+    end;
+end;
+
+
+{LOCAL}
+procedure examine_app14 (cinfo : j_decompress_ptr;
+                         var data : array of JOCTET;
+                   datalen : uint;
+                         remaining : INT32);
+{ Examine first few bytes from an APP14.
+  Take appropriate action if it is an Adobe marker.
+  datalen is # of bytes at data[], remaining is length of rest of marker data.
+ }
+var
+  {$IFDEF DEBUG}
+  version, flags0, flags1,
+  {$ENDIF}
+  transform : uint;
+begin
+  if (datalen >= APP14_DATA_LEN) and
+     (GETJOCTET(data[0]) = $41) and
+     (GETJOCTET(data[1]) = $64) and
+     (GETJOCTET(data[2]) = $6F) and
+     (GETJOCTET(data[3]) = $62) and
+     (GETJOCTET(data[4]) = $65) then
+  begin
+    { Found Adobe APP14 marker }
+    {$IFDEF DEBUG}
+    version := (GETJOCTET(data[5]) shl 8) + GETJOCTET(data[6]);
+    flags0 := (GETJOCTET(data[7]) shl 8) + GETJOCTET(data[8]);
+    flags1 := (GETJOCTET(data[9]) shl 8) + GETJOCTET(data[10]);
+    {$ENDIF}
+    transform := GETJOCTET(data[11]);
+    {$IFDEF DEBUG}
+    TRACEMS4(j_common_ptr(cinfo), 1, JTRC_ADOBE, version, flags0, flags1, transform);
+    {$ENDIF}
+    cinfo^.saw_Adobe_marker := TRUE;
+    cinfo^.Adobe_transform := UINT8 (transform);
+  end
+  else
+  begin
+    { Start of APP14 does not match "Adobe", or too short }
+    {$IFDEF DEBUG}
+    TRACEMS1(j_common_ptr(cinfo), 1, JTRC_APP14, int (datalen + remaining));
+    {$ENDIF}
+  end;
+end;
+
+
+{METHODDEF}
+function get_interesting_appn (cinfo : j_decompress_ptr) : boolean;
+{ Process an APP0 or APP14 marker without saving it }
+var
+  length : INT32;
+  b : array[0..APPN_DATA_LEN-1] of JOCTET;
+  i, numtoread: uint;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+{ Read two bytes interpreted as an unsigned 16-bit integer.
+  length should be declared unsigned int or perhaps INT32. }
+
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_interesting_appn := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+  Inc( next_input_byte );
+
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      get_interesting_appn := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  Inc( length, GETJOCTET(next_input_byte^));
+  Inc( next_input_byte );
+
+  Dec(length, 2);
+
+  { get the interesting part of the marker data }
+  if (length >= APPN_DATA_LEN) then
+    numtoread := APPN_DATA_LEN
+  else
+    if (length > 0) then
+      numtoread := uint(length)
+    else
+      numtoread := 0;
+
+  if numtoread > 0 then
+  begin
+    for i := 0 to numtoread-1 do
+    begin
+    { Read a byte into b[i]. If must suspend, return FALSE. }
+      { make a byte available.
+        Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+        but we must reload the local copies after a successful fill. }
+      if (bytes_in_buffer = 0) then
+      begin
+        if (not datasrc^.fill_input_buffer(cinfo)) then
+        begin
+          get_interesting_appn := FALSE;
+          exit;
+        end;
+        { Reload the local copies }
+        next_input_byte := datasrc^.next_input_byte;
+        bytes_in_buffer := datasrc^.bytes_in_buffer;
+      end;
+      Dec( bytes_in_buffer );
+
+      b[i] := GETJOCTET(next_input_byte^);
+      Inc(next_input_byte);
+    end;
+  end;
+
+  Dec(length, numtoread);
+
+  { process it }
+  case (cinfo^.unread_marker) of
+  M_APP0:
+    examine_app0(cinfo, b, numtoread, length);
+  M_APP14:
+    examine_app14(cinfo, b, numtoread, length);
+  else
+    { can't get here unless jpeg_save_markers chooses wrong processor }
+    ERREXIT1(j_common_ptr(cinfo), JERR_UNKNOWN_MARKER, cinfo^.unread_marker);
+  end;
+
+  { skip any remaining data -- could be lots }
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  if (length > 0) then
+    cinfo^.src^.skip_input_data(cinfo, long(length));
+
+  get_interesting_appn := TRUE;
+end;
+
+{$ifdef SAVE_MARKERS_SUPPORTED}
+
+{METHODDEF}
+function save_marker (cinfo : j_decompress_ptr) : boolean;
+{ Save an APPn or COM marker into the marker list }
+var
+  marker : my_marker_ptr;
+  cur_marker : jpeg_saved_marker_ptr;
+  bytes_read, data_length : uint;
+  data : JOCTET_FIELD_PTR;
+  length : INT32;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+var
+  limit : uint;
+var
+  prev : jpeg_saved_marker_ptr;
+begin
+  { local copies of input pointer/count }
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+  marker := my_marker_ptr(cinfo^.marker);
+  cur_marker := marker^.cur_marker;
+  length := 0;
+
+  if (cur_marker = NIL) then
+  begin
+    { begin reading a marker }
+    { Read two bytes interpreted as an unsigned 16-bit integer. }
+
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        save_marker := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    length := (uint( GETJOCTET(next_input_byte^)) shl 8);
+    Inc( next_input_byte );
+
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        save_marker := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    Inc( length, GETJOCTET(next_input_byte^));
+    Inc( next_input_byte );
+
+    Dec(length, 2);
+    if (length >= 0) then
+    begin   { watch out for bogus length word }
+      { figure out how much we want to save }
+
+      if (cinfo^.unread_marker = int(M_COM)) then
+  limit := marker^.length_limit_COM
+      else
+  limit := marker^.length_limit_APPn[cinfo^.unread_marker - int(M_APP0)];
+      if (uint(length) < limit) then
+  limit := uint(length);
+      { allocate and initialize the marker item }
+      cur_marker := jpeg_saved_marker_ptr(
+  cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE,
+                               SIZEOF(jpeg_marker_struct) + limit) );
+      cur_marker^.next := NIL;
+      cur_marker^.marker := UINT8 (cinfo^.unread_marker);
+      cur_marker^.original_length := uint(length);
+      cur_marker^.data_length := limit;
+      { data area is just beyond the jpeg_marker_struct }
+      cur_marker^.data := JOCTET_FIELD_PTR(cur_marker);
+      Inc(jpeg_saved_marker_ptr(cur_marker^.data));
+      data := cur_marker^.data;
+
+      marker^.cur_marker := cur_marker;
+      marker^.bytes_read := 0;
+      bytes_read := 0;
+      data_length := limit;
+    end
+    else
+    begin
+      { deal with bogus length word }
+      data_length := 0;
+      bytes_read := 0;
+      data := NIL;
+    end
+  end
+  else
+  begin
+    { resume reading a marker }
+    bytes_read := marker^.bytes_read;
+    data_length := cur_marker^.data_length;
+    data := cur_marker^.data;
+    Inc(data, bytes_read);
+  end;
+
+  while (bytes_read < data_length) do
+  begin
+    { move the restart point to here }
+    datasrc^.next_input_byte := next_input_byte;
+    datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+    marker^.bytes_read := bytes_read;
+    { If there's not at least one byte in buffer, suspend }
+    if (bytes_in_buffer = 0) then
+    begin
+      if not datasrc^.fill_input_buffer (cinfo) then
+      begin
+        save_marker := FALSE;
+        exit;
+      end;
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+
+    { Copy bytes with reasonable rapidity }
+    while (bytes_read < data_length) and (bytes_in_buffer > 0) do
+    begin
+      JOCTETPTR(data)^ := next_input_byte^;
+      Inc(JOCTETPTR(data));
+      Inc(next_input_byte);
+      Dec(bytes_in_buffer);
+      Inc(bytes_read);
+    end;
+  end;
+
+  { Done reading what we want to read }
+  if (cur_marker <> NIL) then
+  begin { will be NIL if bogus length word }
+    { Add new marker to end of list }
+    if (cinfo^.marker_list = NIL) then
+    begin
+      cinfo^.marker_list := cur_marker
+    end
+    else
+    begin
+      prev := cinfo^.marker_list;
+      while (prev^.next <> NIL) do
+  prev := prev^.next;
+      prev^.next := cur_marker;
+    end;
+    { Reset pointer & calc remaining data length }
+    data := cur_marker^.data;
+    length := cur_marker^.original_length - data_length;
+  end;
+  { Reset to initial state for next marker }
+  marker^.cur_marker := NIL;
+
+  { Process the marker if interesting; else just make a generic trace msg }
+  case (cinfo^.unread_marker) of
+  M_APP0:
+    examine_app0(cinfo, data^, data_length, length);
+  M_APP14:
+    examine_app14(cinfo, data^, data_length, length);
+  else
+    {$IFDEF DEBUG}
+    TRACEMS2(j_common_ptr(cinfo), 1, JTRC_MISC_MARKER, cinfo^.unread_marker,
+       int(data_length + length));
+    {$ENDIF}
+  end;
+
+  { skip any remaining data -- could be lots }
+  { do before skip_input_data }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  if (length > 0) then
+    cinfo^.src^.skip_input_data (cinfo, long(length) );
+
+  save_marker := TRUE;
+end;
+
+{$endif} { SAVE_MARKERS_SUPPORTED }
+
+
+{ Find the next JPEG marker, save it in cinfo^.unread_marker.
+  Returns FALSE if had to suspend before reaching a marker;
+  in that case cinfo^.unread_marker is unchanged.
+
+  Note that the result might not be a valid marker code,
+  but it will never be 0 or FF. }
+
+{LOCAL}
+function next_marker (cinfo : j_decompress_ptr) : boolean;
+var
+  c : int;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+  {while TRUE do}
+  repeat
+    { Read a byte into variable c. If must suspend, return FALSE. }
+    { make a byte available.
+      Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+      but we must reload the local copies after a successful fill. }
+    if (bytes_in_buffer = 0) then
+    begin
+      if (not datasrc^.fill_input_buffer(cinfo)) then
+      begin
+        next_marker := FALSE;
+        exit;
+      end;
+      { Reload the local copies }
+      next_input_byte := datasrc^.next_input_byte;
+      bytes_in_buffer := datasrc^.bytes_in_buffer;
+    end;
+    Dec( bytes_in_buffer );
+
+    c := GETJOCTET(next_input_byte^);
+    Inc(next_input_byte);
+
+   { Skip any non-FF bytes.
+     This may look a bit inefficient, but it will not occur in a valid file.
+     We sync after each discarded byte so that a suspending data source
+     can discard the byte from its buffer. }
+
+    while (c <> $FF) do
+    begin
+      Inc(cinfo^.marker^.discarded_bytes);
+      { Unload the local copies --- do this only at a restart boundary }
+      datasrc^.next_input_byte := next_input_byte;
+      datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+      { Read a byte into variable c. If must suspend, return FALSE. }
+      { make a byte available.
+        Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+        but we must reload the local copies after a successful fill. }
+      if (bytes_in_buffer = 0) then
+      begin
+        if (not datasrc^.fill_input_buffer(cinfo)) then
+        begin
+          next_marker := FALSE;
+          exit;
+        end;
+        { Reload the local copies }
+        next_input_byte := datasrc^.next_input_byte;
+        bytes_in_buffer := datasrc^.bytes_in_buffer;
+      end;
+      Dec( bytes_in_buffer );
+
+      c := GETJOCTET(next_input_byte^);
+      Inc(next_input_byte);
+
+    end;
+    { This loop swallows any duplicate FF bytes.  Extra FFs are legal as
+      pad bytes, so don't count them in discarded_bytes.  We assume there
+      will not be so many consecutive FF bytes as to overflow a suspending
+      data source's input buffer. }
+
+    repeat
+      { Read a byte into variable c. If must suspend, return FALSE. }
+      { make a byte available.
+        Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+        but we must reload the local copies after a successful fill. }
+      if (bytes_in_buffer = 0) then
+      begin
+        if (not datasrc^.fill_input_buffer(cinfo)) then
+        begin
+          next_marker := FALSE;
+          exit;
+        end;
+        { Reload the local copies }
+        next_input_byte := datasrc^.next_input_byte;
+        bytes_in_buffer := datasrc^.bytes_in_buffer;
+      end;
+      Dec( bytes_in_buffer );
+
+      c := GETJOCTET(next_input_byte^);
+      Inc(next_input_byte);
+    Until (c <> $FF);
+    if (c <> 0) then
+      break;      { found a valid marker, exit loop }
+    { Reach here if we found a stuffed-zero data sequence (FF/00).
+      Discard it and loop back to try again. }
+
+    Inc(cinfo^.marker^.discarded_bytes, 2);
+    { Unload the local copies --- do this only at a restart boundary }
+    datasrc^.next_input_byte := next_input_byte;
+    datasrc^.bytes_in_buffer := bytes_in_buffer;
+  Until False;
+
+  if (cinfo^.marker^.discarded_bytes <> 0) then
+  begin
+    WARNMS2(j_common_ptr(cinfo), JWRN_EXTRANEOUS_DATA,
+            cinfo^.marker^.discarded_bytes, c);
+    cinfo^.marker^.discarded_bytes := 0;
+  end;
+
+  cinfo^.unread_marker := c;
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  next_marker := TRUE;
+end;  { next_marker }
+
+
+{LOCAL}
+function first_marker (cinfo : j_decompress_ptr) : boolean;
+{ Like next_marker, but used to obtain the initial SOI marker. }
+{ For this marker, we do not allow preceding garbage or fill; otherwise,
+  we might well scan an entire input file before realizing it ain't JPEG.
+  If an application wants to process non-JFIF files, it must seek to the
+  SOI before calling the JPEG library. }
+var
+  c, c2 : int;
+var
+  datasrc : jpeg_source_mgr_ptr;
+  next_input_byte : JOCTETptr;
+  bytes_in_buffer : size_t;
+begin
+  datasrc := cinfo^.src;
+  next_input_byte := datasrc^.next_input_byte;
+  bytes_in_buffer := datasrc^.bytes_in_buffer;
+
+  { Read a byte into variable c. If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      first_marker := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  c := GETJOCTET(next_input_byte^);
+  Inc(next_input_byte);
+
+  { Read a byte into variable c2. If must suspend, return FALSE. }
+  { make a byte available.
+    Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+    but we must reload the local copies after a successful fill. }
+  if (bytes_in_buffer = 0) then
+  begin
+    if (not datasrc^.fill_input_buffer(cinfo)) then
+    begin
+      first_marker := FALSE;
+      exit;
+    end;
+    { Reload the local copies }
+    next_input_byte := datasrc^.next_input_byte;
+    bytes_in_buffer := datasrc^.bytes_in_buffer;
+  end;
+  Dec( bytes_in_buffer );
+
+  c2 := GETJOCTET(next_input_byte^);
+  Inc(next_input_byte);
+
+  if (c <> $FF) or (c2 <> int(M_SOI)) then
+    ERREXIT2(j_common_ptr(cinfo), JERR_NO_SOI, c, c2);
+
+  cinfo^.unread_marker := c2;
+
+  { Unload the local copies --- do this only at a restart boundary }
+  datasrc^.next_input_byte := next_input_byte;
+  datasrc^.bytes_in_buffer := bytes_in_buffer;
+
+  first_marker := TRUE;
+end;  { first_marker }
+
+
+{ Read markers until SOS or EOI.
+
+  Returns same codes as are defined for jpeg_consume_input:
+  JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.   }
+
+{METHODDEF}
+function read_markers (cinfo : j_decompress_ptr) : int;
+begin
+  { Outer loop repeats once for each marker. }
+  repeat
+    { Collect the marker proper, unless we already did. }
+    { NB: first_marker() enforces the requirement that SOI appear first. }
+    if (cinfo^.unread_marker = 0) then
+    begin
+      if not cinfo^.marker^.saw_SOI then
+      begin
+        if not first_marker(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+      end
+      else
+      begin
+        if not next_marker(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+      end;
+    end;
+    { At this point cinfo^.unread_marker contains the marker code and the
+      input point is just past the marker proper, but before any parameters.
+      A suspension will cause us to return with this state still true. }
+
+    case (cinfo^.unread_marker) of
+      M_SOI:
+        if not get_soi(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_SOF0,             { Baseline }
+      M_SOF1:             { Extended sequential, Huffman }
+        if not get_sof(cinfo, FALSE, FALSE) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+      M_SOF2:                     { Progressive, Huffman }
+        if not get_sof(cinfo, TRUE, FALSE) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_SOF9:                     { Extended sequential, arithmetic }
+        if not get_sof(cinfo, FALSE, TRUE) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_SOF10:                    { Progressive, arithmetic }
+        if not get_sof(cinfo, TRUE, TRUE) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      { Currently unsupported SOFn types }
+      M_SOF3,                     { Lossless, Huffman }
+      M_SOF5,                     { Differential sequential, Huffman }
+      M_SOF6,                     { Differential progressive, Huffman }
+      M_SOF7,                     { Differential lossless, Huffman }
+      M_JPG,                      { Reserved for JPEG extensions }
+      M_SOF11,                    { Lossless, arithmetic }
+      M_SOF13,                    { Differential sequential, arithmetic }
+      M_SOF14,                    { Differential progressive, arithmetic }
+      M_SOF15:                    { Differential lossless, arithmetic }
+        ERREXIT1(j_common_ptr(cinfo), JERR_SOF_UNSUPPORTED, cinfo^.unread_marker);
+
+      M_SOS:
+        begin
+          if not get_sos(cinfo) then
+          begin
+            read_markers := JPEG_SUSPENDED;
+            exit;
+          end;
+          cinfo^.unread_marker := 0;       { processed the marker }
+          read_markers := JPEG_REACHED_SOS;
+          exit;
+        end;
+
+      M_EOI:
+        begin
+          {$IFDEF DEBUG}
+          TRACEMS(j_common_ptr(cinfo), 1, JTRC_EOI);
+          {$ENDIF}
+          cinfo^.unread_marker := 0;       { processed the marker }
+          read_markers := JPEG_REACHED_EOI;
+          exit;
+        end;
+
+      M_DAC:
+        if not get_dac(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_DHT:
+        if not get_dht(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_DQT:
+        if not get_dqt(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_DRI:
+        if not get_dri(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_APP0,
+      M_APP1,
+      M_APP2,
+      M_APP3,
+      M_APP4,
+      M_APP5,
+      M_APP6,
+      M_APP7,
+      M_APP8,
+      M_APP9,
+      M_APP10,
+      M_APP11,
+      M_APP12,
+      M_APP13,
+      M_APP14,
+      M_APP15:
+        if not my_marker_ptr(cinfo^.marker)^.
+                process_APPn[cinfo^.unread_marker - int(M_APP0)](cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_COM:
+        if not my_marker_ptr(cinfo^.marker)^.process_COM (cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      M_RST0,   { these are all parameterless }
+      M_RST1,
+      M_RST2,
+      M_RST3,
+      M_RST4,
+      M_RST5,
+      M_RST6,
+      M_RST7,
+      M_TEM:
+        {$IFDEF DEBUG}
+        TRACEMS1(j_common_ptr(cinfo), 1, JTRC_PARMLESS_MARKER,
+          cinfo^.unread_marker)
+        {$ENDIF}
+        ;
+
+      M_DNL:    { Ignore DNL ... perhaps the wrong thing }
+        if not skip_variable(cinfo) then
+        begin
+          read_markers := JPEG_SUSPENDED;
+          exit;
+        end;
+
+      else      { must be DHP, EXP, JPGn, or RESn }
+        { For now, we treat the reserved markers as fatal errors since they are
+          likely to be used to signal incompatible JPEG Part 3 extensions.
+          Once the JPEG 3 version-number marker is well defined, this code
+          ought to change! }
+        ERREXIT1(j_common_ptr(cinfo) , JERR_UNKNOWN_MARKER,
+          cinfo^.unread_marker);
+    end; { end of case }
+    { Successfully processed marker, so reset state variable }
+    cinfo^.unread_marker := 0;
+  Until false;
+end;  { read_markers }
+
+
+{ Read a restart marker, which is expected to appear next in the datastream;
+  if the marker is not there, take appropriate recovery action.
+  Returns FALSE if suspension is required.
+
+  This is called by the entropy decoder after it has read an appropriate
+  number of MCUs.  cinfo^.unread_marker may be nonzero if the entropy decoder
+  has already read a marker from the data source.  Under normal conditions
+  cinfo^.unread_marker will be reset to 0 before returning; if not reset,
+  it holds a marker which the decoder will be unable to read past. }
+
+{METHODDEF}
+function read_restart_marker (cinfo : j_decompress_ptr) :boolean;
+begin
+  { Obtain a marker unless we already did. }
+  { Note that next_marker will complain if it skips any data. }
+  if (cinfo^.unread_marker = 0) then
+  begin
+    if not next_marker(cinfo) then
+    begin
+      read_restart_marker := FALSE;
+      exit;
+    end;
+  end;
+
+  if (cinfo^.unread_marker = (int(M_RST0) + cinfo^.marker^.next_restart_num)) then
+  begin
+    { Normal case --- swallow the marker and let entropy decoder continue }
+    {$IFDEF DEBUG}
+    TRACEMS1(j_common_ptr(cinfo), 3, JTRC_RST,
+      cinfo^.marker^.next_restart_num);
+    {$ENDIF}
+    cinfo^.unread_marker := 0;
+  end
+  else
+  begin
+    { Uh-oh, the restart markers have been messed up. }
+    { Let the data source manager determine how to resync. }
+    if not cinfo^.src^.resync_to_restart(cinfo,
+              cinfo^.marker^.next_restart_num) then
+    begin
+      read_restart_marker := FALSE;
+      exit;
+    end;
+  end;
+
+  { Update next-restart state }
+  with cinfo^.marker^ do
+    next_restart_num := (next_restart_num + 1) and 7;
+
+  read_restart_marker := TRUE;
+end; { read_restart_marker }
+
+
+{ This is the default resync_to_restart method for data source managers
+  to use if they don't have any better approach.  Some data source managers
+  may be able to back up, or may have additional knowledge about the data
+  which permits a more intelligent recovery strategy; such managers would
+  presumably supply their own resync method.
+
+  read_restart_marker calls resync_to_restart if it finds a marker other than
+  the restart marker it was expecting.  (This code is *not* used unless
+  a nonzero restart interval has been declared.)  cinfo^.unread_marker is
+  the marker code actually found (might be anything, except 0 or FF).
+  The desired restart marker number (0..7) is passed as a parameter.
+  This routine is supposed to apply whatever error recovery strategy seems
+  appropriate in order to position the input stream to the next data segment.
+  Note that cinfo^.unread_marker is treated as a marker appearing before
+  the current data-source input point; usually it should be reset to zero
+  before returning.
+  Returns FALSE if suspension is required.
+
+  This implementation is substantially constrained by wanting to treat the
+  input as a data stream; this means we can't back up.  Therefore, we have
+  only the following actions to work with:
+    1. Simply discard the marker and let the entropy decoder resume at next
+       byte of file.
+    2. Read forward until we find another marker, discarding intervening
+       data.  (In theory we could look ahead within the current bufferload,
+       without having to discard data if we don't find the desired marker.
+       This idea is not implemented here, in part because it makes behavior
+       dependent on buffer size and chance buffer-boundary positions.)
+    3. Leave the marker unread (by failing to zero cinfo^.unread_marker).
+       This will cause the entropy decoder to process an empty data segment,
+       inserting dummy zeroes, and then we will reprocess the marker.
+
+  #2 is appropriate if we think the desired marker lies ahead, while #3 is
+  appropriate if the found marker is a future restart marker (indicating
+  that we have missed the desired restart marker, probably because it got
+  corrupted).
+  We apply #2 or #3 if the found marker is a restart marker no more than
+  two counts behind or ahead of the expected one.  We also apply #2 if the
+  found marker is not a legal JPEG marker code (it's certainly bogus data).
+  If the found marker is a restart marker more than 2 counts away, we do #1
+  (too much risk that the marker is erroneous; with luck we will be able to
+  resync at some future point).
+  For any valid non-restart JPEG marker, we apply #3.  This keeps us from
+  overrunning the end of a scan.  An implementation limited to single-scan
+  files might find it better to apply #2 for markers other than EOI, since
+  any other marker would have to be bogus data in that case. }
+
+
+{GLOBAL}
+function jpeg_resync_to_restart(cinfo : j_decompress_ptr;
+                                desired : int) : boolean;
+var
+  marker : int;
+  action : int;
+begin
+  marker := cinfo^.unread_marker;
+  //action := 1;     { never used }
+  { Always put up a warning. }
+  WARNMS2(j_common_ptr(cinfo), JWRN_MUST_RESYNC, marker, desired);
+
+  { Outer loop handles repeated decision after scanning forward. }
+  repeat
+    if (marker < int(M_SOF0)) then
+      action := 2                { invalid marker }
+    else
+      if (marker < int(M_RST0)) or (marker > int(M_RST7)) then
+        action := 3                { valid non-restart marker }
+      else
+      begin
+        if (marker = (int(M_RST0) + ((desired+1) and 7))) or
+           (marker = (int(M_RST0) + ((desired+2) and 7))) then
+          action := 3              { one of the next two expected restarts }
+        else
+          if (marker = (int(M_RST0) + ((desired-1) and 7))) or
+             (marker = (int(M_RST0) + ((desired-2) and 7))) then
+            action := 2            { a prior restart, so advance }
+          else
+            action := 1;           { desired restart or too far away }
+      end;
+
+    {$IFDEF DEBUG}
+    TRACEMS2(j_common_ptr(cinfo), 4, JTRC_RECOVERY_ACTION, marker, action);
+    {$ENDIF}
+    case action of
+    1:
+      { Discard marker and let entropy decoder resume processing. }
+      begin
+        cinfo^.unread_marker := 0;
+        jpeg_resync_to_restart := TRUE;
+        exit;
+      end;
+    2:
+      { Scan to the next marker, and repeat the decision loop. }
+      begin
+        if not next_marker(cinfo) then
+        begin
+          jpeg_resync_to_restart := FALSE;
+          exit;
+        end;
+        marker := cinfo^.unread_marker;
+      end;
+    3:
+      { Return without advancing past this marker. }
+      { Entropy decoder will be forced to process an empty segment. }
+      begin
+        jpeg_resync_to_restart := TRUE;
+        exit;
+      end;
+    end; { case }
+  Until false; { end loop }
+end;  { jpeg_resync_to_restart }
+
+
+{ Reset marker processing state to begin a fresh datastream. }
+
+{METHODDEF}
+procedure reset_marker_reader (cinfo : j_decompress_ptr);
+var
+  marker : my_marker_ptr;
+begin
+  marker := my_marker_ptr (cinfo^.marker);
+  with cinfo^ do
+  begin
+    comp_info := NIL;            { until allocated by get_sof }
+    input_scan_number := 0;      { no SOS seen yet }
+    unread_marker := 0;          { no pending marker }
+  end;
+  marker^.pub.saw_SOI := FALSE;    { set internal state too }
+  marker^.pub.saw_SOF := FALSE;
+  marker^.pub.discarded_bytes := 0;
+  marker^.cur_marker := NIL;
+end; { reset_marker_reader }
+
+
+{ Initialize the marker reader module.
+  This is called only once, when the decompression object is created. }
+
+{GLOBAL}
+procedure jinit_marker_reader (cinfo : j_decompress_ptr);
+var
+  marker : my_marker_ptr;
+  i : int;
+begin
+  { Create subobject in permanent pool }
+  marker := my_marker_ptr(
+     cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT,
+                             SIZEOF(my_marker_reader))
+                                    );
+  cinfo^.marker := jpeg_marker_reader_ptr(marker);
+  { Initialize method pointers }
+  marker^.pub.reset_marker_reader := reset_marker_reader;
+  marker^.pub.read_markers := read_markers;
+  marker^.pub.read_restart_marker := read_restart_marker;
+  { Initialize COM/APPn processing.
+    By default, we examine and then discard APP0 and APP14,
+    but simply discard COM and all other APPn. }
+
+  marker^.process_COM := skip_variable;
+  marker^.length_limit_COM := 0;
+  for i := 0 to 16-1 do
+  begin
+    marker^.process_APPn[i] := skip_variable;
+    marker^.length_limit_APPn[i] := 0;
+  end;
+  marker^.process_APPn[0] := get_interesting_appn;
+  marker^.process_APPn[14] := get_interesting_appn;
+  { Reset marker processing state }
+  reset_marker_reader(cinfo);
+end; { jinit_marker_reader }
+
+
+{ Control saving of COM and APPn markers into marker_list. }
+
+
+{$ifdef SAVE_MARKERS_SUPPORTED}
+
+{GLOBAL}
+procedure jpeg_save_markers (cinfo : j_decompress_ptr;
+                             marker_code : int;
+                 length_limit : uint);
+var
+  marker : my_marker_ptr;
+  maxlength : long;
+  processor : jpeg_marker_parser_method;
+begin
+  marker := my_marker_ptr (cinfo^.marker);
+
+  { Length limit mustn't be larger than what we can allocate
+    (should only be a concern in a 16-bit environment). }
+
+  maxlength := cinfo^.mem^.max_alloc_chunk - SIZEOF(jpeg_marker_struct);
+  if (long(length_limit) > maxlength) then
+    length_limit := uint(maxlength);
+
+  { Choose processor routine to use.
+    APP0/APP14 have special requirements. }
+
+  if (length_limit <> 0) then
+  begin
+    processor := save_marker;
+    { If saving APP0/APP14, save at least enough for our internal use. }
+    if (marker_code = int(M_APP0)) and (length_limit < APP0_DATA_LEN) then
+      length_limit := APP0_DATA_LEN
+    else
+      if (marker_code = int(M_APP14)) and (length_limit < APP14_DATA_LEN) then
+        length_limit := APP14_DATA_LEN;
+  end
+  else
+  begin
+    processor := skip_variable;
+    { If discarding APP0/APP14, use our regular on-the-fly processor. }
+    if (marker_code = int(M_APP0)) or (marker_code = int(M_APP14)) then
+      processor := get_interesting_appn;
+  end;
+
+  if (marker_code = int(M_COM)) then
+  begin
+    marker^.process_COM := processor;
+    marker^.length_limit_COM := length_limit;
+  end
+  else
+    if (marker_code >= int(M_APP0)) and (marker_code <= int(M_APP15)) then
+    begin
+      marker^.process_APPn[marker_code - int(M_APP0)] := processor;
+      marker^.length_limit_APPn[marker_code - int(M_APP0)] := length_limit;
+    end
+    else
+      ERREXIT1(j_common_ptr(cinfo), JERR_UNKNOWN_MARKER, marker_code);
+end;
+
+{$endif} { SAVE_MARKERS_SUPPORTED }
+
+{ Install a special processing method for COM or APPn markers. }
+
+{GLOBAL}
+
+procedure jpeg_set_marker_processor (cinfo : j_decompress_ptr;
+                                     marker_code : int;
+                   routine : jpeg_marker_parser_method);
+var
+  marker : my_marker_ptr;
+begin
+  marker := my_marker_ptr (cinfo^.marker);
+  if (marker_code = int(M_COM)) then
+    marker^.process_COM := routine
+  else
+    if (marker_code >= int(M_APP0)) and (marker_code <= int(M_APP15)) then
+      marker^.process_APPn[marker_code - int(M_APP0)] := routine
+    else
+      ERREXIT1(j_common_ptr(cinfo), JERR_UNKNOWN_MARKER, marker_code);
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdmaster.pas b/src/lib/vampimg/JpegLib/imjdmaster.pas
new file mode 100644 (file)
index 0000000..4f233a0
--- /dev/null
@@ -0,0 +1,679 @@
+unit imjdmaster;
+
+{ This file contains master control logic for the JPEG decompressor.
+  These routines are concerned with selecting the modules to be executed
+  and with determining the number of passes and the work to be done in each
+  pass. }
+
+{ Original: jdmaster.c ; Copyright (C) 1991-1998, Thomas G. Lane.  }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjutils,
+  imjerror,
+  imjdeferr,
+  imjdcolor, imjdsample, imjdpostct, imjddctmgr, imjdphuff,
+  imjdhuff, imjdcoefct, imjdmainct,
+{$ifdef QUANT_1PASS_SUPPORTED}
+  imjquant1,
+{$endif}
+{$ifdef QUANT_2PASS_SUPPORTED}
+  imjquant2,
+{$endif}
+{$ifdef UPSAMPLE_MERGING_SUPPORTED}
+  imjdmerge,
+{$endif}
+  imjpeglib;
+
+
+{ Compute output image dimensions and related values.
+  NOTE: this is exported for possible use by application.
+  Hence it mustn't do anything that can't be done twice.
+  Also note that it may be called before the master module is initialized! }
+
+{GLOBAL}
+procedure jpeg_calc_output_dimensions (cinfo : j_decompress_ptr);
+{ Do computations that are needed before master selection phase }
+
+
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+
+{GLOBAL}
+procedure jpeg_new_colormap (cinfo : j_decompress_ptr);
+
+{$endif}
+
+{ Initialize master decompression control and select active modules.
+  This is performed at the start of jpeg_start_decompress. }
+
+{GLOBAL}
+procedure jinit_master_decompress (cinfo : j_decompress_ptr);
+
+implementation
+
+{ Private state }
+
+type
+  my_master_ptr = ^my_decomp_master;
+  my_decomp_master = record
+    pub : jpeg_decomp_master; { public fields }
+
+    pass_number : int;    { # of passes completed }
+
+    using_merged_upsample : boolean; { TRUE if using merged upsample/cconvert }
+
+    { Saved references to initialized quantizer modules,
+      in case we need to switch modes. }
+
+    quantizer_1pass : jpeg_color_quantizer_ptr;
+    quantizer_2pass : jpeg_color_quantizer_ptr;
+  end;
+
+{ Determine whether merged upsample/color conversion should be used.
+  CRUCIAL: this must match the actual capabilities of jdmerge.c! }
+
+{LOCAL}
+function use_merged_upsample (cinfo : j_decompress_ptr) : boolean;
+var
+  compptr : jpeg_component_info_list_ptr;
+begin
+  compptr := cinfo^.comp_info;
+
+{$ifdef UPSAMPLE_MERGING_SUPPORTED}
+  { Merging is the equivalent of plain box-filter upsampling }
+  if (cinfo^.do_fancy_upsampling) or (cinfo^.CCIR601_sampling) then
+  begin
+    use_merged_upsample := FALSE;
+    exit;
+  end;
+  { jdmerge.c only supports YCC=>RGB color conversion }
+  if (cinfo^.jpeg_color_space <> JCS_YCbCr) or (cinfo^.num_components <> 3)
+  or (cinfo^.out_color_space <> JCS_RGB)
+  or (cinfo^.out_color_components <> RGB_PIXELSIZE) then
+  begin
+    use_merged_upsample := FALSE;
+    exit;
+  end;
+
+  { and it only handles 2h1v or 2h2v sampling ratios }
+  if (compptr^[0].h_samp_factor <> 2) or
+     (compptr^[1].h_samp_factor <> 1) or
+     (compptr^[2].h_samp_factor <> 1) or
+     (compptr^[0].v_samp_factor >  2) or
+     (compptr^[1].v_samp_factor <> 1) or
+     (compptr^[2].v_samp_factor <> 1) then
+  begin
+    use_merged_upsample := FALSE;
+    exit;
+  end;
+  { furthermore, it doesn't work if we've scaled the IDCTs differently }
+  if (compptr^[0].DCT_scaled_size <> cinfo^.min_DCT_scaled_size) or
+     (compptr^[1].DCT_scaled_size <> cinfo^.min_DCT_scaled_size) or
+     (compptr^[2].DCT_scaled_size <> cinfo^.min_DCT_scaled_size) then
+  begin
+    use_merged_upsample := FALSE;
+    exit;
+  end;
+  { ??? also need to test for upsample-time rescaling, when & if supported }
+  use_merged_upsample := TRUE;      { by golly, it'll work... }
+{$else}
+  use_merged_upsample := FALSE;
+{$endif}
+end;
+
+
+{ Compute output image dimensions and related values.
+  NOTE: this is exported for possible use by application.
+  Hence it mustn't do anything that can't be done twice.
+  Also note that it may be called before the master module is initialized! }
+
+{GLOBAL}
+procedure jpeg_calc_output_dimensions (cinfo : j_decompress_ptr);
+{ Do computations that are needed before master selection phase }
+{$ifdef IDCT_SCALING_SUPPORTED}
+var
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+{$endif}
+var
+  ssize : int;
+begin
+  { Prevent application from calling me at wrong times }
+  if (cinfo^.global_state <> DSTATE_READY) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+{$ifdef IDCT_SCALING_SUPPORTED}
+
+  { Compute actual output image dimensions and DCT scaling choices. }
+  if (cinfo^.scale_num * 8 <= cinfo^.scale_denom) then
+  begin
+    { Provide 1/8 scaling }
+    cinfo^.output_width := JDIMENSION (
+      jdiv_round_up( long(cinfo^.image_width), long(8)) );
+    cinfo^.output_height := JDIMENSION (
+      jdiv_round_up( long(cinfo^.image_height), long(8)) );
+    cinfo^.min_DCT_scaled_size := 1;
+  end
+  else
+    if (cinfo^.scale_num * 4 <= cinfo^.scale_denom) then
+    begin
+      { Provide 1/4 scaling }
+      cinfo^.output_width := JDIMENSION (
+        jdiv_round_up( long (cinfo^.image_width), long(4)) );
+      cinfo^.output_height := JDIMENSION (
+        jdiv_round_up( long (cinfo^.image_height), long(4)) );
+      cinfo^.min_DCT_scaled_size := 2;
+    end
+    else
+      if (cinfo^.scale_num * 2 <= cinfo^.scale_denom) then
+      begin
+        { Provide 1/2 scaling }
+        cinfo^.output_width := JDIMENSION (
+          jdiv_round_up( long(cinfo^.image_width), long(2)) );
+        cinfo^.output_height := JDIMENSION (
+          jdiv_round_up( long(cinfo^.image_height), long(2)) );
+        cinfo^.min_DCT_scaled_size := 4;
+      end
+      else
+      begin
+        { Provide 1/1 scaling }
+        cinfo^.output_width := cinfo^.image_width;
+        cinfo^.output_height := cinfo^.image_height;
+        cinfo^.min_DCT_scaled_size := DCTSIZE;
+      end;
+  { In selecting the actual DCT scaling for each component, we try to
+    scale up the chroma components via IDCT scaling rather than upsampling.
+    This saves time if the upsampler gets to use 1:1 scaling.
+    Note this code assumes that the supported DCT scalings are powers of 2. }
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    ssize := cinfo^.min_DCT_scaled_size;
+    while (ssize < DCTSIZE) and
+    ((compptr^.h_samp_factor * ssize * 2 <=
+      cinfo^.max_h_samp_factor * cinfo^.min_DCT_scaled_size) and
+     (compptr^.v_samp_factor * ssize * 2 <=
+      cinfo^.max_v_samp_factor * cinfo^.min_DCT_scaled_size)) do
+    begin
+      ssize := ssize * 2;
+    end;
+    compptr^.DCT_scaled_size := ssize;
+    Inc(compptr);
+  end;
+
+  { Recompute downsampled dimensions of components;
+    application needs to know these if using raw downsampled data. }
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Size in samples, after IDCT scaling }
+    compptr^.downsampled_width := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_width) *
+        long (compptr^.h_samp_factor * compptr^.DCT_scaled_size),
+        long (cinfo^.max_h_samp_factor * DCTSIZE)) );
+    compptr^.downsampled_height := JDIMENSION (
+      jdiv_round_up(long (cinfo^.image_height) *
+        long (compptr^.v_samp_factor * compptr^.DCT_scaled_size),
+        long (cinfo^.max_v_samp_factor * DCTSIZE)) );
+    Inc(compptr);
+  end;
+
+{$else} { !IDCT_SCALING_SUPPORTED }
+
+  { Hardwire it to "no scaling" }
+  cinfo^.output_width := cinfo^.image_width;
+  cinfo^.output_height := cinfo^.image_height;
+  { jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
+    and has computed unscaled downsampled_width and downsampled_height. }
+
+{$endif} { IDCT_SCALING_SUPPORTED }
+
+  { Report number of components in selected colorspace. }
+  { Probably this should be in the color conversion module... }
+  case (cinfo^.out_color_space) of
+  JCS_GRAYSCALE:
+    cinfo^.out_color_components := 1;
+{$ifndef RGB_PIXELSIZE_IS_3}
+  JCS_RGB:
+    cinfo^.out_color_components := RGB_PIXELSIZE;
+{$else}
+  JCS_RGB,
+{$endif} { else share code with YCbCr }
+  JCS_YCbCr:
+    cinfo^.out_color_components := 3;
+  JCS_CMYK,
+  JCS_YCCK:
+    cinfo^.out_color_components := 4;
+  else      { else must be same colorspace as in file }
+    cinfo^.out_color_components := cinfo^.num_components;
+  end;
+  if (cinfo^.quantize_colors) then
+    cinfo^.output_components := 1
+  else
+    cinfo^.output_components := cinfo^.out_color_components;
+
+  { See if upsampler will want to emit more than one row at a time }
+  if (use_merged_upsample(cinfo)) then
+    cinfo^.rec_outbuf_height := cinfo^.max_v_samp_factor
+  else
+    cinfo^.rec_outbuf_height := 1;
+end;
+
+
+{ Several decompression processes need to range-limit values to the range
+  0..MAXJSAMPLE; the input value may fall somewhat outside this range
+  due to noise introduced by quantization, roundoff error, etc.  These
+  processes are inner loops and need to be as fast as possible.  On most
+  machines, particularly CPUs with pipelines or instruction prefetch,
+  a (subscript-check-less) C table lookup
+    x := sample_range_limit[x];
+  is faster than explicit tests
+    if (x < 0)  x := 0;
+    else if (x > MAXJSAMPLE)  x := MAXJSAMPLE;
+  These processes all use a common table prepared by the routine below.
+
+  For most steps we can mathematically guarantee that the initial value
+  of x is within MAXJSAMPLE+1 of the legal range, so a table running from
+  -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient.  But for the initial
+  limiting step (just after the IDCT), a wildly out-of-range value is
+  possible if the input data is corrupt.  To avoid any chance of indexing
+  off the end of memory and getting a bad-pointer trap, we perform the
+  post-IDCT limiting thus:
+    x := range_limit[x & MASK];
+  where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
+  samples.  Under normal circumstances this is more than enough range and
+  a correct output will be generated; with bogus input data the mask will
+  cause wraparound, and we will safely generate a bogus-but-in-range output.
+  For the post-IDCT step, we want to convert the data from signed to unsigned
+  representation by adding CENTERJSAMPLE at the same time that we limit it.
+  So the post-IDCT limiting table ends up looking like this:
+    CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
+    MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+    0          (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+    0,1,...,CENTERJSAMPLE-1
+  Negative inputs select values from the upper half of the table after
+  masking.
+
+  We can save some space by overlapping the start of the post-IDCT table
+  with the simpler range limiting table.  The post-IDCT table begins at
+  sample_range_limit + CENTERJSAMPLE.
+
+  Note that the table is allocated in near data space on PCs; it's small
+  enough and used often enough to justify this. }
+
+{LOCAL}
+procedure prepare_range_limit_table (cinfo : j_decompress_ptr);
+{ Allocate and fill in the sample_range_limit table }
+var
+  table : range_limit_table_ptr;
+  idct_table : JSAMPROW;
+  i : int;
+begin
+  table := range_limit_table_ptr (
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+    (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)) );
+
+  { First segment of "simple" table: limit[x] := 0 for x < 0 }
+  MEMZERO(table, (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+
+  cinfo^.sample_range_limit := (table);
+  { allow negative subscripts of simple table }
+  { is noop, handled via type definition (Nomssi) }
+  { Main part of "simple" table: limit[x] := x }
+  for i := 0 to MAXJSAMPLE do
+    table^[i] := JSAMPLE (i);
+  idct_table := JSAMPROW(@ table^[CENTERJSAMPLE]);
+                        { Point to where post-IDCT table starts }
+  { End of simple table, rest of first half of post-IDCT table }
+  for i := CENTERJSAMPLE to pred(2*(MAXJSAMPLE+1)) do
+    idct_table^[i] := MAXJSAMPLE;
+  { Second half of post-IDCT table }
+  MEMZERO(@(idct_table^[2 * (MAXJSAMPLE+1)]),
+    (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+  MEMCOPY(@(idct_table^[(4 * (MAXJSAMPLE+1) - CENTERJSAMPLE)]),
+    @cinfo^.sample_range_limit^[0], CENTERJSAMPLE * SIZEOF(JSAMPLE));
+
+end;
+
+
+{ Master selection of decompression modules.
+  This is done once at jpeg_start_decompress time.  We determine
+  which modules will be used and give them appropriate initialization calls.
+  We also initialize the decompressor input side to begin consuming data.
+
+  Since jpeg_read_header has finished, we know what is in the SOF
+  and (first) SOS markers.  We also have all the application parameter
+  settings. }
+
+{LOCAL}
+procedure master_selection (cinfo : j_decompress_ptr);
+var
+  master : my_master_ptr;
+  use_c_buffer : boolean;
+  samplesperrow : long;
+  jd_samplesperrow : JDIMENSION;
+var
+  nscans : int;
+begin
+  master := my_master_ptr (cinfo^.master);
+
+  { Initialize dimensions and other stuff }
+  jpeg_calc_output_dimensions(cinfo);
+  prepare_range_limit_table(cinfo);
+
+  { Width of an output scanline must be representable as JDIMENSION. }
+  samplesperrow := long(cinfo^.output_width) * long (cinfo^.out_color_components);
+  jd_samplesperrow := JDIMENSION (samplesperrow);
+  if (long(jd_samplesperrow) <> samplesperrow) then
+    ERREXIT(j_common_ptr(cinfo), JERR_WIDTH_OVERFLOW);
+
+  { Initialize my private state }
+  master^.pass_number := 0;
+  master^.using_merged_upsample := use_merged_upsample(cinfo);
+
+  { Color quantizer selection }
+  master^.quantizer_1pass := NIL;
+  master^.quantizer_2pass := NIL;
+  { No mode changes if not using buffered-image mode. }
+  if (not cinfo^.quantize_colors) or (not cinfo^.buffered_image) then
+  begin
+    cinfo^.enable_1pass_quant := FALSE;
+    cinfo^.enable_external_quant := FALSE;
+    cinfo^.enable_2pass_quant := FALSE;
+  end;
+  if (cinfo^.quantize_colors) then
+  begin
+    if (cinfo^.raw_data_out) then
+      ERREXIT(j_common_ptr(cinfo), JERR_NOTIMPL);
+    { 2-pass quantizer only works in 3-component color space. }
+    if (cinfo^.out_color_components <> 3) then
+    begin
+      cinfo^.enable_1pass_quant := TRUE;
+      cinfo^.enable_external_quant := FALSE;
+      cinfo^.enable_2pass_quant := FALSE;
+      cinfo^.colormap := NIL;
+    end
+    else
+      if (cinfo^.colormap <> NIL) then
+      begin
+        cinfo^.enable_external_quant := TRUE;
+      end
+      else
+        if (cinfo^.two_pass_quantize) then
+        begin
+          cinfo^.enable_2pass_quant := TRUE;
+        end
+        else
+        begin
+          cinfo^.enable_1pass_quant := TRUE;
+        end;
+
+    if (cinfo^.enable_1pass_quant) then
+    begin
+{$ifdef QUANT_1PASS_SUPPORTED}
+      jinit_1pass_quantizer(cinfo);
+      master^.quantizer_1pass := cinfo^.cquantize;
+{$else}
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+    end;
+
+    { We use the 2-pass code to map to external colormaps. }
+    if (cinfo^.enable_2pass_quant) or (cinfo^.enable_external_quant) then
+    begin
+{$ifdef QUANT_2PASS_SUPPORTED}
+      jinit_2pass_quantizer(cinfo);
+      master^.quantizer_2pass := cinfo^.cquantize;
+{$else}
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+    end;
+    { If both quantizers are initialized, the 2-pass one is left active;
+      this is necessary for starting with quantization to an external map. }
+  end;
+
+  { Post-processing: in particular, color conversion first }
+  if (not cinfo^.raw_data_out) then
+  begin
+    if (master^.using_merged_upsample) then
+    begin
+{$ifdef UPSAMPLE_MERGING_SUPPORTED}
+      jinit_merged_upsampler(cinfo); { does color conversion too }
+{$else}
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+    end
+    else
+    begin
+      jinit_color_deconverter(cinfo);
+      jinit_upsampler(cinfo);
+    end;
+    jinit_d_post_controller(cinfo, cinfo^.enable_2pass_quant);
+  end;
+  { Inverse DCT }
+  jinit_inverse_dct(cinfo);
+  { Entropy decoding: either Huffman or arithmetic coding. }
+  if (cinfo^.arith_code) then
+  begin
+    ERREXIT(j_common_ptr(cinfo), JERR_ARITH_NOTIMPL);
+  end
+  else
+  begin
+    if (cinfo^.progressive_mode) then
+    begin
+{$ifdef D_PROGRESSIVE_SUPPORTED}
+      jinit_phuff_decoder(cinfo);
+{$else}
+      ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif}
+    end
+    else
+      jinit_huff_decoder(cinfo);
+  end;
+
+  { Initialize principal buffer controllers. }
+  use_c_buffer := cinfo^.inputctl^.has_multiple_scans or cinfo^.buffered_image;
+  jinit_d_coef_controller(cinfo, use_c_buffer);
+
+  if (not cinfo^.raw_data_out) then
+    jinit_d_main_controller(cinfo, FALSE { never need full buffer here });
+
+  { We can now tell the memory manager to allocate virtual arrays. }
+  cinfo^.mem^.realize_virt_arrays (j_common_ptr(cinfo));
+
+  { Initialize input side of decompressor to consume first scan. }
+  cinfo^.inputctl^.start_input_pass (cinfo);
+
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+  { If jpeg_start_decompress will read the whole file, initialize
+    progress monitoring appropriately.  The input step is counted
+    as one pass. }
+
+  if (cinfo^.progress <> NIL) and (not cinfo^.buffered_image) and
+     (cinfo^.inputctl^.has_multiple_scans) then
+  begin
+
+    { Estimate number of scans to set pass_limit. }
+    if (cinfo^.progressive_mode) then
+    begin
+      { Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. }
+      nscans := 2 + 3 * cinfo^.num_components;
+    end
+    else
+    begin
+      { For a nonprogressive multiscan file, estimate 1 scan per component. }
+      nscans := cinfo^.num_components;
+    end;
+    cinfo^.progress^.pass_counter := Long(0);
+    cinfo^.progress^.pass_limit := long (cinfo^.total_iMCU_rows) * nscans;
+    cinfo^.progress^.completed_passes := 0;
+    if cinfo^.enable_2pass_quant then
+      cinfo^.progress^.total_passes := 3
+    else
+      cinfo^.progress^.total_passes := 2;
+    { Count the input pass as done }
+    Inc(master^.pass_number);
+  end;
+{$endif} { D_MULTISCAN_FILES_SUPPORTED }
+end;
+
+
+{ Per-pass setup.
+  This is called at the beginning of each output pass.  We determine which
+  modules will be active during this pass and give them appropriate
+  start_pass calls.  We also set is_dummy_pass to indicate whether this
+  is a "real" output pass or a dummy pass for color quantization.
+  (In the latter case, jdapistd.c will crank the pass to completion.) }
+
+{METHODDEF}
+procedure prepare_for_output_pass (cinfo : j_decompress_ptr);
+var
+  master : my_master_ptr;
+begin
+  master := my_master_ptr (cinfo^.master);
+
+  if (master^.pub.is_dummy_pass) then
+  begin
+{$ifdef QUANT_2PASS_SUPPORTED}
+    { Final pass of 2-pass quantization }
+    master^.pub.is_dummy_pass := FALSE;
+    cinfo^.cquantize^.start_pass (cinfo, FALSE);
+    cinfo^.post^.start_pass (cinfo, JBUF_CRANK_DEST);
+    cinfo^.main^.start_pass (cinfo, JBUF_CRANK_DEST);
+{$else}
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+{$endif} { QUANT_2PASS_SUPPORTED }
+  end
+  else
+  begin
+    if (cinfo^.quantize_colors) and (cinfo^.colormap = NIL) then
+    begin
+      { Select new quantization method }
+      if (cinfo^.two_pass_quantize) and (cinfo^.enable_2pass_quant) then
+      begin
+  cinfo^.cquantize := master^.quantizer_2pass;
+  master^.pub.is_dummy_pass := TRUE;
+      end
+      else
+        if (cinfo^.enable_1pass_quant) then
+        begin
+    cinfo^.cquantize := master^.quantizer_1pass;
+        end
+        else
+        begin
+    ERREXIT(j_common_ptr(cinfo), JERR_MODE_CHANGE);
+        end;
+    end;
+    cinfo^.idct^.start_pass (cinfo);
+    cinfo^.coef^.start_output_pass (cinfo);
+    if (not cinfo^.raw_data_out) then
+    begin
+      if (not master^.using_merged_upsample) then
+  cinfo^.cconvert^.start_pass (cinfo);
+      cinfo^.upsample^.start_pass (cinfo);
+      if (cinfo^.quantize_colors) then
+  cinfo^.cquantize^.start_pass (cinfo, master^.pub.is_dummy_pass);
+      if master^.pub.is_dummy_pass  then
+        cinfo^.post^.start_pass (cinfo, JBUF_SAVE_AND_PASS)
+      else
+        cinfo^.post^.start_pass (cinfo, JBUF_PASS_THRU);
+      cinfo^.main^.start_pass (cinfo, JBUF_PASS_THRU);
+    end;
+  end;
+
+  { Set up progress monitor's pass info if present }
+  if (cinfo^.progress <> NIL) then
+  begin
+    cinfo^.progress^.completed_passes := master^.pass_number;
+    if master^.pub.is_dummy_pass then
+      cinfo^.progress^.total_passes := master^.pass_number + 2
+    else
+      cinfo^.progress^.total_passes := master^.pass_number + 1;
+    { In buffered-image mode, we assume one more output pass if EOI not
+      yet reached, but no more passes if EOI has been reached. }
+
+    if (cinfo^.buffered_image) and (not cinfo^.inputctl^.eoi_reached) then
+    begin
+      if cinfo^.enable_2pass_quant then
+        Inc(cinfo^.progress^.total_passes, 2)
+      else
+        Inc(cinfo^.progress^.total_passes, 1);
+    end;
+  end;
+end;
+
+
+{ Finish up at end of an output pass. }
+
+{METHODDEF}
+procedure finish_output_pass (cinfo : j_decompress_ptr);
+var
+  master : my_master_ptr;
+begin
+  master := my_master_ptr (cinfo^.master);
+
+  if (cinfo^.quantize_colors) then
+    cinfo^.cquantize^.finish_pass (cinfo);
+  Inc(master^.pass_number);
+end;
+
+
+{$ifdef D_MULTISCAN_FILES_SUPPORTED}
+
+{ Switch to a new external colormap between output passes. }
+
+{GLOBAL}
+procedure jpeg_new_colormap (cinfo : j_decompress_ptr);
+var
+  master : my_master_ptr;
+begin
+  master := my_master_ptr (cinfo^.master);
+
+  { Prevent application from calling me at wrong times }
+  if (cinfo^.global_state <> DSTATE_BUFIMAGE) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state);
+
+  if (cinfo^.quantize_colors) and (cinfo^.enable_external_quant) and
+     (cinfo^.colormap <> NIL) then
+  begin
+    { Select 2-pass quantizer for external colormap use }
+    cinfo^.cquantize := master^.quantizer_2pass;
+    { Notify quantizer of colormap change }
+    cinfo^.cquantize^.new_color_map (cinfo);
+    master^.pub.is_dummy_pass := FALSE; { just in case }
+  end
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_MODE_CHANGE);
+end;
+
+{$endif} { D_MULTISCAN_FILES_SUPPORTED }
+
+
+{ Initialize master decompression control and select active modules.
+  This is performed at the start of jpeg_start_decompress. }
+
+{GLOBAL}
+procedure jinit_master_decompress (cinfo : j_decompress_ptr);
+var
+  master : my_master_ptr;
+begin
+  master := my_master_ptr (
+      cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+          SIZEOF(my_decomp_master)) );
+  cinfo^.master := jpeg_decomp_master_ptr(master);
+  master^.pub.prepare_for_output_pass := prepare_for_output_pass;
+  master^.pub.finish_output_pass := finish_output_pass;
+
+  master^.pub.is_dummy_pass := FALSE;
+
+  master_selection(cinfo);
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdmerge.pas b/src/lib/vampimg/JpegLib/imjdmerge.pas
new file mode 100644 (file)
index 0000000..a99d195
--- /dev/null
@@ -0,0 +1,514 @@
+unit imjdmerge;
+
+{  This file contains code for merged upsampling/color conversion.
+
+  This file combines functions from jdsample.c and jdcolor.c;
+  read those files first to understand what's going on.
+
+  When the chroma components are to be upsampled by simple replication
+  (ie, box filtering), we can save some work in color conversion by
+  calculating all the output pixels corresponding to a pair of chroma
+  samples at one time.  In the conversion equations
+  R := Y           + K1 * Cr
+  G := Y + K2 * Cb + K3 * Cr
+  B := Y + K4 * Cb
+  only the Y term varies among the group of pixels corresponding to a pair
+  of chroma samples, so the rest of the terms can be calculated just once.
+  At typical sampling ratios, this eliminates half or three-quarters of the
+  multiplications needed for color conversion.
+
+  This file currently provides implementations for the following cases:
+  YCbCr => RGB color conversion only.
+  Sampling ratios of 2h1v or 2h2v.
+  No scaling needed at upsample time.
+  Corner-aligned (non-CCIR601) sampling alignment.
+  Other special cases could be added, but in most applications these are
+  the only common cases.  (For uncommon cases we fall back on the more
+  general code in jdsample.c and jdcolor.c.) }
+
+{ Original: jdmerge.c ;  Copyright (C) 1994-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjutils;
+
+{ Module initialization routine for merged upsampling/color conversion.
+
+  NB: this is called under the conditions determined by use_merged_upsample()
+  in jdmaster.c.  That routine MUST correspond to the actual capabilities
+  of this module; no safety checks are made here. }
+
+{GLOBAL}
+procedure jinit_merged_upsampler (cinfo : j_decompress_ptr);
+
+implementation
+
+
+{ Private subobject }
+
+type  { the same definition as in JdColor }
+  int_Color_Table = array[0..MAXJSAMPLE+1-1] of int;
+  int_CConvertPtr = ^int_Color_Table;
+  INT32_Color_Table = array[0..MAXJSAMPLE+1-1] of INT32;
+  INT32_CConvertPtr = ^INT32_Color_Table;
+
+type
+  my_upsample_ptr = ^my_upsampler;
+    my_upsampler = record
+    pub : jpeg_upsampler; { public fields }
+
+    { Pointer to routine to do actual upsampling/conversion of one row group }
+    upmethod : procedure (cinfo : j_decompress_ptr;
+        input_buf : JSAMPIMAGE;
+                          in_row_group_ctr : JDIMENSION;
+        output_buf : JSAMPARRAY);
+
+    { Private state for YCC->RGB conversion }
+    Cr_r_tab : int_CConvertPtr;   { => table for Cr to R conversion }
+    Cb_b_tab : int_CConvertPtr;   { => table for Cb to B conversion }
+    Cr_g_tab : INT32_CConvertPtr; { => table for Cr to G conversion }
+    Cb_g_tab : INT32_CConvertPtr; { => table for Cb to G conversion }
+
+    { For 2:1 vertical sampling, we produce two output rows at a time.
+      We need a "spare" row buffer to hold the second output row if the
+      application provides just a one-row buffer; we also use the spare
+      to discard the dummy last row if the image height is odd. }
+
+    spare_row : JSAMPROW;
+    spare_full : boolean;   { TRUE if spare buffer is occupied }
+
+    out_row_width : JDIMENSION; { samples per output row }
+    rows_to_go : JDIMENSION;  { counts rows remaining in image }
+  end; {my_upsampler;}
+
+
+const
+  SCALEBITS = 16; { speediest right-shift on some machines }
+  ONE_HALF  = (INT32(1) shl (SCALEBITS-1));
+
+
+{ Initialize tables for YCC->RGB colorspace conversion.
+  This is taken directly from jdcolor.c; see that file for more info. }
+
+{LOCAL}
+procedure build_ycc_rgb_table (cinfo : j_decompress_ptr);
+const
+  FIX_1_40200 = INT32( Round(1.40200 * (INT32(1) shl SCALEBITS)) );
+  FIX_1_77200 = INT32( Round(1.77200 * (INT32(1) shl SCALEBITS)) );
+  FIX_0_71414 = INT32( Round(0.71414 * (INT32(1) shl SCALEBITS)) );
+  FIX_0_34414 = INT32( Round(0.34414 * (INT32(1) shl SCALEBITS)) );
+var
+  upsample : my_upsample_ptr;
+  i : int;
+  x : INT32;
+var
+  shift_temp : INT32;
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+
+  upsample^.Cr_r_tab := int_CConvertPtr (
+    cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(int)) );
+  upsample^.Cb_b_tab := int_CConvertPtr (
+    cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(int)) );
+  upsample^.Cr_g_tab := INT32_CConvertPtr (
+    cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(INT32)) );
+  upsample^.Cb_g_tab := INT32_CConvertPtr (
+    cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
+        (MAXJSAMPLE+1) * SIZEOF(INT32)) );
+
+  x := -CENTERJSAMPLE;
+  for i := 0 to pred(MAXJSAMPLE) do
+  begin
+    { i is the actual input pixel value, in the range 0..MAXJSAMPLE }
+    { The Cb or Cr value we are thinking of is x := i - CENTERJSAMPLE }
+    { Cr=>R value is nearest int to 1.40200 * x }
+    {upsample^.Cr_r_tab^[i] := int(
+        RIGHT_SHIFT(FIX_1_40200 * x + ONE_HALF, SCALEBITS) );}
+    shift_temp := FIX_1_40200  * x + ONE_HALF;
+    if shift_temp < 0 then  { SHIFT arithmetic RIGHT }
+      upsample^.Cr_r_tab^[i] := int((shift_temp shr SCALEBITS)
+                             or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      upsample^.Cr_r_tab^[i] := int(shift_temp shr SCALEBITS);
+
+
+    { Cb=>B value is nearest int to 1.77200 * x }
+    {upsample^.Cb_b_tab^[i] := int(
+        RIGHT_SHIFT(FIX_1_77200 * x + ONE_HALF, SCALEBITS) );}
+    shift_temp := FIX_1_77200 * x + ONE_HALF;
+    if shift_temp < 0 then  { SHIFT arithmetic RIGHT }
+      upsample^.Cb_b_tab^[i] := int((shift_temp shr SCALEBITS)
+                             or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      upsample^.Cb_b_tab^[i] := int(shift_temp shr SCALEBITS);
+
+    { Cr=>G value is scaled-up -0.71414 * x }
+    upsample^.Cr_g_tab^[i] := (- FIX_0_71414) * x;
+    { Cb=>G value is scaled-up -0.34414 * x }
+    { We also add in ONE_HALF so that need not do it in inner loop }
+    upsample^.Cb_g_tab^[i] := (- FIX_0_34414) * x + ONE_HALF;
+    Inc(x);
+  end;
+end;
+
+
+{ Initialize for an upsampling pass. }
+
+{METHODDEF}
+procedure start_pass_merged_upsample (cinfo : j_decompress_ptr);
+var
+  upsample : my_upsample_ptr;
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+
+  { Mark the spare buffer empty }
+  upsample^.spare_full := FALSE;
+  { Initialize total-height counter for detecting bottom of image }
+  upsample^.rows_to_go := cinfo^.output_height;
+end;
+
+
+{ Control routine to do upsampling (and color conversion).
+
+  The control routine just handles the row buffering considerations. }
+
+{METHODDEF}
+procedure merged_2v_upsample (cinfo : j_decompress_ptr;
+                  input_buf : JSAMPIMAGE;
+                              var in_row_group_ctr : JDIMENSION;
+                              in_row_groups_avail : JDIMENSION;
+                              output_buf : JSAMPARRAY;
+                              var out_row_ctr : JDIMENSION;
+                              out_rows_avail : JDIMENSION);
+{ 2:1 vertical sampling case: may need a spare row. }
+var
+  upsample : my_upsample_ptr;
+  work_ptrs : array[0..2-1] of JSAMPROW;
+  num_rows : JDIMENSION;    { number of rows returned to caller }
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+
+  if (upsample^.spare_full) then
+  begin
+    { If we have a spare row saved from a previous cycle, just return it. }
+    jcopy_sample_rows(JSAMPARRAY(@upsample^.spare_row),
+                      0,
+                      JSAMPARRAY(@ output_buf^[out_row_ctr]),
+                      0, 1, upsample^.out_row_width);
+    num_rows := 1;
+    upsample^.spare_full := FALSE;
+  end
+  else
+  begin
+    { Figure number of rows to return to caller. }
+    num_rows := 2;
+    { Not more than the distance to the end of the image. }
+    if (num_rows > upsample^.rows_to_go) then
+      num_rows := upsample^.rows_to_go;
+    { And not more than what the client can accept: }
+    Dec(out_rows_avail, {var} out_row_ctr);
+    if (num_rows > out_rows_avail) then
+      num_rows := out_rows_avail;
+    { Create output pointer array for upsampler. }
+    work_ptrs[0] := output_buf^[out_row_ctr];
+    if (num_rows > 1) then
+    begin
+      work_ptrs[1] := output_buf^[out_row_ctr + 1];
+    end
+    else
+    begin
+      work_ptrs[1] := upsample^.spare_row;
+      upsample^.spare_full := TRUE;
+    end;
+    { Now do the upsampling. }
+    upsample^.upmethod (cinfo, input_buf, {var}in_row_group_ctr,
+                        JSAMPARRAY(@work_ptrs));
+  end;
+
+  { Adjust counts }
+  Inc(out_row_ctr, num_rows);
+  Dec(upsample^.rows_to_go, num_rows);
+  { When the buffer is emptied, declare this input row group consumed }
+  if (not upsample^.spare_full) then
+    Inc(in_row_group_ctr);
+end;
+
+
+{METHODDEF}
+procedure merged_1v_upsample (cinfo : j_decompress_ptr;
+                 input_buf : JSAMPIMAGE;
+                             var in_row_group_ctr : JDIMENSION;
+                 in_row_groups_avail : JDIMENSION;
+                 output_buf : JSAMPARRAY;
+                             var out_row_ctr : JDIMENSION;
+                 out_rows_avail : JDIMENSION);
+{ 1:1 vertical sampling case: much easier, never need a spare row. }
+var
+  upsample : my_upsample_ptr;
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+
+  { Just do the upsampling. }
+  upsample^.upmethod (cinfo, input_buf, in_row_group_ctr,
+       JSAMPARRAY(@ output_buf^[out_row_ctr]));
+  { Adjust counts }
+  Inc(out_row_ctr);
+  Inc(in_row_group_ctr);
+end;
+
+
+{ These are the routines invoked by the control routines to do
+  the actual upsampling/conversion.  One row group is processed per call.
+
+  Note: since we may be writing directly into application-supplied buffers,
+  we have to be honest about the output width; we can't assume the buffer
+  has been rounded up to an even width. }
+
+
+{ Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. }
+
+{METHODDEF}
+procedure h2v1_merged_upsample (cinfo : j_decompress_ptr;
+                    input_buf : JSAMPIMAGE;
+                                in_row_group_ctr : JDIMENSION;
+                    output_buf : JSAMPARRAY);
+var
+  upsample : my_upsample_ptr;
+  {register} y, cred, cgreen, cblue : int;
+  cb, cr : int;
+  {register}  outptr : JSAMPROW;
+  inptr0, inptr1, inptr2 : JSAMPLE_PTR;
+  col : JDIMENSION;
+  { copy these pointers into registers if possible }
+  {register} range_limit : range_limit_table_ptr;
+  Crrtab : int_CConvertPtr;
+  Cbbtab : int_CConvertPtr;
+  Crgtab : INT32_CConvertPtr;
+  Cbgtab : INT32_CConvertPtr;
+var
+  shift_temp : INT32;
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+  range_limit := cinfo^.sample_range_limit;
+  Crrtab := upsample^.Cr_r_tab;
+  Cbbtab := upsample^.Cb_b_tab;
+  Crgtab := upsample^.Cr_g_tab;
+  Cbgtab := upsample^.Cb_g_tab;
+
+  inptr0 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr]);
+  inptr1 := JSAMPLE_PTR(input_buf^[1]^[in_row_group_ctr]);
+  inptr2 := JSAMPLE_PTR(input_buf^[2]^[in_row_group_ctr]);
+  outptr := output_buf^[0];
+  { Loop for each pair of output pixels }
+  for col := pred(cinfo^.output_width shr 1) downto 0 do
+  begin
+    { Do the chroma part of the calculation }
+    cb := GETJSAMPLE(inptr1^);
+    Inc(inptr1);
+    cr := GETJSAMPLE(inptr2^);
+    Inc(inptr2);
+    cred := Crrtab^[cr];
+    {cgreen := int( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );}
+    shift_temp := Cbgtab^[cb] + Crgtab^[cr];
+    if shift_temp < 0 then   { SHIFT arithmetic RIGHT }
+      cgreen := int((shift_temp shr SCALEBITS)
+                            or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      cgreen := int(shift_temp shr SCALEBITS);
+
+    cblue := Cbbtab^[cb];
+    { Fetch 2 Y values and emit 2 pixels }
+    y  := GETJSAMPLE(inptr0^);
+    Inc(inptr0);
+    outptr^[RGB_RED] :=   range_limit^[y + cred];
+    outptr^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr^[RGB_BLUE] :=  range_limit^[y + cblue];
+    Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE);
+    y  := GETJSAMPLE(inptr0^);
+    Inc(inptr0);
+    outptr^[RGB_RED] :=   range_limit^[y + cred];
+    outptr^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr^[RGB_BLUE] :=  range_limit^[y + cblue];
+    Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE);
+  end;
+  { If image width is odd, do the last output column separately }
+  if Odd(cinfo^.output_width) then
+  begin
+    cb := GETJSAMPLE(inptr1^);
+    cr := GETJSAMPLE(inptr2^);
+    cred := Crrtab^[cr];
+    {cgreen := int ( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );}
+    shift_temp := Cbgtab^[cb] + Crgtab^[cr];
+    if shift_temp < 0 then   { SHIFT arithmetic RIGHT }
+      cgreen := int((shift_temp shr SCALEBITS)
+                            or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      cgreen := int(shift_temp shr SCALEBITS);
+
+    cblue := Cbbtab^[cb];
+    y  := GETJSAMPLE(inptr0^);
+    outptr^[RGB_RED] :=   range_limit^[y + cred];
+    outptr^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr^[RGB_BLUE] :=  range_limit^[y + cblue];
+  end;
+end;
+
+
+{ Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. }
+
+{METHODDEF}
+procedure h2v2_merged_upsample (cinfo : j_decompress_ptr;
+                    input_buf : JSAMPIMAGE;
+                                in_row_group_ctr : JDIMENSION;
+                    output_buf : JSAMPARRAY);
+var
+  upsample : my_upsample_ptr;
+  {register} y, cred, cgreen, cblue : int;
+  cb, cr : int;
+  {register} outptr0, outptr1 : JSAMPROW;
+  inptr00, inptr01, inptr1, inptr2 : JSAMPLE_PTR;
+  col : JDIMENSION;
+  { copy these pointers into registers if possible }
+  {register} range_limit : range_limit_table_ptr;
+  Crrtab : int_CConvertPtr;
+  Cbbtab : int_CConvertPtr;
+  Crgtab : INT32_CConvertPtr;
+  Cbgtab : INT32_CConvertPtr;
+var
+  shift_temp : INT32;
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+  range_limit := cinfo^.sample_range_limit;
+  Crrtab := upsample^.Cr_r_tab;
+  Cbbtab := upsample^.Cb_b_tab;
+  Crgtab := upsample^.Cr_g_tab;
+  Cbgtab := upsample^.Cb_g_tab;
+
+  inptr00 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr*2]);
+  inptr01 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr*2 + 1]);
+  inptr1 := JSAMPLE_PTR(input_buf^[1]^[in_row_group_ctr]);
+  inptr2 := JSAMPLE_PTR(input_buf^[2]^[in_row_group_ctr]);
+  outptr0 := output_buf^[0];
+  outptr1 := output_buf^[1];
+  { Loop for each group of output pixels }
+  for col := pred(cinfo^.output_width shr 1) downto 0 do
+  begin
+    { Do the chroma part of the calculation }
+    cb := GETJSAMPLE(inptr1^);
+    Inc(inptr1);
+    cr := GETJSAMPLE(inptr2^);
+    Inc(inptr2);
+    cred := Crrtab^[cr];
+    {cgreen := int( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );}
+    shift_temp := Cbgtab^[cb] + Crgtab^[cr];
+    if shift_temp < 0 then   { SHIFT arithmetic RIGHT }
+      cgreen := int((shift_temp shr SCALEBITS)
+                            or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      cgreen := int(shift_temp shr SCALEBITS);
+
+    cblue := Cbbtab^[cb];
+    { Fetch 4 Y values and emit 4 pixels }
+    y  := GETJSAMPLE(inptr00^);
+    Inc(inptr00);
+    outptr0^[RGB_RED] :=   range_limit^[y + cred];
+    outptr0^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr0^[RGB_BLUE] :=  range_limit^[y + cblue];
+    Inc(JSAMPLE_PTR(outptr0), RGB_PIXELSIZE);
+    y  := GETJSAMPLE(inptr00^);
+    Inc(inptr00);
+    outptr0^[RGB_RED] :=   range_limit^[y + cred];
+    outptr0^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr0^[RGB_BLUE] :=  range_limit^[y + cblue];
+    Inc(JSAMPLE_PTR(outptr0), RGB_PIXELSIZE);
+    y  := GETJSAMPLE(inptr01^);
+    Inc(inptr01);
+    outptr1^[RGB_RED] :=   range_limit^[y + cred];
+    outptr1^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr1^[RGB_BLUE] :=  range_limit^[y + cblue];
+    Inc(JSAMPLE_PTR(outptr1), RGB_PIXELSIZE);
+    y  := GETJSAMPLE(inptr01^);
+    Inc(inptr01);
+    outptr1^[RGB_RED] :=   range_limit^[y + cred];
+    outptr1^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr1^[RGB_BLUE] :=  range_limit^[y + cblue];
+    Inc(JSAMPLE_PTR(outptr1), RGB_PIXELSIZE);
+  end;
+  { If image width is odd, do the last output column separately }
+  if Odd(cinfo^.output_width) then
+  begin
+    cb := GETJSAMPLE(inptr1^);
+    cr := GETJSAMPLE(inptr2^);
+    cred := Crrtab^[cr];
+    {cgreen := int (RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS));}
+    shift_temp := Cbgtab^[cb] + Crgtab^[cr];
+    if shift_temp < 0 then   { SHIFT arithmetic RIGHT }
+      cgreen := int((shift_temp shr SCALEBITS)
+                            or ( (not INT32(0)) shl (32-SCALEBITS)))
+    else
+      cgreen := int(shift_temp shr SCALEBITS);
+
+    cblue := Cbbtab^[cb];
+    y  := GETJSAMPLE(inptr00^);
+    outptr0^[RGB_RED] :=   range_limit^[y + cred];
+    outptr0^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr0^[RGB_BLUE] :=  range_limit^[y + cblue];
+    y  := GETJSAMPLE(inptr01^);
+    outptr1^[RGB_RED] :=   range_limit^[y + cred];
+    outptr1^[RGB_GREEN] := range_limit^[y + cgreen];
+    outptr1^[RGB_BLUE] :=  range_limit^[y + cblue];
+  end;
+end;
+
+
+{ Module initialization routine for merged upsampling/color conversion.
+
+  NB: this is called under the conditions determined by use_merged_upsample()
+  in jdmaster.c.  That routine MUST correspond to the actual capabilities
+  of this module; no safety checks are made here. }
+
+
+{GLOBAL}
+procedure jinit_merged_upsampler (cinfo : j_decompress_ptr);
+var
+  upsample : my_upsample_ptr;
+begin
+  upsample := my_upsample_ptr (
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_upsampler)) );
+  cinfo^.upsample := jpeg_upsampler_ptr (upsample);
+  upsample^.pub.start_pass := start_pass_merged_upsample;
+  upsample^.pub.need_context_rows := FALSE;
+
+  upsample^.out_row_width := cinfo^.output_width * JDIMENSION(cinfo^.out_color_components);
+
+  if (cinfo^.max_v_samp_factor = 2) then
+  begin
+    upsample^.pub.upsample := merged_2v_upsample;
+    upsample^.upmethod := h2v2_merged_upsample;
+    { Allocate a spare row buffer }
+    upsample^.spare_row := JSAMPROW(
+      cinfo^.mem^.alloc_large ( j_common_ptr(cinfo), JPOOL_IMAGE,
+    size_t (upsample^.out_row_width * SIZEOF(JSAMPLE))) );
+  end
+  else
+  begin
+    upsample^.pub.upsample := merged_1v_upsample;
+    upsample^.upmethod := h2v1_merged_upsample;
+    { No spare row needed }
+    upsample^.spare_row := NIL;
+  end;
+
+  build_ycc_rgb_table(cinfo);
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdphuff.pas b/src/lib/vampimg/JpegLib/imjdphuff.pas
new file mode 100644 (file)
index 0000000..1ab53d2
--- /dev/null
@@ -0,0 +1,1061 @@
+unit imjdphuff;
+
+{ This file contains Huffman entropy decoding routines for progressive JPEG.
+
+  Much of the complexity here has to do with supporting input suspension.
+  If the data source module demands suspension, we want to be able to back
+  up to the start of the current MCU.  To do this, we copy state variables
+  into local working storage, and update them back to the permanent
+  storage only upon successful completion of an MCU. }
+
+{ Original: jdphuff.c ; Copyright (C) 1995-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjdhuff;   { Declarations shared with jdhuff.c }
+
+
+{GLOBAL}
+procedure jinit_phuff_decoder (cinfo : j_decompress_ptr);
+
+implementation
+
+{ Expanded entropy decoder object for progressive Huffman decoding.
+
+  The savable_state subrecord contains fields that change within an MCU,
+  but must not be updated permanently until we complete the MCU. }
+
+type
+  savable_state = record
+    EOBRUN : uInt;               { remaining EOBs in EOBRUN }
+    last_dc_val : array[00..MAX_COMPS_IN_SCAN-1] of int;
+                                 { last DC coef for each component }
+  end;
+
+
+type
+  phuff_entropy_ptr  = ^phuff_entropy_decoder;
+  phuff_entropy_decoder = record
+    pub : jpeg_entropy_decoder; { public fields }
+
+    { These fields are loaded into local variables at start of each MCU.
+      In case of suspension, we exit WITHOUT updating them. }
+
+    bitstate : bitread_perm_state;  { Bit buffer at start of MCU }
+    saved : savable_state;    { Other state at start of MCU }
+
+    { These fields are NOT loaded into local working state. }
+    restarts_to_go : uInt;              { MCUs left in this restart interval }
+
+    { Pointers to derived tables (these workspaces have image lifespan) }
+    derived_tbls : array[0..NUM_HUFF_TBLS-1] of d_derived_tbl_ptr;
+
+    ac_derived_tbl : d_derived_tbl_ptr; { active table during an AC scan }
+  end;
+
+
+
+{ Forward declarations }
+{METHODDEF}
+function decode_mcu_DC_first (cinfo : j_decompress_ptr;
+                              var MCU_data : array of JBLOCKROW) : boolean;
+                              forward;
+{METHODDEF}
+function decode_mcu_AC_first (cinfo : j_decompress_ptr;
+                              var MCU_data : array of JBLOCKROW) : boolean;
+                              forward;
+{METHODDEF}
+function decode_mcu_DC_refine (cinfo : j_decompress_ptr;
+                               var MCU_data : array of JBLOCKROW) : boolean;
+                               forward;
+{METHODDEF}
+function decode_mcu_AC_refine (cinfo : j_decompress_ptr;
+                               var MCU_data : array of JBLOCKROW) : boolean;
+                               forward;
+
+{ Initialize for a Huffman-compressed scan. }
+
+{METHODDEF}
+procedure start_pass_phuff_decoder (cinfo : j_decompress_ptr);
+var
+  entropy : phuff_entropy_ptr;
+  is_DC_band, bad : boolean;
+  ci, coefi, tbl : int;
+  coef_bit_ptr : coef_bits_ptr;
+  compptr : jpeg_component_info_ptr;
+var
+  cindex : int;
+  expected : int;
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+
+  is_DC_band := (cinfo^.Ss = 0);
+
+  { Validate scan parameters }
+  bad := FALSE;
+  if (is_DC_band) then
+  begin
+    if (cinfo^.Se <> 0) then
+      bad := TRUE;
+  end
+  else
+  begin
+    { need not check Ss/Se < 0 since they came from unsigned bytes }
+    if (cinfo^.Ss > cinfo^.Se) or (cinfo^.Se >= DCTSIZE2) then
+      bad := TRUE;
+    { AC scans may have only one component }
+    if (cinfo^.comps_in_scan <> 1) then
+      bad := TRUE;
+  end;
+  if (cinfo^.Ah <> 0) then
+  begin
+    { Successive approximation refinement scan: must have Al = Ah-1. }
+    if (cinfo^.Al <> cinfo^.Ah-1) then
+      bad := TRUE;
+  end;
+  if (cinfo^.Al > 13) then      { need not check for < 0 }
+    bad := TRUE;
+  { Arguably the maximum Al value should be less than 13 for 8-bit precision,
+    but the spec doesn't say so, and we try to be liberal about what we
+    accept.  Note: large Al values could result in out-of-range DC
+    coefficients during early scans, leading to bizarre displays due to
+    overflows in the IDCT math.  But we won't crash. }
+
+  if (bad) then
+    ERREXIT4(j_common_ptr(cinfo), JERR_BAD_PROGRESSION,
+       cinfo^.Ss, cinfo^.Se, cinfo^.Ah, cinfo^.Al);
+  { Update progression status, and verify that scan order is legal.
+    Note that inter-scan inconsistencies are treated as warnings
+    not fatal errors ... not clear if this is right way to behave. }
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    cindex := cinfo^.cur_comp_info[ci]^.component_index;
+    coef_bit_ptr := coef_bits_ptr(@(cinfo^.coef_bits^[cindex])); {^[0] ???
+                                                                   Nomssi    }
+    if (not is_DC_band) and (coef_bit_ptr^[0] < 0) then
+      { AC without prior DC scan }
+      WARNMS2(j_common_ptr(cinfo), JWRN_BOGUS_PROGRESSION, cindex, 0);
+    for coefi := cinfo^.Ss to cinfo^.Se do
+    begin
+      if (coef_bit_ptr^[coefi] < 0) then
+        expected :=  0
+      else
+        expected := coef_bit_ptr^[coefi];
+      if (cinfo^.Ah <> expected) then
+  WARNMS2(j_common_ptr(cinfo), JWRN_BOGUS_PROGRESSION, cindex, coefi);
+      coef_bit_ptr^[coefi] := cinfo^.Al;
+    end;
+  end;
+
+  { Select MCU decoding routine }
+  if (cinfo^.Ah = 0) then
+  begin
+    if (is_DC_band) then
+      entropy^.pub.decode_mcu := decode_mcu_DC_first
+    else
+      entropy^.pub.decode_mcu := decode_mcu_AC_first;
+  end
+  else
+  begin
+    if (is_DC_band) then
+      entropy^.pub.decode_mcu := decode_mcu_DC_refine
+    else
+      entropy^.pub.decode_mcu := decode_mcu_AC_refine;
+  end;
+
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+  begin
+    compptr := cinfo^.cur_comp_info[ci];
+    { Make sure requested tables are present, and compute derived tables.
+      We may build same derived table more than once, but it's not expensive. }
+
+    if (is_DC_band) then
+    begin
+      if (cinfo^.Ah = 0) then
+      begin { DC refinement needs no table }
+  tbl := compptr^.dc_tbl_no;
+  jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+         entropy^.derived_tbls[tbl]);
+      end;
+    end
+    else
+    begin
+      tbl := compptr^.ac_tbl_no;
+      jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+             entropy^.derived_tbls[tbl]);
+      { remember the single active table }
+      entropy^.ac_derived_tbl := entropy^.derived_tbls[tbl];
+    end;
+    { Initialize DC predictions to 0 }
+    entropy^.saved.last_dc_val[ci] := 0;
+  end;
+
+  { Initialize bitread state variables }
+  entropy^.bitstate.bits_left := 0;
+  entropy^.bitstate.get_buffer := 0; { unnecessary, but keeps Purify quiet }
+  entropy^.pub.insufficient_data := FALSE;
+
+  { Initialize private state variables }
+  entropy^.saved.EOBRUN := 0;
+
+  { Initialize restart counter }
+  entropy^.restarts_to_go := cinfo^.restart_interval;
+end;
+
+
+{ Figure F.12: extend sign bit.
+  On some machines, a shift and add will be faster than a table lookup. }
+
+{$ifdef AVOID_TABLES}
+
+#define HUFF_EXTEND(x,s)
+  ((x) < (1shl((s)-1)) ? (x) + (((-1)shl(s)) + 1) : (x))
+
+{$else}
+
+{ #define HUFF_EXTEND(x,s)
+  if (x) < extend_test[s] then
+    (x) + extend_offset[s]
+  else
+    (x)}
+
+const
+ extend_test : Array[0..16-1] of int =   { entry n is 2**(n-1) }
+   ($0000, $0001, $0002, $0004, $0008, $0010, $0020, $0040,
+    $0080, $0100, $0200, $0400, $0800, $1000, $2000, $4000);
+
+const
+  extend_offset : array[0..16-1] of int = { entry n is (-1 shl n) + 1 }
+  ( 0, ((-1) shl 1) + 1, ((-1) shl 2) + 1, ((-1) shl 3) + 1, ((-1) shl 4) + 1,
+    ((-1) shl 5) + 1, ((-1) shl 6) + 1, ((-1) shl 7) + 1, ((-1) shl 8) + 1,
+    ((-1) shl 9) + 1, ((-1) shl 10) + 1, ((-1) shl 11) + 1, ((-1) shl 12) + 1,
+    ((-1) shl 13) + 1, ((-1) shl 14) + 1, ((-1) shl 15) + 1 );
+
+{$endif} { AVOID_TABLES }
+
+
+{ Check for a restart marker & resynchronize decoder.
+  return:=s FALSE if must suspend. }
+
+{LOCAL}
+function process_restart (cinfo : j_decompress_ptr) : boolean;
+var
+  entropy : phuff_entropy_ptr;
+  ci : int;
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+
+  { Throw away any unused bits remaining in bit buffer; }
+  { include any full bytes in next_marker's count of discarded bytes }
+  Inc(cinfo^.marker^.discarded_bytes, entropy^.bitstate.bits_left div 8);
+  entropy^.bitstate.bits_left := 0;
+
+  { Advance past the RSTn marker }
+  if (not cinfo^.marker^.read_restart_marker (cinfo)) then
+  begin
+    process_restart := FALSE;
+    exit;
+  end;
+
+  { Re-initialize DC predictions to 0 }
+  for ci := 0 to pred(cinfo^.comps_in_scan) do
+    entropy^.saved.last_dc_val[ci] := 0;
+  { Re-init EOB run count, too }
+  entropy^.saved.EOBRUN := 0;
+
+  { Reset restart counter }
+  entropy^.restarts_to_go := cinfo^.restart_interval;
+
+  { Reset out-of-data flag, unless read_restart_marker left us smack up
+    against a marker.  In that case we will end up treating the next data
+    segment as empty, and we can avoid producing bogus output pixels by
+    leaving the flag set. }
+  if (cinfo^.unread_marker = 0) then
+    entropy^.pub.insufficient_data := FALSE;
+
+  process_restart := TRUE;
+end;
+
+
+{ Huffman MCU decoding.
+  Each of these routines decodes and returns one MCU's worth of
+  Huffman-compressed coefficients.
+  The coefficients are reordered from zigzag order into natural array order,
+  but are not dequantized.
+
+  The i'th block of the MCU is stored into the block pointed to by
+  MCU_data[i].  WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+
+  We return FALSE if data source requested suspension.  In that case no
+  changes have been made to permanent state.  (Exception: some output
+  coefficients may already have been assigned.  This is harmless for
+  spectral selection, since we'll just re-assign them on the next call.
+  Successive approximation AC refinement has to be more careful, however.) }
+
+
+{ MCU decoding for DC initial scan (either spectral selection,
+  or first pass of successive approximation). }
+
+{METHODDEF}
+function decode_mcu_DC_first (cinfo : j_decompress_ptr;
+                              var MCU_data : array of JBLOCKROW) : boolean;
+label
+  label1;
+var
+  entropy : phuff_entropy_ptr;
+  Al : int;
+  {register} s, r : int;
+  blkn, ci : int;
+  block : JBLOCK_PTR;
+  {BITREAD_STATE_VARS;}
+  get_buffer : bit_buf_type ; {register}
+  bits_left : int; {register}
+  br_state : bitread_working_state;
+
+  state : savable_state;
+  tbl : d_derived_tbl_ptr;
+  compptr : jpeg_component_info_ptr;
+var
+  nb, look : int; {register}
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+  Al := cinfo^.Al;
+
+  { Process restart marker if needed; may have to suspend }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+      if (not process_restart(cinfo)) then
+      begin
+  decode_mcu_DC_first := FALSE;
+        exit;
+      end;
+  end;
+
+  { If we've run out of data, just leave the MCU set to zeroes.
+    This way, we return uniform gray for the remainder of the segment. }
+
+  if not entropy^.pub.insufficient_data then
+  begin
+
+    { Load up working state }
+    {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);}
+    br_state.cinfo := cinfo;
+    br_state.next_input_byte := cinfo^.src^.next_input_byte;
+    br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer;
+    get_buffer := entropy^.bitstate.get_buffer;
+    bits_left := entropy^.bitstate.bits_left;
+
+    {ASSIGN_STATE(state, entropy^.saved);}
+    state := entropy^.saved;
+
+    { Outer loop handles each block in the MCU }
+
+    for blkn := 0 to pred(cinfo^.blocks_in_MCU) do
+    begin
+      block := JBLOCK_PTR(MCU_data[blkn]);
+      ci := cinfo^.MCU_membership[blkn];
+      compptr := cinfo^.cur_comp_info[ci];
+      tbl := entropy^.derived_tbls[compptr^.dc_tbl_no];
+
+      { Decode a single block's worth of coefficients }
+
+      { Section F.2.2.1: decode the DC coefficient difference }
+      {HUFF_DECODE(s, br_state, tbl, return FALSE, label1);}
+      if (bits_left < HUFF_LOOKAHEAD) then
+      begin
+        if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then
+        begin
+          decode_mcu_DC_first := FALSE;
+          exit;
+        end;
+        get_buffer := br_state.get_buffer;
+        bits_left := br_state.bits_left;
+        if (bits_left < HUFF_LOOKAHEAD) then
+        begin
+          nb := 1;
+          goto label1;
+        end;
+      end;
+      {look := PEEK_BITS(HUFF_LOOKAHEAD);}
+      look := int(get_buffer shr (bits_left -  HUFF_LOOKAHEAD)) and
+                     pred(1 shl HUFF_LOOKAHEAD);
+
+      nb := tbl^.look_nbits[look];
+      if (nb <> 0) then
+      begin
+        {DROP_BITS(nb);}
+        Dec(bits_left, nb);
+
+        s := tbl^.look_sym[look];
+      end
+      else
+      begin
+        nb := HUFF_LOOKAHEAD+1;
+    label1:
+        s := jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb);
+        if (s < 0) then
+        begin
+          decode_mcu_DC_first := FALSE;
+          exit;
+        end;
+        get_buffer := br_state.get_buffer;
+        bits_left := br_state.bits_left;
+      end;
+
+      if (s <> 0) then
+      begin
+        {CHECK_BIT_BUFFER(br_state, s, return FALSE);}
+        if (bits_left < s) then
+        begin
+          if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then
+          begin
+            decode_mcu_DC_first := FALSE;
+            exit;
+          end;
+          get_buffer := br_state.get_buffer;
+          bits_left := br_state.bits_left;
+        end;
+
+        {r := GET_BITS(s);}
+        Dec(bits_left, s);
+        r := (int(get_buffer shr bits_left)) and ( pred(1 shl s) );
+
+        {s := HUFF_EXTEND(r, s);}
+        if (r < extend_test[s]) then
+          s := r + extend_offset[s]
+        else
+          s := r;
+      end;
+
+      { Convert DC difference to actual value, update last_dc_val }
+      Inc(s, state.last_dc_val[ci]);
+      state.last_dc_val[ci] := s;
+      { Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) }
+      block^[0] := JCOEF (s shl Al);
+    end;
+
+    { Completed MCU, so update state }
+    {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);}
+    cinfo^.src^.next_input_byte := br_state.next_input_byte;
+    cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer;
+    entropy^.bitstate.get_buffer := get_buffer;
+    entropy^.bitstate.bits_left := bits_left;
+
+    {ASSIGN_STATE(entropy^.saved, state);}
+    entropy^.saved := state;
+  end;
+
+  { Account for restart interval (no-op if not using restarts) }
+  Dec(entropy^.restarts_to_go);
+
+  decode_mcu_DC_first := TRUE;
+end;
+
+
+{ MCU decoding for AC initial scan (either spectral selection,
+  or first pass of successive approximation). }
+
+{METHODDEF}
+function decode_mcu_AC_first (cinfo : j_decompress_ptr;
+                              var MCU_data : array of JBLOCKROW) : boolean;
+label
+  label2;
+var
+  entropy : phuff_entropy_ptr;
+  Se : int;
+  Al : int;
+  {register} s, k, r : int;
+  EOBRUN : uInt;
+  block : JBLOCK_PTR;
+  {BITREAD_STATE_VARS;}
+  get_buffer : bit_buf_type ; {register}
+  bits_left : int; {register}
+  br_state : bitread_working_state;
+
+  tbl : d_derived_tbl_ptr;
+var
+  nb, look : int; {register}
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+  Se := cinfo^.Se;
+  Al := cinfo^.Al;
+
+  { Process restart marker if needed; may have to suspend }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+      if (not process_restart(cinfo)) then
+      begin
+  decode_mcu_AC_first := FALSE;
+        exit;
+      end;
+  end;
+
+  { If we've run out of data, just leave the MCU set to zeroes.
+    This way, we return uniform gray for the remainder of the segment. }
+  if not entropy^.pub.insufficient_data then
+  begin
+
+    { Load up working state.
+      We can avoid loading/saving bitread state if in an EOB run. }
+
+    EOBRUN := entropy^.saved.EOBRUN; { only part of saved state we care about }
+
+    { There is always only one block per MCU }
+
+    if (EOBRUN > 0) then       { if it's a band of zeroes... }
+      Dec(EOBRUN)              { ...process it now (we do nothing) }
+    else
+    begin
+      {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);}
+      br_state.cinfo := cinfo;
+      br_state.next_input_byte := cinfo^.src^.next_input_byte;
+      br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer;
+      get_buffer := entropy^.bitstate.get_buffer;
+      bits_left := entropy^.bitstate.bits_left;
+
+      block := JBLOCK_PTR(MCU_data[0]);
+      tbl := entropy^.ac_derived_tbl;
+
+      k := cinfo^.Ss;
+      while (k <= Se) do
+      begin
+        {HUFF_DECODE(s, br_state, tbl, return FALSE, label2);}
+        if (bits_left < HUFF_LOOKAHEAD) then
+        begin
+          if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then
+          begin
+            decode_mcu_AC_first := FALSE;
+            exit;
+          end;
+          get_buffer := br_state.get_buffer;
+          bits_left := br_state.bits_left;
+          if (bits_left < HUFF_LOOKAHEAD) then
+          begin
+            nb := 1;
+            goto label2;
+          end;
+        end;
+        {look := PEEK_BITS(HUFF_LOOKAHEAD);}
+        look := int(get_buffer shr (bits_left -  HUFF_LOOKAHEAD)) and
+                       pred(1 shl HUFF_LOOKAHEAD);
+
+        nb := tbl^.look_nbits[look];
+        if (nb <> 0) then
+        begin
+          {DROP_BITS(nb);}
+          Dec(bits_left, nb);
+
+          s := tbl^.look_sym[look];
+        end
+        else
+        begin
+          nb := HUFF_LOOKAHEAD+1;
+      label2:
+          s := jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb);
+          if (s < 0) then
+          begin
+            decode_mcu_AC_first := FALSE;
+            exit;
+          end;
+          get_buffer := br_state.get_buffer;
+          bits_left := br_state.bits_left;
+        end;
+
+        r := s shr 4;
+        s := s and 15;
+        if (s <> 0) then
+        begin
+          Inc(k, r);
+          {CHECK_BIT_BUFFER(br_state, s, return FALSE);}
+          if (bits_left < s) then
+          begin
+            if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then
+            begin
+              decode_mcu_AC_first := FALSE;
+              exit;
+            end;
+            get_buffer := br_state.get_buffer;
+            bits_left := br_state.bits_left;
+          end;
+
+          {r := GET_BITS(s);}
+          Dec(bits_left, s);
+          r := (int(get_buffer shr bits_left)) and ( pred(1 shl s) );
+
+          {s := HUFF_EXTEND(r, s);}
+          if (r < extend_test[s]) then
+            s := r + extend_offset[s]
+          else
+            s := r;
+
+    { Scale and output coefficient in natural (dezigzagged) order }
+          block^[jpeg_natural_order[k]] := JCOEF (s shl Al);
+        end
+        else
+        begin
+          if (r = 15) then
+          begin   { ZRL }
+            Inc(k, 15); { skip 15 zeroes in band }
+          end
+          else
+          begin   { EOBr, run length is 2^r + appended bits }
+            EOBRUN := 1 shl r;
+            if (r <> 0) then
+            begin   { EOBr, r > 0 }
+        {CHECK_BIT_BUFFER(br_state, r, return FALSE);}
+              if (bits_left < r) then
+              begin
+                if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,r)) then
+                begin
+                  decode_mcu_AC_first := FALSE;
+                  exit;
+                end;
+                get_buffer := br_state.get_buffer;
+                bits_left := br_state.bits_left;
+              end;
+
+              {r := GET_BITS(r);}
+              Dec(bits_left, r);
+              r := (int(get_buffer shr bits_left)) and ( pred(1 shl r) );
+
+              Inc(EOBRUN, r);
+            end;
+      Dec(EOBRUN);          { this band is processed at this moment }
+      break;                { force end-of-band }
+    end;
+        end;
+        Inc(k);
+      end;
+
+      {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);}
+      cinfo^.src^.next_input_byte := br_state.next_input_byte;
+      cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer;
+      entropy^.bitstate.get_buffer := get_buffer;
+      entropy^.bitstate.bits_left := bits_left;
+    end;
+
+    { Completed MCU, so update state }
+    entropy^.saved.EOBRUN := EOBRUN; { only part of saved state we care about }
+  end;
+
+  { Account for restart interval (no-op if not using restarts) }
+  Dec(entropy^.restarts_to_go);
+
+  decode_mcu_AC_first := TRUE;
+end;
+
+
+{ MCU decoding for DC successive approximation refinement scan.
+  Note: we assume such scans can be multi-component, although the spec
+  is not very clear on the point. }
+
+{METHODDEF}
+function decode_mcu_DC_refine (cinfo : j_decompress_ptr;
+                               var MCU_data : array of JBLOCKROW) : boolean;
+
+var
+  entropy : phuff_entropy_ptr;
+  p1 : int;          { 1 in the bit position being coded }
+  blkn : int;
+  block : JBLOCK_PTR;
+  {BITREAD_STATE_VARS;}
+  get_buffer : bit_buf_type ; {register}
+  bits_left : int; {register}
+  br_state : bitread_working_state;
+begin
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+  p1 := 1 shl cinfo^.Al;
+
+  { Process restart marker if needed; may have to suspend }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+      if (not process_restart(cinfo)) then
+      begin
+  decode_mcu_DC_refine := FALSE;
+        exit;
+      end;
+  end;
+
+  { Not worth the cycles to check insufficient_data here,
+    since we will not change the data anyway if we read zeroes. }
+
+  { Load up working state }
+  {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);}
+  br_state.cinfo := cinfo;
+  br_state.next_input_byte := cinfo^.src^.next_input_byte;
+  br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer;
+  get_buffer := entropy^.bitstate.get_buffer;
+  bits_left := entropy^.bitstate.bits_left;
+
+  { Outer loop handles each block in the MCU }
+
+  for blkn := 0 to pred(cinfo^.blocks_in_MCU) do
+  begin
+    block := JBLOCK_PTR(MCU_data[blkn]);
+
+    { Encoded data is simply the next bit of the two's-complement DC value }
+    {CHECK_BIT_BUFFER(br_state, 1, return FALSE);}
+    if (bits_left < 1) then
+    begin
+      if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then
+      begin
+        decode_mcu_DC_refine := FALSE;
+        exit;
+      end;
+      get_buffer := br_state.get_buffer;
+      bits_left := br_state.bits_left;
+    end;
+
+    {if (GET_BITS(1)) then}
+    Dec(bits_left);
+    if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) ) <> 0 then
+      block^[0] := block^[0] or p1;
+    { Note: since we use OR, repeating the assignment later is safe }
+  end;
+
+  { Completed MCU, so update state }
+  {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);}
+  cinfo^.src^.next_input_byte := br_state.next_input_byte;
+  cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer;
+  entropy^.bitstate.get_buffer := get_buffer;
+  entropy^.bitstate.bits_left := bits_left;
+
+  { Account for restart interval (no-op if not using restarts) }
+  Dec(entropy^.restarts_to_go);
+
+  decode_mcu_DC_refine := TRUE;
+end;
+
+
+{ MCU decoding for AC successive approximation refinement scan. }
+
+{METHODDEF}
+function decode_mcu_AC_refine (cinfo : j_decompress_ptr;
+                               var MCU_data : array of JBLOCKROW) : boolean;
+label
+  undoit, label3;
+var
+  entropy : phuff_entropy_ptr;
+  Se : int;
+  p1 : int;     { 1 in the bit position being coded }
+  m1 : int;     { -1 in the bit position being coded }
+  {register} s, k, r : int;
+  EOBRUN : uInt;
+  block : JBLOCK_PTR;
+  thiscoef : JCOEF_PTR;
+  {BITREAD_STATE_VARS;}
+  get_buffer : bit_buf_type ; {register}
+  bits_left : int; {register}
+  br_state : bitread_working_state;
+
+  tbl : d_derived_tbl_ptr;
+  num_newnz : int;
+  newnz_pos : array[0..DCTSIZE2-1] of int;
+var
+  pos : int;
+var
+  nb, look : int; {register}
+begin
+  num_newnz := 0;
+  block := nil;
+
+  entropy := phuff_entropy_ptr (cinfo^.entropy);
+  Se := cinfo^.Se;
+  p1 := 1 shl cinfo^.Al;  { 1 in the bit position being coded }
+  m1 := (-1) shl cinfo^.Al; { -1 in the bit position being coded }
+
+  { Process restart marker if needed; may have to suspend }
+  if (cinfo^.restart_interval <> 0) then
+  begin
+    if (entropy^.restarts_to_go = 0) then
+      if (not process_restart(cinfo)) then
+      begin
+  decode_mcu_AC_refine := FALSE;
+        exit;
+      end;
+  end;
+
+  { If we've run out of data, don't modify the MCU. }
+  if not entropy^.pub.insufficient_data then
+  begin
+
+    { Load up working state }
+    {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);}
+    br_state.cinfo := cinfo;
+    br_state.next_input_byte := cinfo^.src^.next_input_byte;
+    br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer;
+    get_buffer := entropy^.bitstate.get_buffer;
+    bits_left := entropy^.bitstate.bits_left;
+
+    EOBRUN := entropy^.saved.EOBRUN; { only part of saved state we care about }
+
+    { There is always only one block per MCU }
+    block := JBLOCK_PTR(MCU_data[0]);
+    tbl := entropy^.ac_derived_tbl;
+
+    { If we are forced to suspend, we must undo the assignments to any newly
+      nonzero coefficients in the block, because otherwise we'd get confused
+      next time about which coefficients were already nonzero.
+      But we need not undo addition of bits to already-nonzero coefficients;
+      instead, we can test the current bit position to see if we already did it.}
+
+    num_newnz := 0;
+
+    { initialize coefficient loop counter to start of band }
+    k := cinfo^.Ss;
+
+    if (EOBRUN = 0) then
+    begin
+      while (k <= Se) do
+      begin
+        {HUFF_DECODE(s, br_state, tbl, goto undoit, label3);}
+        if (bits_left < HUFF_LOOKAHEAD) then
+        begin
+          if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then
+            goto undoit;
+          get_buffer := br_state.get_buffer;
+          bits_left := br_state.bits_left;
+          if (bits_left < HUFF_LOOKAHEAD) then
+          begin
+            nb := 1;
+            goto label3;
+          end;
+        end;
+        {look := PEEK_BITS(HUFF_LOOKAHEAD);}
+        look := int(get_buffer shr (bits_left -  HUFF_LOOKAHEAD)) and
+                       pred(1 shl HUFF_LOOKAHEAD);
+
+        nb := tbl^.look_nbits[look];
+        if (nb <> 0) then
+        begin
+          {DROP_BITS(nb);}
+          Dec(bits_left, nb);
+
+          s := tbl^.look_sym[look];
+        end
+        else
+        begin
+          nb := HUFF_LOOKAHEAD+1;
+      label3:
+          s := jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb);
+          if (s < 0) then
+            goto undoit;
+          get_buffer := br_state.get_buffer;
+          bits_left := br_state.bits_left;
+        end;
+
+        r := s shr 4;
+        s := s and 15;
+        if (s <> 0) then
+        begin
+    if (s <> 1) then  { size of new coef should always be 1 }
+      WARNMS(j_common_ptr(cinfo), JWRN_HUFF_BAD_CODE);
+          {CHECK_BIT_BUFFER(br_state, 1, goto undoit);}
+          if (bits_left < 1) then
+          begin
+            if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then
+              goto undoit;
+            get_buffer := br_state.get_buffer;
+            bits_left := br_state.bits_left;
+          end;
+
+          {if (GET_BITS(1)) then}
+          Dec(bits_left);
+          if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) )<>0 then
+      s := p1   { newly nonzero coef is positive }
+    else
+      s := m1;    { newly nonzero coef is negative }
+        end
+        else
+        begin
+    if (r <> 15) then
+          begin
+      EOBRUN := 1 shl r;  { EOBr, run length is 2^r + appended bits }
+      if (r <> 0) then
+            begin
+        {CHECK_BIT_BUFFER(br_state, r, goto undoit);}
+              if (bits_left < r) then
+              begin
+                if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,r)) then
+                  goto undoit;
+                get_buffer := br_state.get_buffer;
+                bits_left := br_state.bits_left;
+              end;
+
+        {r := GET_BITS(r);}
+              Dec(bits_left, r);
+              r := (int(get_buffer shr bits_left)) and ( pred(1 shl r) );
+
+        Inc(EOBRUN, r);
+      end;
+      break;    { rest of block is handled by EOB logic }
+    end;
+    { note s := 0 for processing ZRL }
+        end;
+        { Advance over already-nonzero coefs and r still-zero coefs,
+          appending correction bits to the nonzeroes.  A correction bit is 1
+          if the absolute value of the coefficient must be increased. }
+
+        repeat
+    thiscoef :=@(block^[jpeg_natural_order[k]]);
+    if (thiscoef^ <> 0) then
+          begin
+      {CHECK_BIT_BUFFER(br_state, 1, goto undoit);}
+            if (bits_left < 1) then
+            begin
+              if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then
+                goto undoit;
+              get_buffer := br_state.get_buffer;
+              bits_left := br_state.bits_left;
+            end;
+
+      {if (GET_BITS(1)) then}
+            Dec(bits_left);
+            if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) )<>0 then
+            begin
+        if ((thiscoef^ and p1) = 0) then
+              begin { do nothing if already set it }
+          if (thiscoef^ >= 0) then
+      Inc(thiscoef^, p1)
+          else
+      Inc(thiscoef^, m1);
+        end;
+      end;
+    end
+          else
+          begin
+            Dec(r);
+      if (r < 0) then
+        break;    { reached target zero coefficient }
+    end;
+    Inc(k);
+        until (k > Se);
+        if (s <> 0) then
+        begin
+    pos := jpeg_natural_order[k];
+    { Output newly nonzero coefficient }
+    block^[pos] := JCOEF (s);
+    { Remember its position in case we have to suspend }
+    newnz_pos[num_newnz] := pos;
+          Inc(num_newnz);
+        end;
+        Inc(k);
+      end;
+    end;
+
+    if (EOBRUN > 0) then
+    begin
+      { Scan any remaining coefficient positions after the end-of-band
+        (the last newly nonzero coefficient, if any).  Append a correction
+        bit to each already-nonzero coefficient.  A correction bit is 1
+        if the absolute value of the coefficient must be increased. }
+
+      while (k <= Se) do
+      begin
+        thiscoef := @(block^[jpeg_natural_order[k]]);
+        if (thiscoef^ <> 0) then
+        begin
+    {CHECK_BIT_BUFFER(br_state, 1, goto undoit);}
+          if (bits_left < 1) then
+          begin
+            if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then
+              goto undoit;
+            get_buffer := br_state.get_buffer;
+            bits_left := br_state.bits_left;
+          end;
+
+    {if (GET_BITS(1)) then}
+          Dec(bits_left);
+          if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) )<>0 then
+          begin
+      if ((thiscoef^ and p1) = 0) then
+            begin { do nothing if already changed it }
+        if (thiscoef^ >= 0) then
+          Inc(thiscoef^, p1)
+        else
+          Inc(thiscoef^, m1);
+      end;
+    end;
+        end;
+        Inc(k);
+      end;
+      { Count one block completed in EOB run }
+      Dec(EOBRUN);
+    end;
+
+    { Completed MCU, so update state }
+    {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);}
+    cinfo^.src^.next_input_byte := br_state.next_input_byte;
+    cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer;
+    entropy^.bitstate.get_buffer := get_buffer;
+    entropy^.bitstate.bits_left := bits_left;
+
+    entropy^.saved.EOBRUN := EOBRUN; { only part of saved state we care about }
+  end;
+
+  { Account for restart interval (no-op if not using restarts) }
+  Dec(entropy^.restarts_to_go);
+
+  decode_mcu_AC_refine := TRUE;
+  exit;
+
+undoit:
+  { Re-zero any output coefficients that we made newly nonzero }
+  while (num_newnz > 0) do
+  begin
+    Dec(num_newnz);
+    block^[newnz_pos[num_newnz]] := 0;
+  end;
+
+  decode_mcu_AC_refine := FALSE;
+end;
+
+
+{ Module initialization routine for progressive Huffman entropy decoding. }
+
+{GLOBAL}
+procedure jinit_phuff_decoder (cinfo : j_decompress_ptr);
+var
+  entropy : phuff_entropy_ptr;
+  coef_bit_ptr : int_ptr;
+  ci, i : int;
+begin
+  entropy := phuff_entropy_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE,
+        SIZEOF(phuff_entropy_decoder)) );
+  cinfo^.entropy := jpeg_entropy_decoder_ptr (entropy);
+  entropy^.pub.start_pass := start_pass_phuff_decoder;
+
+  { Mark derived tables unallocated }
+  for i := 0 to pred(NUM_HUFF_TBLS) do
+  begin
+    entropy^.derived_tbls[i] := NIL;
+  end;
+
+  { Create progression status table }
+  cinfo^.coef_bits := coef_bits_ptrrow (
+     cinfo^.mem^.alloc_small ( j_common_ptr (cinfo), JPOOL_IMAGE,
+        cinfo^.num_components*DCTSIZE2*SIZEOF(int)) );
+  coef_bit_ptr := @cinfo^.coef_bits^[0][0];
+  for ci := 0 to pred(cinfo^.num_components) do
+    for i := 0 to pred(DCTSIZE2) do
+    begin
+      coef_bit_ptr^ := -1;
+      Inc(coef_bit_ptr);
+    end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdpostct.pas b/src/lib/vampimg/JpegLib/imjdpostct.pas
new file mode 100644 (file)
index 0000000..8769550
--- /dev/null
@@ -0,0 +1,341 @@
+unit imjdpostct;
+
+{ Original: jdpostct.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+{ This file contains the decompression postprocessing controller.
+  This controller manages the upsampling, color conversion, and color
+  quantization/reduction steps; specifically, it controls the buffering
+  between upsample/color conversion and color quantization/reduction.
+
+  If no color quantization/reduction is required, then this module has no
+  work to do, and it just hands off to the upsample/color conversion code.
+  An integrated upsample/convert/quantize process would replace this module
+  entirely. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjpeglib;
+
+{ Initialize postprocessing controller. }
+
+{GLOBAL}
+procedure jinit_d_post_controller (cinfo : j_decompress_ptr;
+                                   need_full_buffer : boolean);
+implementation
+
+
+{ Private buffer controller object }
+
+type
+  my_post_ptr = ^my_post_controller;
+  my_post_controller = record
+    pub : jpeg_d_post_controller; { public fields }
+
+    { Color quantization source buffer: this holds output data from
+      the upsample/color conversion step to be passed to the quantizer.
+      For two-pass color quantization, we need a full-image buffer;
+      for one-pass operation, a strip buffer is sufficient. }
+
+    whole_image : jvirt_sarray_ptr;   { virtual array, or NIL if one-pass }
+    buffer : JSAMPARRAY;    { strip buffer, or current strip of virtual }
+    strip_height : JDIMENSION;  { buffer size in rows }
+    { for two-pass mode only: }
+    starting_row : JDIMENSION;  { row # of first row in current strip }
+    next_row : JDIMENSION;    { index of next row to fill/empty in strip }
+  end;
+
+{ Forward declarations }
+{METHODDEF}
+procedure post_process_1pass(cinfo : j_decompress_ptr;
+                 input_buf : JSAMPIMAGE;
+                             var in_row_group_ctr : JDIMENSION;
+                 in_row_groups_avail : JDIMENSION;
+                 output_buf : JSAMPARRAY;
+                             var out_row_ctr : JDIMENSION;
+                 out_rows_avail : JDIMENSION); forward;
+{$ifdef QUANT_2PASS_SUPPORTED}
+{METHODDEF}
+procedure post_process_prepass(cinfo : j_decompress_ptr;
+                   input_buf : JSAMPIMAGE;
+                               var in_row_group_ctr : JDIMENSION;
+                   in_row_groups_avail : JDIMENSION;
+                   output_buf : JSAMPARRAY;
+                               var out_row_ctr : JDIMENSION;
+                   out_rows_avail : JDIMENSION);  forward;
+{METHODDEF}
+procedure post_process_2pass(cinfo : j_decompress_ptr;
+                 input_buf : JSAMPIMAGE;
+                             var in_row_group_ctr : JDIMENSION;
+                 in_row_groups_avail : JDIMENSION;
+                 output_buf : JSAMPARRAY;
+                             var out_row_ctr : JDIMENSION;
+                 out_rows_avail : JDIMENSION);  forward;
+{$endif}
+
+
+{ Initialize for a processing pass. }
+
+{METHODDEF}
+procedure start_pass_dpost (cinfo : j_decompress_ptr;
+                            pass_mode : J_BUF_MODE);
+var
+  post : my_post_ptr;
+begin
+  post := my_post_ptr(cinfo^.post);
+
+  case (pass_mode) of
+  JBUF_PASS_THRU:
+    if (cinfo^.quantize_colors) then
+    begin
+      { Single-pass processing with color quantization. }
+      post^.pub.post_process_data := post_process_1pass;
+      { We could be doing buffered-image output before starting a 2-pass
+        color quantization; in that case, jinit_d_post_controller did not
+        allocate a strip buffer.  Use the virtual-array buffer as workspace. }
+      if (post^.buffer = NIL) then
+      begin
+  post^.buffer := cinfo^.mem^.access_virt_sarray
+    (j_common_ptr(cinfo), post^.whole_image,
+     JDIMENSION(0), post^.strip_height, TRUE);
+      end;
+    end
+    else
+    begin
+      { For single-pass processing without color quantization,
+        I have no work to do; just call the upsampler directly. }
+
+      post^.pub.post_process_data := cinfo^.upsample^.upsample;
+    end;
+
+{$ifdef QUANT_2PASS_SUPPORTED}
+  JBUF_SAVE_AND_PASS:
+    begin
+      { First pass of 2-pass quantization }
+      if (post^.whole_image = NIL) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+      post^.pub.post_process_data := post_process_prepass;
+    end;
+  JBUF_CRANK_DEST:
+    begin
+      { Second pass of 2-pass quantization }
+      if (post^.whole_image = NIL) then
+        ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+      post^.pub.post_process_data := post_process_2pass;
+    end;
+{$endif} { QUANT_2PASS_SUPPORTED }
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+  end;
+  post^.next_row := 0;
+  post^.starting_row := 0;
+end;
+
+
+{ Process some data in the one-pass (strip buffer) case.
+  This is used for color precision reduction as well as one-pass quantization. }
+
+{METHODDEF}
+procedure post_process_1pass (cinfo : j_decompress_ptr;
+                  input_buf : JSAMPIMAGE;
+                              var in_row_group_ctr : JDIMENSION;
+                  in_row_groups_avail : JDIMENSION;
+                  output_buf : JSAMPARRAY;
+                              var out_row_ctr : JDIMENSION;
+                  out_rows_avail : JDIMENSION);
+var
+  post : my_post_ptr;
+  num_rows, max_rows : JDIMENSION;
+begin
+  post := my_post_ptr (cinfo^.post);
+
+  { Fill the buffer, but not more than what we can dump out in one go. }
+  { Note we rely on the upsampler to detect bottom of image. }
+  max_rows := out_rows_avail - out_row_ctr;
+  if (max_rows > post^.strip_height) then
+    max_rows := post^.strip_height;
+  num_rows := 0;
+  cinfo^.upsample^.upsample (cinfo,
+                 input_buf,
+                             in_row_group_ctr,
+                             in_row_groups_avail,
+                 post^.buffer,
+                             num_rows,  { var }
+                             max_rows);
+  { Quantize and emit data. }
+
+  cinfo^.cquantize^.color_quantize (cinfo,
+    post^.buffer,
+                JSAMPARRAY(@ output_buf^[out_row_ctr]),
+                int(num_rows));
+
+  Inc(out_row_ctr, num_rows);
+end;
+
+
+{$ifdef QUANT_2PASS_SUPPORTED}
+
+{ Process some data in the first pass of 2-pass quantization. }
+
+{METHODDEF}
+procedure post_process_prepass (cinfo : j_decompress_ptr;
+                                input_buf : JSAMPIMAGE;
+                                var in_row_group_ctr : JDIMENSION;
+                    in_row_groups_avail : JDIMENSION;
+                    output_buf : JSAMPARRAY;
+                                var out_row_ctr : JDIMENSION;
+                    out_rows_avail:JDIMENSION);
+var
+  post : my_post_ptr;
+  old_next_row, num_rows : JDIMENSION;
+begin
+  post := my_post_ptr(cinfo^.post);
+
+  { Reposition virtual buffer if at start of strip. }
+  if (post^.next_row = 0) then
+  begin
+    post^.buffer := cinfo^.mem^.access_virt_sarray
+  (j_common_ptr(cinfo), post^.whole_image,
+   post^.starting_row, post^.strip_height, TRUE);
+  end;
+
+  { Upsample some data (up to a strip height's worth). }
+  old_next_row := post^.next_row;
+  cinfo^.upsample^.upsample (cinfo,
+    input_buf, in_row_group_ctr, in_row_groups_avail,
+    post^.buffer, post^.next_row, post^.strip_height);
+
+  { Allow quantizer to scan new data.  No data is emitted, }
+  { but we advance out_row_ctr so outer loop can tell when we're done. }
+  if (post^.next_row > old_next_row) then
+  begin
+    num_rows := post^.next_row - old_next_row;
+
+
+    cinfo^.cquantize^.color_quantize (cinfo,
+                      JSAMPARRAY(@ post^.buffer^[old_next_row]),
+      JSAMPARRAY(NIL),
+                        int(num_rows));
+    Inc(out_row_ctr, num_rows);
+  end;
+
+  { Advance if we filled the strip. }
+  if (post^.next_row >= post^.strip_height) then
+  begin
+    Inc(post^.starting_row, post^.strip_height);
+    post^.next_row := 0;
+  end;
+end;
+
+
+{ Process some data in the second pass of 2-pass quantization. }
+
+{METHODDEF}
+procedure post_process_2pass (cinfo : j_decompress_ptr;
+                  input_buf : JSAMPIMAGE;
+                              var in_row_group_ctr : JDIMENSION;
+                  in_row_groups_avail : JDIMENSION;
+                  output_buf : JSAMPARRAY;
+                              var out_row_ctr : JDIMENSION;
+                  out_rows_avail : JDIMENSION);
+var
+  post : my_post_ptr;
+  num_rows, max_rows : JDIMENSION;
+begin
+  post := my_post_ptr(cinfo^.post);
+
+  { Reposition virtual buffer if at start of strip. }
+  if (post^.next_row = 0) then
+  begin
+    post^.buffer := cinfo^.mem^.access_virt_sarray
+  (j_common_ptr(cinfo), post^.whole_image,
+   post^.starting_row, post^.strip_height, FALSE);
+  end;
+
+  { Determine number of rows to emit. }
+  num_rows := post^.strip_height - post^.next_row; { available in strip }
+  max_rows := out_rows_avail - out_row_ctr; { available in output area }
+  if (num_rows > max_rows) then
+    num_rows := max_rows;
+  { We have to check bottom of image here, can't depend on upsampler. }
+  max_rows := cinfo^.output_height - post^.starting_row;
+  if (num_rows > max_rows) then
+    num_rows := max_rows;
+
+  { Quantize and emit data. }
+  cinfo^.cquantize^.color_quantize (cinfo,
+                JSAMPARRAY(@ post^.buffer^[post^.next_row]),
+                JSAMPARRAY(@ output_buf^[out_row_ctr]),
+    int(num_rows));
+  Inc(out_row_ctr, num_rows);
+
+  { Advance if we filled the strip. }
+  Inc(post^.next_row, num_rows);
+  if (post^.next_row >= post^.strip_height) then
+  begin
+    Inc(post^.starting_row, post^.strip_height);
+    post^.next_row := 0;
+  end;
+end;
+
+{$endif} { QUANT_2PASS_SUPPORTED }
+
+
+{ Initialize postprocessing controller. }
+
+{GLOBAL}
+procedure jinit_d_post_controller (cinfo : j_decompress_ptr;
+                                   need_full_buffer : boolean);
+var
+  post : my_post_ptr;
+begin
+  post := my_post_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_post_controller)) );
+  cinfo^.post := jpeg_d_post_controller_ptr (post);
+  post^.pub.start_pass := start_pass_dpost;
+  post^.whole_image := NIL; { flag for no virtual arrays }
+  post^.buffer := NIL;    { flag for no strip buffer }
+
+  { Create the quantization buffer, if needed }
+  if (cinfo^.quantize_colors) then
+  begin
+    { The buffer strip height is max_v_samp_factor, which is typically
+      an efficient number of rows for upsampling to return.
+      (In the presence of output rescaling, we might want to be smarter?) }
+
+    post^.strip_height := JDIMENSION (cinfo^.max_v_samp_factor);
+    if (need_full_buffer) then
+    begin
+      { Two-pass color quantization: need full-image storage. }
+      { We round up the number of rows to a multiple of the strip height. }
+{$ifdef QUANT_2PASS_SUPPORTED}
+      post^.whole_image := cinfo^.mem^.request_virt_sarray
+  (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE,
+   LongInt(cinfo^.output_width) * cinfo^.out_color_components,
+   JDIMENSION (jround_up( long(cinfo^.output_height),
+        long(post^.strip_height)) ),
+   post^.strip_height);
+{$else}
+      ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE);
+{$endif} { QUANT_2PASS_SUPPORTED }
+    end
+    else
+    begin
+      { One-pass color quantization: just make a strip buffer. }
+      post^.buffer := cinfo^.mem^.alloc_sarray
+  (j_common_ptr (cinfo), JPOOL_IMAGE,
+   LongInt(cinfo^.output_width) * cinfo^.out_color_components,
+   post^.strip_height);
+    end;
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjdsample.pas b/src/lib/vampimg/JpegLib/imjdsample.pas
new file mode 100644 (file)
index 0000000..ec95e34
--- /dev/null
@@ -0,0 +1,592 @@
+unit imjdsample;
+
+{ Original: jdsample.c; Copyright (C) 1991-1996, Thomas G. Lane. }
+
+{ This file contains upsampling routines.
+
+  Upsampling input data is counted in "row groups".  A row group
+  is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
+  sample rows of each component.  Upsampling will normally produce
+  max_v_samp_factor pixel rows from each row group (but this could vary
+  if the upsampler is applying a scale factor of its own).
+
+  An excellent reference for image resampling is
+    Digital Image Warping, George Wolberg, 1990.
+    Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.}
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjutils,
+  imjpeglib,
+  imjdeferr,
+  imjerror;
+
+
+{ Pointer to routine to upsample a single component }
+type
+  upsample1_ptr = procedure (cinfo : j_decompress_ptr;
+                             compptr : jpeg_component_info_ptr;
+                             input_data : JSAMPARRAY;
+                             var output_data_ptr : JSAMPARRAY);
+
+{ Module initialization routine for upsampling. }
+
+{GLOBAL}
+procedure jinit_upsampler (cinfo : j_decompress_ptr);
+
+implementation
+
+{ Private subobject }
+
+type
+  my_upsample_ptr = ^my_upsampler;
+  my_upsampler = record
+    pub : jpeg_upsampler; { public fields }
+
+    { Color conversion buffer.  When using separate upsampling and color
+      conversion steps, this buffer holds one upsampled row group until it
+      has been color converted and output.
+      Note: we do not allocate any storage for component(s) which are full-size,
+      ie do not need rescaling.  The corresponding entry of color_buf[] is
+      simply set to point to the input data array, thereby avoiding copying.}
+
+    color_buf : array[0..MAX_COMPONENTS-1] of JSAMPARRAY;
+
+    { Per-component upsampling method pointers }
+    methods : array[0..MAX_COMPONENTS-1] of upsample1_ptr;
+
+    next_row_out : int;         { counts rows emitted from color_buf }
+    rows_to_go : JDIMENSION;    { counts rows remaining in image }
+
+    { Height of an input row group for each component. }
+    rowgroup_height : array[0..MAX_COMPONENTS-1] of int;
+
+    { These arrays save pixel expansion factors so that int_expand need not
+      recompute them each time.  They are unused for other upsampling methods.}
+    h_expand : array[0..MAX_COMPONENTS-1] of UINT8 ;
+    v_expand : array[0..MAX_COMPONENTS-1] of UINT8 ;
+  end;
+
+
+{ Initialize for an upsampling pass. }
+
+{METHODDEF}
+procedure start_pass_upsample (cinfo : j_decompress_ptr);
+var
+  upsample : my_upsample_ptr;
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+
+  { Mark the conversion buffer empty }
+  upsample^.next_row_out := cinfo^.max_v_samp_factor;
+  { Initialize total-height counter for detecting bottom of image }
+  upsample^.rows_to_go := cinfo^.output_height;
+end;
+
+
+{ Control routine to do upsampling (and color conversion).
+
+  In this version we upsample each component independently.
+  We upsample one row group into the conversion buffer, then apply
+  color conversion a row at a time. }
+
+{METHODDEF}
+procedure sep_upsample (cinfo : j_decompress_ptr;
+                  input_buf : JSAMPIMAGE;
+                        var in_row_group_ctr : JDIMENSION;
+                  in_row_groups_avail : JDIMENSION;
+                  output_buf : JSAMPARRAY;
+                        var out_row_ctr : JDIMENSION;
+                  out_rows_avail : JDIMENSION);
+var
+  upsample : my_upsample_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+  num_rows : JDIMENSION;
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+
+  { Fill the conversion buffer, if it's empty }
+  if (upsample^.next_row_out >= cinfo^.max_v_samp_factor) then
+  begin
+    compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+    for ci := 0 to pred(cinfo^.num_components) do
+    begin
+      { Invoke per-component upsample method.  Notice we pass a POINTER
+        to color_buf[ci], so that fullsize_upsample can change it. }
+
+      upsample^.methods[ci] (cinfo, compptr,
+  JSAMPARRAY(@ input_buf^[ci]^
+           [LongInt(in_row_group_ctr) * upsample^.rowgroup_height[ci]]),
+  upsample^.color_buf[ci]);
+
+      Inc(compptr);
+    end;
+    upsample^.next_row_out := 0;
+  end;
+
+  { Color-convert and emit rows }
+
+  { How many we have in the buffer: }
+  num_rows := JDIMENSION (cinfo^.max_v_samp_factor - upsample^.next_row_out);
+  { Not more than the distance to the end of the image.  Need this test
+    in case the image height is not a multiple of max_v_samp_factor: }
+
+  if (num_rows > upsample^.rows_to_go) then
+    num_rows := upsample^.rows_to_go;
+  { And not more than what the client can accept: }
+  Dec(out_rows_avail, out_row_ctr);
+  if (num_rows > out_rows_avail) then
+    num_rows := out_rows_avail;
+
+  cinfo^.cconvert^.color_convert (cinfo,
+                                 JSAMPIMAGE(@(upsample^.color_buf)),
+                           JDIMENSION (upsample^.next_row_out),
+         JSAMPARRAY(@(output_buf^[out_row_ctr])),
+         int (num_rows));
+
+  { Adjust counts }
+  Inc(out_row_ctr, num_rows);
+  Dec(upsample^.rows_to_go, num_rows);
+  Inc(upsample^.next_row_out, num_rows);
+  { When the buffer is emptied, declare this input row group consumed }
+  if (upsample^.next_row_out >= cinfo^.max_v_samp_factor) then
+    Inc(in_row_group_ctr);
+end;
+
+
+{ These are the routines invoked by sep_upsample to upsample pixel values
+  of a single component.  One row group is processed per call. }
+
+
+{ For full-size components, we just make color_buf[ci] point at the
+  input buffer, and thus avoid copying any data.  Note that this is
+  safe only because sep_upsample doesn't declare the input row group
+  "consumed" until we are done color converting and emitting it. }
+
+{METHODDEF}
+procedure fullsize_upsample (cinfo : j_decompress_ptr;
+                             compptr : jpeg_component_info_ptr;
+                 input_data : JSAMPARRAY;
+                             var output_data_ptr : JSAMPARRAY);
+begin
+  output_data_ptr := input_data;
+end;
+
+
+{ This is a no-op version used for "uninteresting" components.
+  These components will not be referenced by color conversion. }
+
+{METHODDEF}
+procedure noop_upsample (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   input_data : JSAMPARRAY;
+                         var output_data_ptr : JSAMPARRAY);
+begin
+  output_data_ptr := NIL; { safety check }
+end;
+
+
+{ This version handles any integral sampling ratios.
+  This is not used for typical JPEG files, so it need not be fast.
+  Nor, for that matter, is it particularly accurate: the algorithm is
+  simple replication of the input pixel onto the corresponding output
+  pixels.  The hi-falutin sampling literature refers to this as a
+  "box filter".  A box filter tends to introduce visible artifacts,
+  so if you are actually going to use 3:1 or 4:1 sampling ratios
+  you would be well advised to improve this code. }
+
+{METHODDEF}
+procedure int_upsample (cinfo : j_decompress_ptr;
+                        compptr : jpeg_component_info_ptr;
+                  input_data : JSAMPARRAY;
+                        var output_data_ptr : JSAMPARRAY);
+var
+  upsample : my_upsample_ptr;
+  output_data : JSAMPARRAY;
+  {register} inptr, outptr : JSAMPLE_PTR;
+  {register} invalue : JSAMPLE;
+  {register} h : int;
+  {outend}
+  h_expand, v_expand : int;
+  inrow, outrow : int;
+var
+  outcount : int;  { Nomssi: avoid pointer arithmetic }
+begin
+  upsample := my_upsample_ptr (cinfo^.upsample);
+  output_data := output_data_ptr;
+
+  h_expand := upsample^.h_expand[compptr^.component_index];
+  v_expand := upsample^.v_expand[compptr^.component_index];
+
+  inrow := 0;
+  outrow := 0;
+  while (outrow < cinfo^.max_v_samp_factor) do
+  begin
+    { Generate one output row with proper horizontal expansion }
+    inptr := JSAMPLE_PTR(input_data^[inrow]);
+    outptr := JSAMPLE_PTR(output_data^[outrow]);
+    outcount := cinfo^.output_width;
+    while (outcount > 0) do     { Nomssi }
+    begin
+      invalue := inptr^;  { don't need GETJSAMPLE() here }
+      Inc(inptr);
+      for h := pred(h_expand) downto 0 do
+      begin
+  outptr^ := invalue;
+        inc(outptr);       { <-- fix: this was left out in PasJpeg 1.0 }
+        Dec(outcount);        { thanks to Jannie Gerber for the report }
+      end;
+    end;
+
+    { Generate any additional output rows by duplicating the first one }
+    if (v_expand > 1) then
+    begin
+      jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+      v_expand-1, cinfo^.output_width);
+    end;
+    Inc(inrow);
+    Inc(outrow, v_expand);
+  end;
+end;
+
+
+{ Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
+  It's still a box filter. }
+
+{METHODDEF}
+procedure h2v1_upsample (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   input_data : JSAMPARRAY;
+                         var output_data_ptr : JSAMPARRAY);
+var
+  output_data : JSAMPARRAY;
+  {register} inptr, outptr : JSAMPLE_PTR;
+  {register} invalue : JSAMPLE;
+  {outend : JSAMPROW;}
+  outcount : int;
+  inrow : int;
+begin
+  output_data := output_data_ptr;
+
+  for inrow := 0 to pred(cinfo^.max_v_samp_factor) do
+  begin
+    inptr := JSAMPLE_PTR(input_data^[inrow]);
+    outptr := JSAMPLE_PTR(output_data^[inrow]);
+    {outend := outptr + cinfo^.output_width;}
+    outcount := cinfo^.output_width;
+    while (outcount > 0) do
+    begin
+      invalue := inptr^;  { don't need GETJSAMPLE() here }
+      Inc(inptr);
+      outptr^ := invalue;
+      Inc(outptr);
+      outptr^ := invalue;
+      Inc(outptr);
+      Dec(outcount, 2);         { Nomssi: to avoid pointer arithmetic }
+    end;
+  end;
+end;
+
+
+{ Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
+  It's still a box filter. }
+
+{METHODDEF}
+procedure h2v2_upsample (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   input_data : JSAMPARRAY;
+                         var output_data_ptr : JSAMPARRAY);
+var
+  output_data : JSAMPARRAY;
+  {register} inptr, outptr : JSAMPLE_PTR;
+  {register} invalue : JSAMPLE;
+  {outend : JSAMPROW;}
+  outcount : int;
+  inrow, outrow : int;
+begin
+  output_data := output_data_ptr;
+
+  inrow := 0;
+  outrow := 0;
+  while (outrow < cinfo^.max_v_samp_factor) do
+  begin
+    inptr := JSAMPLE_PTR(input_data^[inrow]);
+    outptr := JSAMPLE_PTR(output_data^[outrow]);
+    {outend := outptr + cinfo^.output_width;}
+    outcount := cinfo^.output_width;
+    while (outcount > 0) do
+    begin
+      invalue := inptr^;  { don't need GETJSAMPLE() here }
+      Inc(inptr);
+      outptr^ := invalue;
+      Inc(outptr);
+      outptr^ := invalue;
+      Inc(outptr);
+      Dec(outcount, 2);
+    end;
+    jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+          1, cinfo^.output_width);
+    Inc(inrow);
+    Inc(outrow, 2);
+  end;
+end;
+
+
+{ Fancy processing for the common case of 2:1 horizontal and 1:1 vertical.
+
+  The upsampling algorithm is linear interpolation between pixel centers,
+  also known as a "triangle filter".  This is a good compromise between
+  speed and visual quality.  The centers of the output pixels are 1/4 and 3/4
+  of the way between input pixel centers.
+
+  A note about the "bias" calculations: when rounding fractional values to
+  integer, we do not want to always round 0.5 up to the next integer.
+  If we did that, we'd introduce a noticeable bias towards larger values.
+  Instead, this code is arranged so that 0.5 will be rounded up or down at
+  alternate pixel locations (a simple ordered dither pattern). }
+
+{METHODDEF}
+procedure h2v1_fancy_upsample (cinfo : j_decompress_ptr;
+                               compptr : jpeg_component_info_ptr;
+                               input_data : JSAMPARRAY;
+                               var output_data_ptr : JSAMPARRAY);
+var
+  output_data : JSAMPARRAY;
+  {register} pre_inptr, inptr, outptr : JSAMPLE_PTR;
+  {register} invalue : int;
+  {register} colctr : JDIMENSION;
+  inrow : int;
+begin
+  output_data := output_data_ptr;
+
+  for inrow := 0 to pred(cinfo^.max_v_samp_factor) do
+  begin
+    inptr := JSAMPLE_PTR(input_data^[inrow]);
+    outptr := JSAMPLE_PTR(output_data^[inrow]);
+    { Special case for first column }
+    pre_inptr := inptr;
+    invalue := GETJSAMPLE(inptr^);
+    Inc(inptr);
+    outptr^ := JSAMPLE (invalue);
+    Inc(outptr);
+    outptr^ := JSAMPLE ((invalue * 3 + GETJSAMPLE(inptr^) + 2) shr 2);
+    Inc(outptr);
+
+    for colctr := pred(compptr^.downsampled_width - 2) downto 0 do
+    begin
+      { General case: 3/4 * nearer pixel + 1/4 * further pixel }
+      invalue := GETJSAMPLE(inptr^) * 3;
+      Inc(inptr);
+      outptr^ := JSAMPLE ((invalue + GETJSAMPLE(pre_inptr^) + 1) shr 2);
+      Inc(pre_inptr);
+      Inc(outptr);
+      outptr^ := JSAMPLE ((invalue + GETJSAMPLE(inptr^) + 2) shr 2);
+      Inc(outptr);
+    end;
+
+    { Special case for last column }
+    invalue := GETJSAMPLE(inptr^);
+    outptr^ := JSAMPLE ((invalue * 3 + GETJSAMPLE(pre_inptr^) + 1) shr 2);
+    Inc(outptr);
+    outptr^ := JSAMPLE (invalue);
+    {Inc(outptr);                        - value never used }
+  end;
+end;
+
+
+{ Fancy processing for the common case of 2:1 horizontal and 2:1 vertical.
+  Again a triangle filter; see comments for h2v1 case, above.
+
+  It is OK for us to reference the adjacent input rows because we demanded
+  context from the main buffer controller (see initialization code). }
+
+{METHODDEF}
+procedure h2v2_fancy_upsample (cinfo : j_decompress_ptr;
+                               compptr : jpeg_component_info_ptr;
+                   input_data : JSAMPARRAY;
+                               var output_data_ptr : JSAMPARRAY);
+var
+  output_data : JSAMPARRAY;
+  {register} inptr0, inptr1, outptr : JSAMPLE_PTR;
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+  {register} thiscolsum, lastcolsum, nextcolsum : int;
+{$else}
+  {register} thiscolsum, lastcolsum, nextcolsum : INT32;
+{$endif}
+  {register} colctr : JDIMENSION;
+  inrow, outrow, v : int;
+var
+  prev_input_data : JSAMPARRAY;  { Nomssi work around }
+begin
+  output_data := output_data_ptr;
+
+  outrow := 0;
+  inrow := 0;
+  while (outrow < cinfo^.max_v_samp_factor) do
+  begin
+    for v := 0 to pred(2) do
+    begin
+      { inptr0 points to nearest input row, inptr1 points to next nearest }
+      inptr0 := JSAMPLE_PTR(input_data^[inrow]);
+      if (v = 0) then         { next nearest is row above }
+      begin
+  {inptr1 := JSAMPLE_PTR(input_data^[inrow-1]);}
+        prev_input_data := input_data;       { work around }
+        Dec(JSAMPROW_PTR(prev_input_data));  { negative offsets }
+  inptr1 := JSAMPLE_PTR(prev_input_data^[inrow]);
+      end
+      else                    { next nearest is row below }
+  inptr1 := JSAMPLE_PTR(input_data^[inrow+1]);
+      outptr := JSAMPLE_PTR(output_data^[outrow]);
+      Inc(outrow);
+
+      { Special case for first column }
+      thiscolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^);
+      Inc(inptr0);
+      Inc(inptr1);
+      nextcolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^);
+      Inc(inptr0);
+      Inc(inptr1);
+
+      outptr^ := JSAMPLE ((thiscolsum * 4 + 8) shr 4);
+      Inc(outptr);
+      outptr^ := JSAMPLE ((thiscolsum * 3 + nextcolsum + 7) shr 4);
+      Inc(outptr);
+      lastcolsum := thiscolsum; thiscolsum := nextcolsum;
+
+      for colctr := pred(compptr^.downsampled_width - 2) downto 0 do
+      begin
+  { General case: 3/4 * nearer pixel + 1/4 * further pixel in each }
+  { dimension, thus 9/16, 3/16, 3/16, 1/16 overall }
+  nextcolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^);
+        Inc(inptr0);
+        Inc(inptr1);
+  outptr^ := JSAMPLE ((thiscolsum * 3 + lastcolsum + 8) shr 4);
+        Inc(outptr);
+  outptr^ := JSAMPLE ((thiscolsum * 3 + nextcolsum + 7) shr 4);
+        Inc(outptr);
+  lastcolsum := thiscolsum;
+        thiscolsum := nextcolsum;
+      end;
+
+      { Special case for last column }
+      outptr^ := JSAMPLE ((thiscolsum * 3 + lastcolsum + 8) shr 4);
+      Inc(outptr);
+      outptr^ := JSAMPLE ((thiscolsum * 4 + 7) shr 4);
+      {Inc(outptr);                     - value never used }
+    end;
+    Inc(inrow);
+  end;
+end;
+
+
+{ Module initialization routine for upsampling. }
+
+{GLOBAL}
+procedure jinit_upsampler (cinfo : j_decompress_ptr);
+var
+  upsample : my_upsample_ptr;
+  ci : int;
+  compptr : jpeg_component_info_ptr;
+  need_buffer, do_fancy : boolean;
+  h_in_group, v_in_group, h_out_group, v_out_group : int;
+begin
+  upsample := my_upsample_ptr (
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_upsampler)) );
+  cinfo^.upsample := jpeg_upsampler_ptr (upsample);
+  upsample^.pub.start_pass := start_pass_upsample;
+  upsample^.pub.upsample := sep_upsample;
+  upsample^.pub.need_context_rows := FALSE; { until we find out differently }
+
+  if (cinfo^.CCIR601_sampling)  then        { this isn't supported }
+    ERREXIT(j_common_ptr(cinfo), JERR_CCIR601_NOTIMPL);
+
+  { jdmainct.c doesn't support context rows when min_DCT_scaled_size := 1,
+    so don't ask for it. }
+
+  do_fancy := cinfo^.do_fancy_upsampling and (cinfo^.min_DCT_scaled_size > 1);
+
+  { Verify we can handle the sampling factors, select per-component methods,
+    and create storage as needed. }
+
+  compptr := jpeg_component_info_ptr(cinfo^.comp_info);
+  for ci := 0 to pred(cinfo^.num_components) do
+  begin
+    { Compute size of an "input group" after IDCT scaling.  This many samples
+      are to be converted to max_h_samp_factor * max_v_samp_factor pixels. }
+
+    h_in_group := (compptr^.h_samp_factor * compptr^.DCT_scaled_size) div
+     cinfo^.min_DCT_scaled_size;
+    v_in_group := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div
+     cinfo^.min_DCT_scaled_size;
+    h_out_group := cinfo^.max_h_samp_factor;
+    v_out_group := cinfo^.max_v_samp_factor;
+    upsample^.rowgroup_height[ci] := v_in_group; { save for use later }
+    need_buffer := TRUE;
+    if (not compptr^.component_needed) then
+    begin
+      { Don't bother to upsample an uninteresting component. }
+      upsample^.methods[ci] := noop_upsample;
+      need_buffer := FALSE;
+    end
+    else
+      if (h_in_group = h_out_group) and (v_in_group = v_out_group) then
+      begin
+        { Fullsize components can be processed without any work. }
+        upsample^.methods[ci] := fullsize_upsample;
+        need_buffer := FALSE;
+      end
+      else
+        if (h_in_group * 2 = h_out_group) and
+           (v_in_group = v_out_group) then
+        begin
+        { Special cases for 2h1v upsampling }
+          if (do_fancy) and (compptr^.downsampled_width > 2) then
+      upsample^.methods[ci] := h2v1_fancy_upsample
+          else
+      upsample^.methods[ci] := h2v1_upsample;
+        end
+        else
+          if (h_in_group * 2 = h_out_group) and
+             (v_in_group * 2 = v_out_group) then
+          begin
+            { Special cases for 2h2v upsampling }
+            if (do_fancy) and (compptr^.downsampled_width > 2) then
+            begin
+        upsample^.methods[ci] := h2v2_fancy_upsample;
+        upsample^.pub.need_context_rows := TRUE;
+            end
+            else
+        upsample^.methods[ci] := h2v2_upsample;
+          end
+          else
+            if ((h_out_group mod h_in_group) = 0) and
+               ((v_out_group mod v_in_group) = 0) then
+            begin
+              { Generic integral-factors upsampling method }
+              upsample^.methods[ci] := int_upsample;
+              upsample^.h_expand[ci] := UINT8 (h_out_group div h_in_group);
+              upsample^.v_expand[ci] := UINT8 (v_out_group div v_in_group);
+            end
+            else
+              ERREXIT(j_common_ptr(cinfo), JERR_FRACT_SAMPLE_NOTIMPL);
+    if (need_buffer) then
+    begin
+      upsample^.color_buf[ci] := cinfo^.mem^.alloc_sarray
+  (j_common_ptr(cinfo), JPOOL_IMAGE,
+   JDIMENSION (jround_up( long (cinfo^.output_width),
+        long (cinfo^.max_h_samp_factor))),
+   JDIMENSION (cinfo^.max_v_samp_factor));
+    end;
+    Inc(compptr);
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjerror.pas b/src/lib/vampimg/JpegLib/imjerror.pas
new file mode 100644 (file)
index 0000000..11f53fd
--- /dev/null
@@ -0,0 +1,462 @@
+unit imjerror;
+
+{ This file contains simple error-reporting and trace-message routines.
+  These are suitable for Unix-like systems and others where writing to
+  stderr is the right thing to do.  Many applications will want to replace
+  some or all of these routines.
+
+  These routines are used by both the compression and decompression code. }
+
+{ Source: jerror.c;  Copyright (C) 1991-1996, Thomas G. Lane. }
+{ note: format_message still contains a hack }
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjdeferr,
+  imjpeglib;
+{
+  jversion;
+}
+
+const
+  EXIT_FAILURE  = 1;   { define halt() codes if not provided }
+
+{GLOBAL}
+function jpeg_std_error (var err : jpeg_error_mgr) : jpeg_error_mgr_ptr;
+
+
+
+procedure ERREXIT(cinfo : j_common_ptr; code : J_MESSAGE_CODE);
+
+procedure ERREXIT1(cinfo : j_common_ptr; code : J_MESSAGE_CODE; p1 : uInt);
+
+procedure ERREXIT2(cinfo : j_common_ptr; code : J_MESSAGE_CODE; p1 : int; p2 : int);
+
+procedure ERREXIT3(cinfo : j_common_ptr; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int);
+
+procedure ERREXIT4(cinfo : j_common_ptr; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int; p4 : int);
+
+procedure ERREXITS(cinfo : j_common_ptr;code : J_MESSAGE_CODE;
+                   str : AnsiString);
+{ Nonfatal errors (we can keep going, but the data is probably corrupt) }
+
+procedure WARNMS(cinfo : j_common_ptr; code : J_MESSAGE_CODE);
+
+procedure WARNMS1(cinfo : j_common_ptr;code : J_MESSAGE_CODE; p1 : int);
+
+procedure WARNMS2(cinfo : j_common_ptr; code : J_MESSAGE_CODE;
+                  p1 : int; p2 : int);
+
+{ Informational/debugging messages }
+procedure TRACEMS(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE);
+
+procedure TRACEMS1(cinfo : j_common_ptr; lvl : int;
+                   code : J_MESSAGE_CODE; p1 : long);
+
+procedure TRACEMS2(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                   p1 : int;
+                   p2 : int);
+
+procedure TRACEMS3(cinfo : j_common_ptr;
+                   lvl : int;
+                   code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int);
+
+procedure TRACEMS4(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int; p4 : int);
+
+procedure TRACEMS5(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int; p4 : int; p5 : int);
+
+procedure TRACEMS8(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                  p1 : int; p2 : int; p3 : int; p4 : int;
+                  p5 : int; p6 : int; p7 : int; p8 : int);
+
+procedure TRACEMSS(cinfo : j_common_ptr; lvl : int;
+                   code : J_MESSAGE_CODE; str : AnsiString);
+
+implementation
+
+
+{ How to format a message string, in format_message() ? }
+
+{$IFDEF OS2}
+  {$DEFINE NO_FORMAT}
+{$ENDIF}
+{$IFDEF FPC}
+  {$DEFINE NO_FORMAT}
+{$ENDIF}
+
+uses
+{$IFNDEF NO_FORMAT}
+  {$IFDEF VER70}
+    drivers, { Turbo Vision unit with FormatStr }
+  {$ELSE}
+    sysutils,  { Delphi Unit with Format() }
+  {$ENDIF}
+{$ENDIF}
+  imjcomapi;
+
+{ Error exit handler: must not return to caller.
+
+  Applications may override this if they want to get control back after
+  an error.  Typically one would longjmp somewhere instead of exiting.
+  The setjmp buffer can be made a private field within an expanded error
+  handler object.  Note that the info needed to generate an error message
+  is stored in the error object, so you can generate the message now or
+  later, at your convenience.
+  You should make sure that the JPEG object is cleaned up (with jpeg_abort
+  or jpeg_destroy) at some point. }
+
+
+{METHODDEF}
+procedure error_exit (cinfo : j_common_ptr);
+begin
+  { Always display the message }
+  cinfo^.err^.output_message(cinfo);
+
+  { Let the memory manager delete any temp files before we die }
+  jpeg_destroy(cinfo);
+
+  halt(EXIT_FAILURE);
+end;
+
+
+{ Actual output of an error or trace message.
+  Applications may override this method to send JPEG messages somewhere
+  other than stderr. }
+
+{ Macros to simplify using the error and trace message stuff }
+{ The first parameter is either type of cinfo pointer }
+
+{ Fatal errors (print message and exit) }
+procedure ERREXIT(cinfo : j_common_ptr; code : J_MESSAGE_CODE);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.error_exit(cinfo);
+end;
+
+procedure ERREXIT1(cinfo : j_common_ptr; code : J_MESSAGE_CODE; p1 : uInt);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.error_exit (cinfo);
+end;
+
+procedure ERREXIT2(cinfo : j_common_ptr; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.msg_parm.i[1] := p2;
+  cinfo^.err^.error_exit (cinfo);
+end;
+
+procedure ERREXIT3(cinfo : j_common_ptr; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.msg_parm.i[1] := p2;
+  cinfo^.err^.msg_parm.i[2] := p3;
+  cinfo^.err^.error_exit (cinfo);
+end;
+
+procedure ERREXIT4(cinfo : j_common_ptr; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int; p4 : int);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.msg_parm.i[1] := p2;
+  cinfo^.err^.msg_parm.i[2] := p3;
+  cinfo^.err^.msg_parm.i[3] := p4;
+  cinfo^.err^.error_exit (cinfo);
+end;
+
+procedure ERREXITS(cinfo : j_common_ptr;code : J_MESSAGE_CODE;
+                   str : AnsiString);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.s := str;  { string[JMSG_STR_PARM_MAX] }
+  cinfo^.err^.error_exit (cinfo);
+end;
+
+{ Nonfatal errors (we can keep going, but the data is probably corrupt) }
+
+procedure WARNMS(cinfo : j_common_ptr; code : J_MESSAGE_CODE);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.emit_message(cinfo, -1);
+end;
+
+procedure WARNMS1(cinfo : j_common_ptr;code : J_MESSAGE_CODE; p1 : int);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.emit_message (cinfo, -1);
+end;
+
+procedure WARNMS2(cinfo : j_common_ptr; code : J_MESSAGE_CODE;
+                  p1 : int; p2 : int);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.msg_parm.i[1] := p2;
+  cinfo^.err^.emit_message (cinfo, -1);
+end;
+
+{ Informational/debugging messages }
+procedure TRACEMS(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.emit_message(cinfo, lvl);
+end;
+
+procedure TRACEMS1(cinfo : j_common_ptr; lvl : int;
+                   code : J_MESSAGE_CODE; p1 : long);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.emit_message (cinfo, lvl);
+end;
+
+procedure TRACEMS2(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                   p1 : int;
+                   p2 : int);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.i[0] := p1;
+  cinfo^.err^.msg_parm.i[1] := p2;
+  cinfo^.err^.emit_message (cinfo, lvl);
+end;
+
+procedure TRACEMS3(cinfo : j_common_ptr;
+                   lvl : int;
+                   code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int);
+var
+  _mp : int8array;
+begin
+  _mp[0] := p1; _mp[1] := p2; _mp[2] := p3;
+  cinfo^.err^.msg_parm.i := _mp;
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.emit_message (cinfo, lvl);
+end;
+
+
+procedure TRACEMS4(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int; p4 : int);
+var
+  _mp : int8array;
+begin
+  _mp[0] := p1; _mp[1] := p2; _mp[2] := p3; _mp[3] := p4;
+  cinfo^.err^.msg_parm.i := _mp;
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.emit_message (cinfo, lvl);
+end;
+
+procedure TRACEMS5(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                   p1 : int; p2 : int; p3 : int; p4 : int; p5 : int);
+var
+  _mp : ^int8array;
+begin
+  _mp := @cinfo^.err^.msg_parm.i;
+  _mp^[0] := p1; _mp^[1] := p2; _mp^[2] := p3;
+  _mp^[3] := p4; _mp^[5] := p5;
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.emit_message (cinfo, lvl);
+end;
+
+procedure TRACEMS8(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE;
+                  p1 : int; p2 : int; p3 : int; p4 : int;
+                  p5 : int; p6 : int; p7 : int; p8 : int);
+var
+  _mp : int8array;
+begin
+  _mp[0] := p1; _mp[1] := p2; _mp[2] := p3; _mp[3] := p4;
+  _mp[4] := p5; _mp[5] := p6; _mp[6] := p7; _mp[7] := p8;
+  cinfo^.err^.msg_parm.i := _mp;
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.emit_message (cinfo, lvl);
+end;
+
+procedure TRACEMSS(cinfo : j_common_ptr; lvl : int;
+                   code : J_MESSAGE_CODE; str : AnsiString);
+begin
+  cinfo^.err^.msg_code := ord(code);
+  cinfo^.err^.msg_parm.s := str; { string JMSG_STR_PARM_MAX }
+  cinfo^.err^.emit_message (cinfo, lvl);
+end;
+
+{METHODDEF}
+procedure output_message (cinfo : j_common_ptr);
+var
+  buffer : AnsiString; {[JMSG_LENGTH_MAX];}
+begin
+  { Create the message }
+  cinfo^.err^.format_message (cinfo, buffer);
+
+  { Send it to stderr, adding a newline }
+  WriteLn(output, buffer);
+end;
+
+
+
+{ Decide whether to emit a trace or warning message.
+  msg_level is one of:
+    -1: recoverable corrupt-data warning, may want to abort.
+     0: important advisory messages (always display to user).
+     1: first level of tracing detail.
+     2,3,...: successively more detailed tracing messages.
+  An application might override this method if it wanted to abort on warnings
+  or change the policy about which messages to display. }
+
+
+{METHODDEF}
+procedure emit_message (cinfo : j_common_ptr; msg_level : int);
+var
+  err : jpeg_error_mgr_ptr;
+begin
+  err := cinfo^.err;
+  if (msg_level < 0) then
+  begin
+    { It's a warning message.  Since corrupt files may generate many warnings,
+      the policy implemented here is to show only the first warning,
+      unless trace_level >= 3. }
+
+    if (err^.num_warnings = 0) or (err^.trace_level >= 3) then
+      err^.output_message(cinfo);
+    { Always count warnings in num_warnings. }
+    Inc( err^.num_warnings );
+  end
+  else
+  begin
+    { It's a trace message.  Show it if trace_level >= msg_level. }
+    if (err^.trace_level >= msg_level) then
+      err^.output_message (cinfo);
+  end;
+end;
+
+
+{ Format a message string for the most recent JPEG error or message.
+  The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
+  characters.  Note that no '\n' character is added to the string.
+  Few applications should need to override this method. }
+
+
+{METHODDEF}
+procedure format_message (cinfo : j_common_ptr; var buffer : AnsiString);
+var
+  err : jpeg_error_mgr_ptr;
+  msg_code : J_MESSAGE_CODE;
+  msgtext : AnsiString;
+  isstring : boolean;
+begin
+  err := cinfo^.err;
+  msg_code := J_MESSAGE_CODE(err^.msg_code);
+  msgtext := '';
+
+  { Look up message string in proper table }
+  if (msg_code > JMSG_NOMESSAGE)
+    and (msg_code <= J_MESSAGE_CODE(err^.last_jpeg_message)) then
+  begin
+    msgtext := err^.jpeg_message_table^[msg_code];
+  end
+  else
+  if (err^.addon_message_table <> NIL) and
+     (msg_code >= err^.first_addon_message) and
+     (msg_code <= err^.last_addon_message) then
+  begin
+    msgtext := err^.addon_message_table^[J_MESSAGE_CODE
+           (ord(msg_code) - ord(err^.first_addon_message))];
+  end;
+
+  { Defend against bogus message number }
+  if (msgtext = '') then
+  begin
+    err^.msg_parm.i[0] := int(msg_code);
+    msgtext := err^.jpeg_message_table^[JMSG_NOMESSAGE];
+  end;
+
+  { Check for string parameter, as indicated by %s in the message text }
+  isstring := Pos('%s', msgtext) > 0;
+
+  { Format the message into the passed buffer }
+  if (isstring) then
+    buffer := Concat(msgtext, err^.msg_parm.s)
+  else
+  begin
+ {$IFDEF VER70}
+    FormatStr(buffer, msgtext, err^.msg_parm.i);
+ {$ELSE}
+   {$IFDEF NO_FORMAT}
+   buffer := msgtext;
+   {$ELSE}
+   buffer := Format(msgtext, [
+        err^.msg_parm.i[0], err^.msg_parm.i[1],
+        err^.msg_parm.i[2], err^.msg_parm.i[3],
+        err^.msg_parm.i[4], err^.msg_parm.i[5],
+        err^.msg_parm.i[6], err^.msg_parm.i[7] ]);
+   {$ENDIF}
+ {$ENDIF}
+  end;
+end;
+
+
+
+{ Reset error state variables at start of a new image.
+  This is called during compression startup to reset trace/error
+  processing to default state, without losing any application-specific
+  method pointers.  An application might possibly want to override
+  this method if it has additional error processing state. }
+
+
+{METHODDEF}
+procedure reset_error_mgr (cinfo : j_common_ptr);
+begin
+  cinfo^.err^.num_warnings := 0;
+  { trace_level is not reset since it is an application-supplied parameter }
+  cinfo^.err^.msg_code := 0;      { may be useful as a flag for "no error" }
+end;
+
+
+{ Fill in the standard error-handling methods in a jpeg_error_mgr object.
+  Typical call is:
+        cinfo : jpeg_compress_struct;
+        err : jpeg_error_mgr;
+
+        cinfo.err := jpeg_std_error(@err);
+  after which the application may override some of the methods. }
+
+
+{GLOBAL}
+function jpeg_std_error (var err : jpeg_error_mgr) : jpeg_error_mgr_ptr;
+begin
+  err.error_exit := error_exit;
+  err.emit_message := emit_message;
+  err.output_message := output_message;
+  err.format_message := format_message;
+  err.reset_error_mgr := reset_error_mgr;
+
+  err.trace_level := 0;         { default := no tracing }
+  err.num_warnings := 0;        { no warnings emitted yet }
+  err.msg_code := 0;            { may be useful as a flag for "no error" }
+
+  { Initialize message table pointers }
+  err.jpeg_message_table := @jpeg_std_message_table;
+  err.last_jpeg_message := pred(JMSG_LASTMSGCODE);
+
+  err.addon_message_table := NIL;
+  err.first_addon_message := JMSG_NOMESSAGE;  { for safety }
+  err.last_addon_message := JMSG_NOMESSAGE;
+
+  jpeg_std_error := @err;
+end;
+
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjfdctflt.pas b/src/lib/vampimg/JpegLib/imjfdctflt.pas
new file mode 100644 (file)
index 0000000..1038284
--- /dev/null
@@ -0,0 +1,176 @@
+unit imjfdctflt;
+
+{$N+}
+{ This file contains a floating-point implementation of the
+  forward DCT (Discrete Cosine Transform).
+
+  This implementation should be more accurate than either of the integer
+  DCT implementations.  However, it may not give the same results on all
+  machines because of differences in roundoff behavior.  Speed will depend
+  on the hardware's floating point capacity.
+
+  A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+  on each column.  Direct algorithms are also available, but they are
+  much more complex and seem not to be any faster when reduced to code.
+
+  This implementation is based on Arai, Agui, and Nakajima's algorithm for
+  scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+  Japanese, but the algorithm is described in the Pennebaker & Mitchell
+  JPEG textbook (see REFERENCES section in file README).  The following code
+  is based directly on figure 4-8 in P&M.
+  While an 8-point DCT cannot be done in less than 11 multiplies, it is
+  possible to arrange the computation so that many of the multiplies are
+  simple scalings of the final outputs.  These multiplies can then be
+  folded into the multiplications or divisions by the JPEG quantization
+  table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+  to be done in the DCT itself.
+  The primary disadvantage of this method is that with a fixed-point
+  implementation, accuracy is lost due to imprecise representation of the
+  scaled quantization values.  However, that problem does not arise if
+  we use floating point arithmetic. }
+
+{ Original : jfdctflt.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdct;   { Private declarations for DCT subsystem }
+
+
+{ Perform the forward DCT on one block of samples.}
+
+{GLOBAL}
+procedure jpeg_fdct_float (var data : array of FAST_FLOAT);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+
+{ Perform the forward DCT on one block of samples.}
+
+{GLOBAL}
+procedure jpeg_fdct_float (var data : array of FAST_FLOAT);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = array [0..DCTSIZE2-1] of FAST_FLOAT;
+var
+  tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : FAST_FLOAT;
+  tmp10, tmp11, tmp12, tmp13 : FAST_FLOAT;
+  z1, z2, z3, z4, z5, z11, z13 : FAST_FLOAT;
+  dataptr : PWorkspace;
+  ctr : int;
+begin
+  { Pass 1: process rows. }
+
+  dataptr := PWorkspace(@data);
+  for ctr := DCTSIZE-1 downto 0 do
+  begin
+    tmp0 := dataptr^[0] + dataptr^[7];
+    tmp7 := dataptr^[0] - dataptr^[7];
+    tmp1 := dataptr^[1] + dataptr^[6];
+    tmp6 := dataptr^[1] - dataptr^[6];
+    tmp2 := dataptr^[2] + dataptr^[5];
+    tmp5 := dataptr^[2] - dataptr^[5];
+    tmp3 := dataptr^[3] + dataptr^[4];
+    tmp4 := dataptr^[3] - dataptr^[4];
+
+    { Even part }
+
+    tmp10 := tmp0 + tmp3; { phase 2 }
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    dataptr^[0] := tmp10 + tmp11; { phase 3 }
+    dataptr^[4] := tmp10 - tmp11;
+
+    z1 := (tmp12 + tmp13) * ({FAST_FLOAT}(0.707106781)); { c4 }
+    dataptr^[2] := tmp13 + z1;  { phase 5 }
+    dataptr^[6] := tmp13 - z1;
+
+    { Odd part }
+
+    tmp10 := tmp4 + tmp5; { phase 2 }
+    tmp11 := tmp5 + tmp6;
+    tmp12 := tmp6 + tmp7;
+
+    { The rotator is modified from fig 4-8 to avoid extra negations. }
+    z5 := (tmp10 - tmp12) * ( {FAST_FLOAT}(0.382683433)); { c6 }
+    z2 := {FAST_FLOAT}(0.541196100) * tmp10 + z5; { c2-c6 }
+    z4 := {FAST_FLOAT}(1.306562965) * tmp12 + z5; { c2+c6 }
+    z3 := tmp11 * {FAST_FLOAT} (0.707106781); { c4 }
+
+    z11 := tmp7 + z3;   { phase 5 }
+    z13 := tmp7 - z3;
+
+    dataptr^[5] := z13 + z2;  { phase 6 }
+    dataptr^[3] := z13 - z2;
+    dataptr^[1] := z11 + z4;
+    dataptr^[7] := z11 - z4;
+
+    Inc(FAST_FLOAT_PTR(dataptr), DCTSIZE);  { advance pointer to next row }
+  end;
+
+  { Pass 2: process columns. }
+
+  dataptr := PWorkspace(@data);
+  for ctr := DCTSIZE-1 downto 0 do
+  begin
+    tmp0 := dataptr^[DCTSIZE*0] + dataptr^[DCTSIZE*7];
+    tmp7 := dataptr^[DCTSIZE*0] - dataptr^[DCTSIZE*7];
+    tmp1 := dataptr^[DCTSIZE*1] + dataptr^[DCTSIZE*6];
+    tmp6 := dataptr^[DCTSIZE*1] - dataptr^[DCTSIZE*6];
+    tmp2 := dataptr^[DCTSIZE*2] + dataptr^[DCTSIZE*5];
+    tmp5 := dataptr^[DCTSIZE*2] - dataptr^[DCTSIZE*5];
+    tmp3 := dataptr^[DCTSIZE*3] + dataptr^[DCTSIZE*4];
+    tmp4 := dataptr^[DCTSIZE*3] - dataptr^[DCTSIZE*4];
+
+    { Even part }
+
+    tmp10 := tmp0 + tmp3; { phase 2 }
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    dataptr^[DCTSIZE*0] := tmp10 + tmp11; { phase 3 }
+    dataptr^[DCTSIZE*4] := tmp10 - tmp11;
+
+    z1 := (tmp12 + tmp13) * {FAST_FLOAT} (0.707106781); { c4 }
+    dataptr^[DCTSIZE*2] := tmp13 + z1; { phase 5 }
+    dataptr^[DCTSIZE*6] := tmp13 - z1;
+
+    { Odd part }
+
+    tmp10 := tmp4 + tmp5; { phase 2 }
+    tmp11 := tmp5 + tmp6;
+    tmp12 := tmp6 + tmp7;
+
+    { The rotator is modified from fig 4-8 to avoid extra negations. }
+    z5 := (tmp10 - tmp12) * {FAST_FLOAT} (0.382683433); { c6 }
+    z2 := {FAST_FLOAT} (0.541196100) * tmp10 + z5; { c2-c6 }
+    z4 := {FAST_FLOAT} (1.306562965) * tmp12 + z5; { c2+c6 }
+    z3 := tmp11 * {FAST_FLOAT} (0.707106781); { c4 }
+
+    z11 := tmp7 + z3;   { phase 5 }
+    z13 := tmp7 - z3;
+
+    dataptr^[DCTSIZE*5] := z13 + z2; { phase 6 }
+    dataptr^[DCTSIZE*3] := z13 - z2;
+    dataptr^[DCTSIZE*1] := z11 + z4;
+    dataptr^[DCTSIZE*7] := z11 - z4;
+
+    Inc(FAST_FLOAT_PTR(dataptr));   { advance pointer to next column }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjfdctfst.pas b/src/lib/vampimg/JpegLib/imjfdctfst.pas
new file mode 100644 (file)
index 0000000..40b2fd1
--- /dev/null
@@ -0,0 +1,237 @@
+unit imjfdctfst;
+
+{ This file contains a fast, not so accurate integer implementation of the
+  forward DCT (Discrete Cosine Transform).
+
+  A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+  on each column.  Direct algorithms are also available, but they are
+  much more complex and seem not to be any faster when reduced to code.
+
+  This implementation is based on Arai, Agui, and Nakajima's algorithm for
+  scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+  Japanese, but the algorithm is described in the Pennebaker & Mitchell
+  JPEG textbook (see REFERENCES section in file README).  The following code
+  is based directly on figure 4-8 in P&M.
+  While an 8-point DCT cannot be done in less than 11 multiplies, it is
+  possible to arrange the computation so that many of the multiplies are
+  simple scalings of the final outputs.  These multiplies can then be
+  folded into the multiplications or divisions by the JPEG quantization
+  table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+  to be done in the DCT itself.
+  The primary disadvantage of this method is that with fixed-point math,
+  accuracy is lost due to imprecise representation of the scaled
+  quantization values.  The smaller the quantization table entry, the less
+  precise the scaled value, so this implementation does worse with high-
+  quality-setting files than with low-quality ones. }
+
+{ Original: jfdctfst.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdct;     { Private declarations for DCT subsystem }
+
+
+{ Perform the forward DCT on one block of samples. }
+
+{GLOBAL}
+procedure jpeg_fdct_ifast (var data : array of DCTELEM);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+
+{ Scaling decisions are generally the same as in the LL&M algorithm;
+  see jfdctint.c for more details.  However, we choose to descale
+  (right shift) multiplication products as soon as they are formed,
+  rather than carrying additional fractional bits into subsequent additions.
+  This compromises accuracy slightly, but it lets us save a few shifts.
+  More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+  everywhere except in the multiplications proper; this saves a good deal
+  of work on 16-bit-int machines.
+
+  Again to save a few shifts, the intermediate results between pass 1 and
+  pass 2 are not upscaled, but are represented only to integral precision.
+
+  A final compromise is to represent the multiplicative constants to only
+  8 fractional bits, rather than 13.  This saves some shifting work on some
+  machines, and may also reduce the cost of multiplication (since there
+  are fewer one-bits in the constants). }
+
+const
+  CONST_BITS = 8;
+const
+  CONST_SCALE = (INT32(1) shl CONST_BITS);
+
+
+const
+  FIX_0_382683433 = INT32(Round(CONST_SCALE * 0.382683433)); {98}
+  FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100)); {139}
+  FIX_0_707106781 = INT32(Round(CONST_SCALE * 0.707106781)); {181}
+  FIX_1_306562965 = INT32(Round(CONST_SCALE * 1.306562965)); {334}
+
+{ Descale and correctly round an INT32 value that's scaled by N bits.
+  We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+  the fudge factor is correct for either sign of X. }
+
+function DESCALE(x : INT32; n : int) : INT32;
+var
+  shift_temp : INT32;
+begin
+{ We can gain a little more speed, with a further compromise in accuracy,
+  by omitting the addition in a descaling shift.  This yields an incorrectly
+  rounded result half the time... }
+{$ifndef USE_ACCURATE_ROUNDING}
+  shift_temp := x;
+{$else}
+  shift_temp := x + (INT32(1) shl (n-1));
+{$endif}
+
+{$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+  if shift_temp < 0 then
+    Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+  else
+{$endif}
+    Descale :=  (shift_temp shr n);
+end;
+
+{ Multiply a DCTELEM variable by an INT32 constant, and immediately
+  descale to yield a DCTELEM result. }
+
+
+   function MULTIPLY(X : DCTELEM; Y: INT32): DCTELEM;
+   begin
+     Multiply := DeScale((X) * (Y), CONST_BITS);
+   end;
+
+
+{ Perform the forward DCT on one block of samples. }
+
+{GLOBAL}
+procedure jpeg_fdct_ifast (var data : array of DCTELEM);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = array [0..DCTSIZE2-1] of DCTELEM;
+var
+  tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : DCTELEM;
+  tmp10, tmp11, tmp12, tmp13 : DCTELEM;
+  z1, z2, z3, z4, z5, z11, z13 : DCTELEM;
+  dataptr :  PWorkspace;
+  ctr : int;
+  {SHIFT_TEMPS}
+begin
+  { Pass 1: process rows. }
+
+  dataptr := PWorkspace(@data);
+  for ctr := DCTSIZE-1 downto 0 do
+  begin
+    tmp0 := dataptr^[0] + dataptr^[7];
+    tmp7 := dataptr^[0] - dataptr^[7];
+    tmp1 := dataptr^[1] + dataptr^[6];
+    tmp6 := dataptr^[1] - dataptr^[6];
+    tmp2 := dataptr^[2] + dataptr^[5];
+    tmp5 := dataptr^[2] - dataptr^[5];
+    tmp3 := dataptr^[3] + dataptr^[4];
+    tmp4 := dataptr^[3] - dataptr^[4];
+
+    { Even part }
+
+    tmp10 := tmp0 + tmp3; { phase 2 }
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    dataptr^[0] := tmp10 + tmp11; { phase 3 }
+    dataptr^[4] := tmp10 - tmp11;
+
+    z1 := MULTIPLY(tmp12 + tmp13, FIX_0_707106781); { c4 }
+    dataptr^[2] := tmp13 + z1;  { phase 5 }
+    dataptr^[6] := tmp13 - z1;
+
+    { Odd part }
+
+    tmp10 := tmp4 + tmp5; { phase 2 }
+    tmp11 := tmp5 + tmp6;
+    tmp12 := tmp6 + tmp7;
+
+    { The rotator is modified from fig 4-8 to avoid extra negations. }
+    z5 := MULTIPLY(tmp10 - tmp12, FIX_0_382683433); { c6 }
+    z2 := MULTIPLY(tmp10, FIX_0_541196100) + z5; { c2-c6 }
+    z4 := MULTIPLY(tmp12, FIX_1_306562965) + z5; { c2+c6 }
+    z3 := MULTIPLY(tmp11, FIX_0_707106781); { c4 }
+
+    z11 := tmp7 + z3;   { phase 5 }
+    z13 := tmp7 - z3;
+
+    dataptr^[5] := z13 + z2;  { phase 6 }
+    dataptr^[3] := z13 - z2;
+    dataptr^[1] := z11 + z4;
+    dataptr^[7] := z11 - z4;
+
+    Inc(DCTELEMPTR(dataptr), DCTSIZE);  { advance pointer to next row }
+  end;
+
+  { Pass 2: process columns. }
+
+  dataptr := PWorkspace(@data);
+  for ctr := DCTSIZE-1 downto 0 do
+  begin
+    tmp0 := dataptr^[DCTSIZE*0] + dataptr^[DCTSIZE*7];
+    tmp7 := dataptr^[DCTSIZE*0] - dataptr^[DCTSIZE*7];
+    tmp1 := dataptr^[DCTSIZE*1] + dataptr^[DCTSIZE*6];
+    tmp6 := dataptr^[DCTSIZE*1] - dataptr^[DCTSIZE*6];
+    tmp2 := dataptr^[DCTSIZE*2] + dataptr^[DCTSIZE*5];
+    tmp5 := dataptr^[DCTSIZE*2] - dataptr^[DCTSIZE*5];
+    tmp3 := dataptr^[DCTSIZE*3] + dataptr^[DCTSIZE*4];
+    tmp4 := dataptr^[DCTSIZE*3] - dataptr^[DCTSIZE*4];
+
+    { Even part }
+
+    tmp10 := tmp0 + tmp3; { phase 2 }
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    dataptr^[DCTSIZE*0] := tmp10 + tmp11; { phase 3 }
+    dataptr^[DCTSIZE*4] := tmp10 - tmp11;
+
+    z1 := MULTIPLY(tmp12 + tmp13, FIX_0_707106781); { c4 }
+    dataptr^[DCTSIZE*2] := tmp13 + z1; { phase 5 }
+    dataptr^[DCTSIZE*6] := tmp13 - z1;
+
+    { Odd part }
+
+    tmp10 := tmp4 + tmp5; { phase 2 }
+    tmp11 := tmp5 + tmp6;
+    tmp12 := tmp6 + tmp7;
+
+    { The rotator is modified from fig 4-8 to avoid extra negations. }
+    z5 := MULTIPLY(tmp10 - tmp12, FIX_0_382683433); { c6 }
+    z2 := MULTIPLY(tmp10, FIX_0_541196100) + z5; { c2-c6 }
+    z4 := MULTIPLY(tmp12, FIX_1_306562965) + z5; { c2+c6 }
+    z3 := MULTIPLY(tmp11, FIX_0_707106781); { c4 }
+
+    z11 := tmp7 + z3;   { phase 5 }
+    z13 := tmp7 - z3;
+
+    dataptr^[DCTSIZE*5] := z13 + z2; { phase 6 }
+    dataptr^[DCTSIZE*3] := z13 - z2;
+    dataptr^[DCTSIZE*1] := z11 + z4;
+    dataptr^[DCTSIZE*7] := z11 - z4;
+
+    Inc(DCTELEMPTR(dataptr)); { advance pointer to next column }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjfdctint.pas b/src/lib/vampimg/JpegLib/imjfdctint.pas
new file mode 100644 (file)
index 0000000..b676fff
--- /dev/null
@@ -0,0 +1,297 @@
+unit imjfdctint;
+
+
+{ This file contains a slow-but-accurate integer implementation of the
+  forward DCT (Discrete Cosine Transform).
+
+  A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+  on each column.  Direct algorithms are also available, but they are
+  much more complex and seem not to be any faster when reduced to code.
+
+  This implementation is based on an algorithm described in
+    C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+    Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+    Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+  The primary algorithm described there uses 11 multiplies and 29 adds.
+  We use their alternate method with 12 multiplies and 32 adds.
+  The advantage of this method is that no data path contains more than one
+  multiplication; this allows a very simple and accurate implementation in
+  scaled fixed-point arithmetic, with a minimal number of shifts. }
+
+{ Original : jfdctint.c ; Copyright (C) 1991-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjutils,
+  imjpeglib,
+  imjdct;   { Private declarations for DCT subsystem }
+
+
+{ Perform the forward DCT on one block of samples. }
+
+{GLOBAL}
+procedure jpeg_fdct_islow (var data : array of DCTELEM);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+
+{ The poop on this scaling stuff is as follows:
+
+  Each 1-D DCT step produces outputs which are a factor of sqrt(N)
+  larger than the true DCT outputs.  The final outputs are therefore
+  a factor of N larger than desired; since N=8 this can be cured by
+  a simple right shift at the end of the algorithm.  The advantage of
+  this arrangement is that we save two multiplications per 1-D DCT,
+  because the y0 and y4 outputs need not be divided by sqrt(N).
+  In the IJG code, this factor of 8 is removed by the quantization step
+  (in jcdctmgr.c), NOT in this module.
+
+  We have to do addition and subtraction of the integer inputs, which
+  is no problem, and multiplication by fractional constants, which is
+  a problem to do in integer arithmetic.  We multiply all the constants
+  by CONST_SCALE and convert them to integer constants (thus retaining
+  CONST_BITS bits of precision in the constants).  After doing a
+  multiplication we have to divide the product by CONST_SCALE, with proper
+  rounding, to produce the correct output.  This division can be done
+  cheaply as a right shift of CONST_BITS bits.  We postpone shifting
+  as long as possible so that partial sums can be added together with
+  full fractional precision.
+
+  The outputs of the first pass are scaled up by PASS1_BITS bits so that
+  they are represented to better-than-integral precision.  These outputs
+  require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+  with the recommended scaling.  (For 12-bit sample data, the intermediate
+  array is INT32 anyway.)
+
+  To avoid overflow of the 32-bit intermediate results in pass 2, we must
+  have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
+  shows that the values given below are the most effective. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  CONST_BITS = 13;
+  PASS1_BITS = 2;
+{$else}
+const
+  CONST_BITS = 13;
+  PASS1_BITS = 1; { lose a little precision to avoid overflow }
+{$endif}
+
+const
+  CONST_SCALE = (INT32(1) shl CONST_BITS);
+
+const
+  FIX_0_298631336 = INT32(Round(CONST_SCALE * 0.298631336));  {2446}
+  FIX_0_390180644 = INT32(Round(CONST_SCALE * 0.390180644));  {3196}
+  FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100));  {4433}
+  FIX_0_765366865 = INT32(Round(CONST_SCALE * 0.765366865));  {6270}
+  FIX_0_899976223 = INT32(Round(CONST_SCALE * 0.899976223));  {7373}
+  FIX_1_175875602 = INT32(Round(CONST_SCALE * 1.175875602));  {9633}
+  FIX_1_501321110 = INT32(Round(CONST_SCALE * 1.501321110));  {12299}
+  FIX_1_847759065 = INT32(Round(CONST_SCALE * 1.847759065));  {15137}
+  FIX_1_961570560 = INT32(Round(CONST_SCALE * 1.961570560));  {16069}
+  FIX_2_053119869 = INT32(Round(CONST_SCALE * 2.053119869));  {16819}
+  FIX_2_562915447 = INT32(Round(CONST_SCALE * 2.562915447));  {20995}
+  FIX_3_072711026 = INT32(Round(CONST_SCALE * 3.072711026));  {25172}
+
+
+{ Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+  For 8-bit samples with the recommended scaling, all the variable
+  and constant values involved are no more than 16 bits wide, so a
+  16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+  For 12-bit samples, a full 32-bit multiplication will be needed. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+
+   {MULTIPLY16C16(var,const)}
+   function Multiply(X, Y: int): INT32;
+   begin
+     Multiply := int(X) * INT32(Y);
+   end;
+
+{$else}
+   function Multiply(X, Y: INT32): INT32;
+   begin
+     Multiply := X * Y;
+   end;
+{$endif}
+
+{ Descale and correctly round an INT32 value that's scaled by N bits.
+  We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+  the fudge factor is correct for either sign of X. }
+
+function DESCALE(x : INT32; n : int) : INT32;
+var
+  shift_temp : INT32;
+begin
+{$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+  shift_temp := x + (INT32(1) shl (n-1));
+  if shift_temp < 0 then
+    Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+  else
+    Descale :=  (shift_temp shr n);
+{$else}
+  Descale := (x + (INT32(1) shl (n-1)) shr n;
+{$endif}
+end;
+
+
+{ Perform the forward DCT on one block of samples. }
+
+{GLOBAL}
+procedure jpeg_fdct_islow (var data : array of DCTELEM);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = array [0..DCTSIZE2-1] of DCTELEM;
+var
+  tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : INT32;
+  tmp10, tmp11, tmp12, tmp13 : INT32;
+  z1, z2, z3, z4, z5 : INT32;
+  dataptr : PWorkspace;
+  ctr : int;
+  {SHIFT_TEMPS}
+begin
+
+  { Pass 1: process rows. }
+  { Note results are scaled up by sqrt(8) compared to a true DCT; }
+  { furthermore, we scale the results by 2**PASS1_BITS. }
+
+  dataptr := PWorkspace(@data);
+  for ctr := DCTSIZE-1 downto 0 do
+  begin
+    tmp0 := dataptr^[0] + dataptr^[7];
+    tmp7 := dataptr^[0] - dataptr^[7];
+    tmp1 := dataptr^[1] + dataptr^[6];
+    tmp6 := dataptr^[1] - dataptr^[6];
+    tmp2 := dataptr^[2] + dataptr^[5];
+    tmp5 := dataptr^[2] - dataptr^[5];
+    tmp3 := dataptr^[3] + dataptr^[4];
+    tmp4 := dataptr^[3] - dataptr^[4];
+
+    { Even part per LL&M figure 1 --- note that published figure is faulty;
+      rotator "sqrt(2)*c1" should be "sqrt(2)*c6".  }
+
+    tmp10 := tmp0 + tmp3;
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    dataptr^[0] := DCTELEM ((tmp10 + tmp11) shl PASS1_BITS);
+    dataptr^[4] := DCTELEM ((tmp10 - tmp11) shl PASS1_BITS);
+
+    z1 := MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+    dataptr^[2] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865),
+           CONST_BITS-PASS1_BITS));
+    dataptr^[6] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065),
+           CONST_BITS-PASS1_BITS));
+
+    { Odd part per figure 8 --- note paper omits factor of sqrt(2).
+      cK represents cos(K*pi/16).
+      i0..i3 in the paper are tmp4..tmp7 here. }
+
+    z1 := tmp4 + tmp7;
+    z2 := tmp5 + tmp6;
+    z3 := tmp4 + tmp6;
+    z4 := tmp5 + tmp7;
+    z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 }
+
+    tmp4 := MULTIPLY(tmp4, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) }
+    tmp5 := MULTIPLY(tmp5, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) }
+    tmp6 := MULTIPLY(tmp6, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) }
+    tmp7 := MULTIPLY(tmp7, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) }
+    z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) }
+    z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) }
+    z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) }
+    z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) }
+
+    Inc(z3, z5);
+    Inc(z4, z5);
+
+    dataptr^[7] := DCTELEM(DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS));
+    dataptr^[5] := DCTELEM(DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS));
+    dataptr^[3] := DCTELEM(DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS));
+    dataptr^[1] := DCTELEM(DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS));
+
+    Inc(DCTELEMPTR(dataptr), DCTSIZE);  { advance pointer to next row }
+  end;
+
+  { Pass 2: process columns.
+    We remove the PASS1_BITS scaling, but leave the results scaled up
+    by an overall factor of 8. }
+
+  dataptr := PWorkspace(@data);
+  for ctr := DCTSIZE-1 downto 0 do
+  begin
+    tmp0 := dataptr^[DCTSIZE*0] + dataptr^[DCTSIZE*7];
+    tmp7 := dataptr^[DCTSIZE*0] - dataptr^[DCTSIZE*7];
+    tmp1 := dataptr^[DCTSIZE*1] + dataptr^[DCTSIZE*6];
+    tmp6 := dataptr^[DCTSIZE*1] - dataptr^[DCTSIZE*6];
+    tmp2 := dataptr^[DCTSIZE*2] + dataptr^[DCTSIZE*5];
+    tmp5 := dataptr^[DCTSIZE*2] - dataptr^[DCTSIZE*5];
+    tmp3 := dataptr^[DCTSIZE*3] + dataptr^[DCTSIZE*4];
+    tmp4 := dataptr^[DCTSIZE*3] - dataptr^[DCTSIZE*4];
+
+    { Even part per LL&M figure 1 --- note that published figure is faulty;
+      rotator "sqrt(2)*c1" should be "sqrt(2)*c6". }
+
+    tmp10 := tmp0 + tmp3;
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    dataptr^[DCTSIZE*0] := DCTELEM (DESCALE(tmp10 + tmp11, PASS1_BITS));
+    dataptr^[DCTSIZE*4] := DCTELEM (DESCALE(tmp10 - tmp11, PASS1_BITS));
+
+    z1 := MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+    dataptr^[DCTSIZE*2] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865),
+             CONST_BITS+PASS1_BITS));
+    dataptr^[DCTSIZE*6] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065),
+             CONST_BITS+PASS1_BITS));
+
+    { Odd part per figure 8 --- note paper omits factor of sqrt(2).
+      cK represents cos(K*pi/16).
+      i0..i3 in the paper are tmp4..tmp7 here. }
+
+    z1 := tmp4 + tmp7;
+    z2 := tmp5 + tmp6;
+    z3 := tmp4 + tmp6;
+    z4 := tmp5 + tmp7;
+    z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 }
+
+    tmp4 := MULTIPLY(tmp4, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) }
+    tmp5 := MULTIPLY(tmp5, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) }
+    tmp6 := MULTIPLY(tmp6, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) }
+    tmp7 := MULTIPLY(tmp7, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) }
+    z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) }
+    z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) }
+    z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) }
+    z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) }
+
+    Inc(z3, z5);
+    Inc(z4, z5);
+
+    dataptr^[DCTSIZE*7] := DCTELEM (DESCALE(tmp4 + z1 + z3,
+             CONST_BITS+PASS1_BITS));
+    dataptr^[DCTSIZE*5] := DCTELEM (DESCALE(tmp5 + z2 + z4,
+             CONST_BITS+PASS1_BITS));
+    dataptr^[DCTSIZE*3] := DCTELEM (DESCALE(tmp6 + z2 + z3,
+             CONST_BITS+PASS1_BITS));
+    dataptr^[DCTSIZE*1] := DCTELEM (DESCALE(tmp7 + z1 + z4,
+             CONST_BITS+PASS1_BITS));
+
+    Inc(DCTELEMPTR(dataptr)); { advance pointer to next column }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjidctasm.pas b/src/lib/vampimg/JpegLib/imjidctasm.pas
new file mode 100644 (file)
index 0000000..a699739
--- /dev/null
@@ -0,0 +1,793 @@
+unit imjidctasm;
+
+{ This file contains a slow-but-accurate integer implementation of the
+  inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+  must also perform dequantization of the input coefficients.
+
+  A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+  on each row (or vice versa, but it's more convenient to emit a row at
+  a time).  Direct algorithms are also available, but they are much more
+  complex and seem not to be any faster when reduced to code.
+
+  This implementation is based on an algorithm described in
+    C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+    Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+    Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+  The primary algorithm described there uses 11 multiplies and 29 adds.
+  We use their alternate method with 12 multiplies and 32 adds.
+  The advantage of this method is that no data path contains more than one
+  multiplication; this allows a very simple and accurate implementation in
+  scaled fixed-point arithmetic, with a minimal number of shifts. }
+
+{ Original : jidctint.c ;  Copyright (C) 1991-1996, Thomas G. Lane. }
+{ ;-------------------------------------------------------------------------
+  ; JIDCTINT.ASM
+  ; 80386 protected mode assembly translation of JIDCTINT.C
+  ; **** Optimized to all hell by Jason M. Felice (jasonf@apk.net) ****
+  ; **** E-mail welcome                      ****
+  ;
+  ; ** This code does not make O/S calls -- use it for OS/2, Win95, WinNT,
+  ; ** DOS prot. mode., Linux, whatever... have fun.
+  ;
+  ; ** Note, this code is dependant on the structure member order in the .h
+  ; ** files for the following structures:
+  ; -- amazingly NOT j_decompress_struct... cool.
+  ; -- jpeg_component_info (dependant on position of dct_table element)
+  ;
+  ; Originally created with the /Fa option of MSVC 4.0 (why work when you
+  ; don't have to?)
+  ;
+  ; (this code, when compiled is 1K bytes smaller than the optimized MSVC
+  ; release build, not to mention 120-130 ms faster in my profile test with 1
+  ; small color and and 1 medium black-and-white jpeg: stats using TASM 4.0
+  ; and MSVC 4.0 to create a non-console app; jpeg_idct_islow accumulated
+  ; 5,760 hits on all trials)
+  ;
+  ; TASM -t -ml -os jidctint.asm, jidctint.obj
+  ;-------------------------------------------------------------------------
+   Converted to Delphi 2.0 BASM for PasJPEG
+   by Jacques NOMSSI NZALI  <nomssi@physik.tu-chemnitz.de>
+   October 13th 1996
+    * assumes Delphi "register" calling convention
+        first 3 parameter are in EAX,EDX,ECX
+    * register allocation revised
+}
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdct;         { Private declarations for DCT subsystem }
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_islow (cinfo : j_decompress_ptr;
+                          compptr : jpeg_component_info_ptr;
+              coef_block : JCOEFPTR;
+              output_buf : JSAMPARRAY;
+                          output_col : JDIMENSION);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+{ The poop on this scaling stuff is as follows:
+
+  Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
+  larger than the true IDCT outputs.  The final outputs are therefore
+  a factor of N larger than desired; since N=8 this can be cured by
+  a simple right shift at the end of the algorithm.  The advantage of
+  this arrangement is that we save two multiplications per 1-D IDCT,
+  because the y0 and y4 inputs need not be divided by sqrt(N).
+
+  We have to do addition and subtraction of the integer inputs, which
+  is no problem, and multiplication by fractional constants, which is
+  a problem to do in integer arithmetic.  We multiply all the constants
+  by CONST_SCALE and convert them to integer constants (thus retaining
+  CONST_BITS bits of precision in the constants).  After doing a
+  multiplication we have to divide the product by CONST_SCALE, with proper
+  rounding, to produce the correct output.  This division can be done
+  cheaply as a right shift of CONST_BITS bits.  We postpone shifting
+  as long as possible so that partial sums can be added together with
+  full fractional precision.
+
+  The outputs of the first pass are scaled up by PASS1_BITS bits so that
+  they are represented to better-than-integral precision.  These outputs
+  require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+  with the recommended scaling.  (To scale up 12-bit sample data further, an
+  intermediate INT32 array would be needed.)
+
+  To avoid overflow of the 32-bit intermediate results in pass 2, we must
+  have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
+  shows that the values given below are the most effective. }
+
+const
+  CONST_BITS = 13;
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  PASS1_BITS = 2;
+{$else}
+const
+  PASS1_BITS = 1; { lose a little precision to avoid overflow }
+{$endif}
+
+const
+  CONST_SCALE = (INT32(1) shl CONST_BITS);
+
+const
+  FIX_0_298631336 = INT32(Round(CONST_SCALE * 0.298631336));  {2446}
+  FIX_0_390180644 = INT32(Round(CONST_SCALE * 0.390180644));  {3196}
+  FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100));  {4433}
+  FIX_0_765366865 = INT32(Round(CONST_SCALE * 0.765366865));  {6270}
+  FIX_0_899976223 = INT32(Round(CONST_SCALE * 0.899976223));  {7373}
+  FIX_1_175875602 = INT32(Round(CONST_SCALE * 1.175875602));  {9633}
+  FIX_1_501321110 = INT32(Round(CONST_SCALE * 1.501321110));  {12299}
+  FIX_1_847759065 = INT32(Round(CONST_SCALE * 1.847759065));  {15137}
+  FIX_1_961570560 = INT32(Round(CONST_SCALE * 1.961570560));  {16069}
+  FIX_2_053119869 = INT32(Round(CONST_SCALE * 2.053119869));  {16819}
+  FIX_2_562915447 = INT32(Round(CONST_SCALE * 2.562915447));  {20995}
+  FIX_3_072711026 = INT32(Round(CONST_SCALE * 3.072711026));  {25172}
+
+
+{ for DESCALE }
+const
+  ROUND_CONST = (INT32(1) shl (CONST_BITS-PASS1_BITS-1));
+const
+  ROUND_CONST_2 = (INT32(1) shl (CONST_BITS+PASS1_BITS+3-1));
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_islow (cinfo : j_decompress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               coef_block : JCOEFPTR;
+               output_buf : JSAMPARRAY;
+                           output_col : JDIMENSION);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = coef_bits_field; { buffers data between passes }
+const
+  coefDCTSIZE = DCTSIZE*SizeOf(JCOEF);
+  wrkDCTSIZE = DCTSIZE*SizeOf(int);
+var
+  tmp0, tmp1, tmp2, tmp3 : INT32;
+  tmp10, tmp11, tmp12, tmp13 : INT32;
+  z1, z2, z3, z4, z5 : INT32;
+var
+  inptr : JCOEFPTR;
+  quantptr : ISLOW_MULT_TYPE_FIELD_PTR;
+  wsptr : PWorkspace;
+  outptr : JSAMPROW;
+var
+  range_limit : JSAMPROW;
+  ctr : int;
+  workspace : TWorkspace;
+var
+  dcval : int;
+var
+  dcval_ : JSAMPLE;
+asm
+  push  edi
+  push  esi
+  push  ebx
+
+  cld { The only direction we use, might as well set it now, as opposed }
+        { to inside 2 loops. }
+
+{ Each IDCT routine is responsible for range-limiting its results and
+  converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+  be quite far out of range if the input data is corrupt, so a bulletproof
+  range-limiting step is required.  We use a mask-and-table-lookup method
+  to do the combined operations quickly.  See the comments with
+  prepare_range_limit_table (in jdmaster.c) for more info. }
+
+  {range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));}
+  mov eax, [eax].jpeg_decompress_struct.sample_range_limit {eax=cinfo}
+  add eax, (MAXJSAMPLE+1 + CENTERJSAMPLE)*(Type JSAMPLE)
+  mov range_limit, eax
+
+  { Pass 1: process columns from input, store into work array. }
+  { Note results are scaled up by sqrt(8) compared to a true IDCT; }
+  { furthermore, we scale the results by 2**PASS1_BITS. }
+
+  {inptr := coef_block;}
+  mov esi, ecx     { ecx=coef_block }
+  {quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table);}
+  mov edi, [edx].jpeg_component_info.dct_table  { edx=compptr }
+
+  {wsptr := PWorkspace(@workspace);}
+  lea ecx, workspace
+
+  {for ctr := pred(DCTSIZE) downto 0 do
+  begin}
+  mov ctr, DCTSIZE
+@loop518:
+    { Due to quantization, we will usually find that many of the input
+      coefficients are zero, especially the AC terms.  We can exploit this
+      by short-circuiting the IDCT calculation for any column in which all
+      the AC terms are zero.  In that case each output is equal to the
+      DC coefficient (with scale factor as needed).
+      With typical images and quantization tables, half or more of the
+      column DCT calculations can be simplified this way. }
+
+    {if ((inptr^[DCTSIZE*1]) or (inptr^[DCTSIZE*2]) or (inptr^[DCTSIZE*3]) or
+  (inptr^[DCTSIZE*4]) or (inptr^[DCTSIZE*5]) or (inptr^[DCTSIZE*6]) or
+  (inptr^[DCTSIZE*7]) = 0) then
+    begin}
+  mov eax, DWORD PTR [esi+coefDCTSIZE*1]
+  or  eax, DWORD PTR [esi+coefDCTSIZE*2]
+  or  eax, DWORD PTR [esi+coefDCTSIZE*3]
+  mov edx, DWORD PTR [esi+coefDCTSIZE*4]
+  or    eax, edx
+  or  eax, DWORD PTR [esi+coefDCTSIZE*5]
+  or  eax, DWORD PTR [esi+coefDCTSIZE*6]
+  or  eax, DWORD PTR [esi+coefDCTSIZE*7]
+  jne @loop520
+
+      { AC terms all zero }
+      {dcval := ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) *
+               (quantptr^[DCTSIZE*0]) shl PASS1_BITS;}
+  mov eax, DWORD PTR [esi+coefDCTSIZE*0]
+  imul  eax, DWORD PTR [edi+wrkDCTSIZE*0]
+  shl eax, PASS1_BITS
+
+  {wsptr^[DCTSIZE*0] := dcval;
+  wsptr^[DCTSIZE*1] := dcval;
+  wsptr^[DCTSIZE*2] := dcval;
+  wsptr^[DCTSIZE*3] := dcval;
+  wsptr^[DCTSIZE*4] := dcval;
+  wsptr^[DCTSIZE*5] := dcval;
+  wsptr^[DCTSIZE*6] := dcval;
+  wsptr^[DCTSIZE*7] := dcval;}
+
+  mov DWORD PTR [ecx+ wrkDCTSIZE*0], eax
+  mov DWORD PTR [ecx+ wrkDCTSIZE*1], eax
+  mov DWORD PTR [ecx+ wrkDCTSIZE*2], eax
+  mov DWORD PTR [ecx+ wrkDCTSIZE*3], eax
+  mov DWORD PTR [ecx+ wrkDCTSIZE*4], eax
+  mov DWORD PTR [ecx+ wrkDCTSIZE*5], eax
+  mov DWORD PTR [ecx+ wrkDCTSIZE*6], eax
+  mov DWORD PTR [ecx+ wrkDCTSIZE*7], eax
+
+      {Inc(JCOEF_PTR(inptr));   { advance pointers to next column }
+      {Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+      Inc(int_ptr(wsptr));
+      continue;}
+  dec ctr
+  je  @loop519
+
+  add   esi, Type JCOEF
+  add edi, Type ISLOW_MULT_TYPE
+  add ecx, Type int  { int_ptr }
+  jmp @loop518
+
+@loop520:
+
+    {end;}
+
+    { Even part: reverse the even part of the forward DCT. }
+    { The rotator is sqrt(2)*c(-6). }
+
+    {z2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*2]) * quantptr^[DCTSIZE*2];
+    z3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*6]) * quantptr^[DCTSIZE*6];
+
+    z1 := (z2 + z3) * INT32(FIX_0_541196100);
+    tmp2 := z1 + INT32(z3) * INT32(- FIX_1_847759065);
+    tmp3 := z1 + INT32(z2) * INT32(FIX_0_765366865);}
+
+  mov edx, DWORD PTR [esi+coefDCTSIZE*2]
+  imul  edx, DWORD PTR [edi+wrkDCTSIZE*2]  {z2}
+
+  mov eax, DWORD PTR [esi+coefDCTSIZE*6]
+  imul  eax, DWORD PTR [edi+wrkDCTSIZE*6]  {z3}
+
+  lea   ebx, [eax+edx]
+  imul  ebx, FIX_0_541196100               {z1}
+
+  imul  eax, (-FIX_1_847759065)
+  add   eax, ebx
+  mov   tmp2, eax
+
+  imul  edx, FIX_0_765366865
+  add   edx, ebx
+  mov   tmp3, edx
+
+    {z2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * quantptr^[DCTSIZE*0];
+    z3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*4]) * quantptr^[DCTSIZE*4];}
+
+  mov edx, DWORD PTR [esi+coefDCTSIZE*4]
+  imul  edx, DWORD PTR [edi+wrkDCTSIZE*4]      { z3 = edx }
+
+  mov eax, DWORD PTR [esi+coefDCTSIZE*0]
+  imul  eax, DWORD PTR [edi+wrkDCTSIZE*0]      { z2 = eax }
+
+    {tmp0 := (z2 + z3) shl CONST_BITS;
+    tmp1 := (z2 - z3) shl CONST_BITS;}
+  lea ebx,[eax+edx]
+  sub eax, edx
+  shl ebx, CONST_BITS                          { tmp0 = ebx }
+  shl eax, CONST_BITS                          { tmp1 = eax }
+
+    {tmp10 := tmp0 + tmp3;
+    tmp13 := tmp0 - tmp3;}
+  mov edx, tmp3
+  sub ebx, edx
+  mov tmp13, ebx
+  add edx, edx
+  add ebx, edx
+  mov tmp10, ebx
+
+    {tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;}
+  mov   ebx, tmp2
+  sub   eax, ebx
+  mov   tmp12, eax
+  add   ebx, ebx
+  add   eax, ebx
+  mov tmp11, eax
+
+    { Odd part per figure 8; the matrix is unitary and hence its
+      transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively. }
+
+    {tmp0 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*7]) * quantptr^[DCTSIZE*7];}
+  mov eax, DWORD PTR [esi+coefDCTSIZE*7]
+  imul  eax, DWORD PTR [edi+wrkDCTSIZE*7]
+  mov   edx, eax                            { edx = tmp0 }
+    {tmp0 := (tmp0) * INT32(FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) }
+  imul  eax, FIX_0_298631336
+  mov tmp0, eax
+
+    {tmp3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*1]) * quantptr^[DCTSIZE*1];}
+  mov eax, DWORD PTR [esi+coefDCTSIZE*1]
+  imul  eax, DWORD PTR [edi+wrkDCTSIZE*1]
+  mov tmp3, eax
+
+    {z1 := tmp0 + tmp3;}
+    {z1 := (z1) * INT32(- FIX_0_899976223); { sqrt(2) * (c7-c3) }
+  add eax, edx
+  imul eax, (-FIX_0_899976223)
+  mov  z1, eax
+
+    {tmp1 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*5]) * quantptr^[DCTSIZE*5];}
+  mov eax, DWORD PTR [esi+coefDCTSIZE*5]
+  imul  eax, DWORD PTR [edi+wrkDCTSIZE*5]
+  mov ebx, eax                            { ebx = tmp1 }
+    {tmp1 := (tmp1) * INT32(FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) }
+  imul  eax, FIX_2_053119869
+  mov tmp1, eax
+
+    {tmp2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*3]) * quantptr^[DCTSIZE*3];}
+  mov eax, DWORD PTR [esi+coefDCTSIZE*3]
+  imul  eax, DWORD PTR [edi+wrkDCTSIZE*3]
+  mov tmp2, eax
+
+    {z3 := tmp0 + tmp2;}
+  add edx, eax                              { edx = z3 }
+
+    {z2 := tmp1 + tmp2;}
+    {z2 := (z2) * INT32(- FIX_2_562915447); { sqrt(2) * (-c1-c3) }
+  add eax, ebx
+  imul  eax, (-FIX_2_562915447)
+  mov z2, eax
+
+    {z4 := tmp1 + tmp3;}
+  add ebx, tmp3                             { ebx = z4 }
+
+    {z5 := INT32(z3 + z4) * INT32(FIX_1_175875602); { sqrt(2) * c3 }
+  lea   eax, [edx+ebx]
+  imul eax, FIX_1_175875602                   { eax = z5 }
+
+    {z4 := (z4) * INT32(- FIX_0_390180644); { sqrt(2) * (c5-c3) }
+    {Inc(z4, z5);}
+  imul   ebx, (-FIX_0_390180644)
+  add    ebx, eax
+  mov    z4, ebx
+
+    {z3 := (z3) * INT32(- FIX_1_961570560); { sqrt(2) * (-c3-c5) }
+    {Inc(z3, z5);}
+  imul edx, (-FIX_1_961570560)
+  add  eax, edx                        { z3 = eax }
+
+    {Inc(tmp0, z1 + z3);}
+  mov   ebx, z1
+  add ebx, eax
+  add tmp0, ebx
+
+    {tmp2 := (tmp2) * INT32(FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) }
+    {Inc(tmp2, z2 + z3);}
+  mov   ebx, tmp2
+  imul  ebx, FIX_3_072711026
+  mov edx, z2                        { z2 = edx }
+  add   ebx, edx
+  add   eax, ebx
+  mov tmp2, eax
+
+    {Inc(tmp1, z2 + z4);}
+  mov   eax, z4                        { z4 = eax }
+  add   edx, eax
+  add   tmp1, edx
+
+    {tmp3 := (tmp3) * INT32(FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) }
+    {Inc(tmp3, z1 + z4);}
+  mov edx, tmp3
+  imul  edx, FIX_1_501321110
+
+  add edx, eax
+  add   edx, z1                        { tmp3 = edx }
+
+    { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 }
+
+    {wsptr^[DCTSIZE*0] := int (DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS));}
+    {wsptr^[DCTSIZE*7] := int (DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS));}
+  mov eax, tmp10
+  add   eax, ROUND_CONST
+  lea   ebx, [eax+edx]
+  sar ebx, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*0], ebx
+
+  sub eax, edx
+  sar eax, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*7], eax
+
+    {wsptr^[DCTSIZE*1] := int (DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS));}
+    {wsptr^[DCTSIZE*6] := int (DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS));}
+  mov eax, tmp11
+  add   eax, ROUND_CONST
+  mov   edx, tmp2
+  lea ebx, [eax+edx]
+  sar ebx, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*1], ebx
+
+  sub eax, edx
+  sar eax, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*6], eax
+
+    {wsptr^[DCTSIZE*2] := int (DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS));}
+    {wsptr^[DCTSIZE*5] := int (DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS));}
+  mov eax, tmp12
+  add   eax, ROUND_CONST
+  mov   edx, tmp1
+  lea ebx, [eax+edx]
+  sar ebx, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*2], ebx
+
+  sub eax, edx
+  sar eax, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*5], eax
+
+    {wsptr^[DCTSIZE*3] := int (DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS));}
+    {wsptr^[DCTSIZE*4] := int (DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS));}
+  mov eax, tmp13
+  add   eax, ROUND_CONST
+  mov   edx, tmp0
+  lea   ebx, [eax+edx]
+  sar ebx, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*3], ebx
+
+  sub eax, edx
+  sar eax, CONST_BITS-PASS1_BITS
+  mov DWORD PTR [ecx+wrkDCTSIZE*4], eax
+
+    {Inc(JCOEF_PTR(inptr));   { advance pointers to next column }
+    {Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+    Inc(int_ptr(wsptr));}
+  dec ctr
+  je  @loop519
+
+  add   esi, Type JCOEF
+  add edi, Type ISLOW_MULT_TYPE
+  add ecx, Type int  { int_ptr }
+  {end;}
+  jmp @loop518
+@loop519:
+  { Save to memory what we've registerized for the preceding loop. }
+
+  { Pass 2: process rows from work array, store into output array. }
+  { Note that we must descale the results by a factor of 8 == 2**3, }
+  { and also undo the PASS1_BITS scaling. }
+
+  {wsptr := @workspace;}
+  lea esi, workspace
+
+  {for ctr := 0 to pred(DCTSIZE) do
+  begin}
+  mov ctr, 0
+@loop523:
+
+    {outptr := output_buf^[ctr];}
+  mov eax, ctr
+  mov ebx, output_buf
+  mov edi, DWORD PTR [ebx+eax*4]           { 4 = SizeOf(pointer) }
+
+    {Inc(JSAMPLE_PTR(outptr), output_col);}
+  add edi, LongWord(output_col)
+
+    { Rows of zeroes can be exploited in the same way as we did with columns.
+      However, the column calculation has created many nonzero AC terms, so
+      the simplification applies less often (typically 5% to 10% of the time).
+      On machines with very fast multiplication, it's possible that the
+      test takes more time than it's worth.  In that case this section
+      may be commented out. }
+
+{$ifndef NO_ZERO_ROW_TEST}
+    {if ((wsptr^[1]) or (wsptr^[2]) or (wsptr^[3]) or (wsptr^[4]) or
+        (wsptr^[5]) or (wsptr^[6]) or (wsptr^[7]) = 0) then
+    begin}
+  mov eax, DWORD PTR [esi+4*1]
+  or  eax, DWORD PTR [esi+4*2]
+  or  eax, DWORD PTR [esi+4*3]
+        jne     @loop525            { Nomssi: early exit path may help }
+  or  eax, DWORD PTR [esi+4*4]
+  or  eax, DWORD PTR [esi+4*5]
+  or  eax, DWORD PTR [esi+4*6]
+  or  eax, DWORD PTR [esi+4*7]
+  jne @loop525
+
+      { AC terms all zero }
+      {JSAMPLE(dcval_) := range_limit^[int(DESCALE(INT32(wsptr^[0]),
+                          PASS1_BITS+3)) and RANGE_MASK];}
+  mov eax, DWORD PTR [esi+4*0]
+  add eax, (INT32(1) shl (PASS1_BITS+3-1))
+  sar eax, PASS1_BITS+3
+  and eax, RANGE_MASK
+        mov     ebx, range_limit
+  mov al, BYTE PTR [ebx+eax]
+        mov     ah, al
+
+      {outptr^[0] := dcval_;
+      outptr^[1] := dcval_;
+      outptr^[2] := dcval_;
+      outptr^[3] := dcval_;
+      outptr^[4] := dcval_;
+      outptr^[5] := dcval_;
+      outptr^[6] := dcval_;
+      outptr^[7] := dcval_;}
+
+  stosw
+  stosw
+  stosw
+  stosw
+
+      {Inc(int_ptr(wsptr), DCTSIZE);  { advance pointer to next row }
+      {continue;}
+  add esi, wrkDCTSIZE
+  inc ctr
+  cmp ctr, DCTSIZE
+  jl  @loop523
+  jmp @loop524
+    {end;}
+@loop525:
+{$endif}
+
+
+    { Even part: reverse the even part of the forward DCT. }
+    { The rotator is sqrt(2)*c(-6). }
+
+    {z2 := INT32 (wsptr^[2]);}
+  mov edx, DWORD PTR [esi+4*2]                   { z2 = edx }
+
+    {z3 := INT32 (wsptr^[6]);}
+  mov ecx, DWORD PTR [esi+4*6]                   { z3 = ecx }
+
+    {z1 := (z2 + z3) * INT32(FIX_0_541196100);}
+  lea   eax, [edx+ecx]
+  imul  eax, FIX_0_541196100
+  mov ebx, eax                                   { z1 = ebx }
+
+    {tmp2 := z1 + (z3) * INT32(- FIX_1_847759065);}
+  imul  ecx, (-FIX_1_847759065)
+  add ecx, ebx                                   { tmp2 = ecx }
+
+    {tmp3 := z1 + (z2) * INT32(FIX_0_765366865);}
+  imul  edx, FIX_0_765366865
+  add ebx, edx                                   { tmp3 = ebx }
+
+    {tmp0 := (INT32(wsptr^[0]) + INT32(wsptr^[4])) shl CONST_BITS;}
+    {tmp1 := (INT32(wsptr^[0]) - INT32(wsptr^[4])) shl CONST_BITS;}
+  mov edx, DWORD PTR [esi+4*4]
+  mov   eax, DWORD PTR [esi+4*0]
+  sub   eax, edx
+  add   edx, edx
+  add   edx, eax
+  shl edx, CONST_BITS              { tmp0 = edx }
+  shl eax, CONST_BITS              { tmp1 = eax }
+
+    {tmp10 := tmp0 + tmp3;}
+    {tmp13 := tmp0 - tmp3;}
+  sub   edx, ebx
+  mov tmp13, edx
+  add   ebx, ebx
+  add   edx, ebx
+  mov tmp10, edx
+
+    {tmp11 := tmp1 + tmp2;}
+    {tmp12 := tmp1 - tmp2;}
+  lea   ebx, [ecx+eax]
+  mov tmp11, ebx
+  sub eax, ecx
+  mov tmp12, eax
+
+    { Odd part per figure 8; the matrix is unitary and hence its
+      transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively. }
+
+{ The following lines no longer produce code, since wsptr has been
+  optimized to esi, it is more efficient to access these values
+  directly.
+    tmp0 := INT32(wsptr^[7]);
+    tmp1 := INT32(wsptr^[5]);
+    tmp2 := INT32(wsptr^[3]);
+    tmp3 := INT32(wsptr^[1]); }
+
+    {z2 := tmp1 + tmp2;}
+    {z2 := (z2) * INT32(- FIX_2_562915447); { sqrt(2) * (-c1-c3) }
+  mov ebx, DWORD PTR [esi+4*3]              { tmp2 }
+  mov   ecx, DWORD PTR [esi+4*5]              { tmp1 }
+  lea   eax, [ebx+ecx]
+  imul  eax, (-FIX_2_562915447)
+  mov z2, eax
+
+    {z3 := tmp0 + tmp2;}
+  mov edx, DWORD PTR [esi+4*7]              { tmp0 }
+  add   ebx, edx                              { old z3 = ebx }
+  mov eax, ebx
+    {z3 := (z3) * INT32(- FIX_1_961570560); { sqrt(2) * (-c3-c5) }
+  imul eax, (-FIX_1_961570560)
+  mov z3, eax
+
+    {z1 := tmp0 + tmp3;}
+    {z1 := (z1) * INT32(- FIX_0_899976223); { sqrt(2) * (c7-c3) }
+  mov eax, DWORD PTR [esi+4*1]               { tmp3 }
+  add edx, eax
+  imul  edx, (-FIX_0_899976223)                { z1 = edx }
+
+    {z4 := tmp1 + tmp3;}
+  add eax, ecx                              { +tmp1 }
+  add ebx, eax                              { z3 + z4 = ebx }
+    {z4 := (z4) * INT32(- FIX_0_390180644); { sqrt(2) * (c5-c3) }
+  imul eax, (-FIX_0_390180644)                { z4 = eax }
+
+    {z5 := (z3 + z4) * INT32(FIX_1_175875602); { sqrt(2) * c3 }
+    {Inc(z3, z5);}
+  imul ebx, FIX_1_175875602
+  mov  ecx, z3
+  add  ecx, ebx                                { ecx = z3 }
+
+    {Inc(z4, z5);}
+  add ebx, eax                                 { z4 = ebx }
+
+    {tmp0 := (tmp0) * INT32(FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) }
+    {Inc(tmp0, z1 + z3);}
+  mov   eax, DWORD PTR [esi+4*7]
+  imul  eax, FIX_0_298631336
+  add   eax, edx
+  add   eax, ecx
+  mov tmp0, eax
+
+    {tmp1 := (tmp1) * INT32(FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) }
+    {Inc(tmp1, z2 + z4);}
+  mov  eax, DWORD PTR [esi+4*5]
+  imul eax, FIX_2_053119869
+  add  eax, z2
+  add  eax, ebx
+  mov  tmp1, eax
+
+    {tmp2 := (tmp2) * INT32(FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) }
+    {Inc(tmp2, z2 + z3);}
+  mov eax, DWORD PTR [esi+4*3]
+  imul  eax, FIX_3_072711026
+  add   eax, z2
+  add   ecx, eax                      { ecx = tmp2 }
+
+    {tmp3 := (tmp3) * INT32(FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) }
+    {Inc(tmp3, z1 + z4);}
+  mov eax, DWORD PTR [esi+4*1]
+  imul  eax, FIX_1_501321110
+  add   eax, edx
+  add   ebx, eax                   { ebx = tmp3 }
+
+    { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 }
+
+    {outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp3,
+                      CONST_BITS+PASS1_BITS+3)) and RANGE_MASK]; }
+    {outptr^[7] := range_limit^[ int(DESCALE(tmp10 - tmp3,
+                        CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];}
+
+  mov edx, tmp10
+  add   edx, ROUND_CONST_2
+  lea eax, [ebx+edx]
+  sub   edx, ebx
+
+  shr eax, CONST_BITS+PASS1_BITS+3
+  and eax, RANGE_MASK
+  mov   ebx, range_limit           { once for all }
+  mov al, BYTE PTR [ebx+eax]
+  mov   [edi+0], al
+
+  shr edx, CONST_BITS+PASS1_BITS+3
+  and edx, RANGE_MASK
+  mov al, BYTE PTR [ebx+edx]
+  mov   [edi+7], al
+
+    {outptr^[1] := range_limit^[ int(DESCALE(tmp11 + tmp2,
+                        CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];}
+  mov eax, tmp11
+  add   eax, ROUND_CONST_2
+  lea edx, [eax+ecx]
+  shr edx, CONST_BITS+PASS1_BITS+3
+  and edx, RANGE_MASK
+  mov dl, BYTE PTR [ebx+edx]
+  mov   [edi+1], dl
+
+    {outptr^[6] := range_limit^[ int(DESCALE(tmp11 - tmp2,
+      CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];}
+  sub eax, ecx
+  shr eax, CONST_BITS+PASS1_BITS+3
+  and eax, RANGE_MASK
+  mov al, BYTE PTR [ebx+eax]
+  mov   [edi+6], al
+
+    {outptr^[2] := range_limit^[ int(DESCALE(tmp12 + tmp1,
+      CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];}
+  mov eax, tmp12
+  add   eax, ROUND_CONST_2
+  mov   ecx, tmp1
+  lea edx, [eax+ecx]
+  shr edx, CONST_BITS+PASS1_BITS+3
+  and edx, RANGE_MASK
+  mov dl, BYTE PTR [ebx+edx]
+  mov   [edi+2], dl
+
+    {outptr^[5] := range_limit^[ int(DESCALE(tmp12 - tmp1,
+      CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];}
+  sub eax, ecx
+  shr eax, CONST_BITS+PASS1_BITS+3
+  and eax, RANGE_MASK
+  mov al, BYTE PTR [ebx+eax]
+  mov   [edi+5], al
+
+    {outptr^[3] := range_limit^[ int(DESCALE(tmp13 + tmp0,
+      CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];}
+  mov eax, tmp13
+  add   eax, ROUND_CONST_2
+  mov   ecx, tmp0
+  lea   edx, [eax+ecx]
+  shr edx, CONST_BITS+PASS1_BITS+3
+  and edx, RANGE_MASK
+  mov dl, BYTE PTR [ebx+edx]
+  mov   [edi+3], dl
+
+    {outptr^[4] := range_limit^[ int(DESCALE(tmp13 - tmp0,
+      CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];}
+  sub eax, ecx
+  shr eax, CONST_BITS+PASS1_BITS+3
+  and eax, RANGE_MASK
+  mov al, BYTE PTR [ebx+eax]
+  mov   [edi+4], al
+
+    {Inc(int_ptr(wsptr), DCTSIZE);  { advance pointer to next row }
+  add esi, wrkDCTSIZE
+  add edi, DCTSIZE
+
+  {end;}
+  inc ctr
+  cmp ctr, DCTSIZE
+  jl  @loop523
+
+@loop524:
+@loop496:
+  pop   ebx
+  pop   esi
+  pop   edi
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjidctflt.pas b/src/lib/vampimg/JpegLib/imjidctflt.pas
new file mode 100644 (file)
index 0000000..febd244
--- /dev/null
@@ -0,0 +1,286 @@
+unit imjidctflt;
+
+{$N+}
+{ This file contains a floating-point implementation of the
+  inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+  must also perform dequantization of the input coefficients.
+
+  This implementation should be more accurate than either of the integer
+  IDCT implementations.  However, it may not give the same results on all
+  machines because of differences in roundoff behavior.  Speed will depend
+  on the hardware's floating point capacity.
+
+  A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+  on each row (or vice versa, but it's more convenient to emit a row at
+  a time).  Direct algorithms are also available, but they are much more
+  complex and seem not to be any faster when reduced to code.
+
+  This implementation is based on Arai, Agui, and Nakajima's algorithm for
+  scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+  Japanese, but the algorithm is described in the Pennebaker & Mitchell
+  JPEG textbook (see REFERENCES section in file README).  The following code
+  is based directly on figure 4-8 in P&M.
+  While an 8-point DCT cannot be done in less than 11 multiplies, it is
+  possible to arrange the computation so that many of the multiplies are
+  simple scalings of the final outputs.  These multiplies can then be
+  folded into the multiplications or divisions by the JPEG quantization
+  table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+  to be done in the DCT itself.
+  The primary disadvantage of this method is that with a fixed-point
+  implementation, accuracy is lost due to imprecise representation of the
+  scaled quantization values.  However, that problem does not arise if
+  we use floating point arithmetic. }
+
+{ Original: jidctflt.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdct;           { Private declarations for DCT subsystem }
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_float (cinfo : j_decompress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               coef_block : JCOEFPTR;
+               output_buf : JSAMPARRAY;
+                           output_col : JDIMENSION);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+
+{ Dequantize a coefficient by multiplying it by the multiplier-table
+  entry; produce a float result. }
+
+function DEQUANTIZE(coef : int; quantval : FAST_FLOAT) : FAST_FLOAT;
+begin
+  Dequantize := ( (coef) * quantval);
+end;
+
+{ Descale and correctly round an INT32 value that's scaled by N bits.
+  We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+  the fudge factor is correct for either sign of X. }
+
+function DESCALE(x : INT32; n : int) : INT32;
+var
+  shift_temp : INT32;
+begin
+{$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+  shift_temp := x + (INT32(1) shl (n-1));
+  if shift_temp < 0 then
+    Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+  else
+    Descale :=  (shift_temp shr n);
+{$else}
+  Descale := (x + (INT32(1) shl (n-1)) shr n;
+{$endif}
+end;
+
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_float (cinfo : j_decompress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               coef_block : JCOEFPTR;
+               output_buf : JSAMPARRAY;
+                           output_col : JDIMENSION);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = array[0..DCTSIZE2-1] of FAST_FLOAT;
+var
+  tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : FAST_FLOAT;
+  tmp10, tmp11, tmp12, tmp13 : FAST_FLOAT;
+  z5, z10, z11, z12, z13 : FAST_FLOAT;
+  inptr : JCOEFPTR;
+  quantptr : FLOAT_MULT_TYPE_FIELD_PTR;
+  wsptr : PWorkSpace;
+  outptr : JSAMPROW;
+  range_limit : JSAMPROW;
+  ctr : int;
+  workspace : TWorkspace; { buffers data between passes }
+  {SHIFT_TEMPS}
+var
+  dcval : FAST_FLOAT;
+begin
+{ Each IDCT routine is responsible for range-limiting its results and
+  converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+  be quite far out of range if the input data is corrupt, so a bulletproof
+  range-limiting step is required.  We use a mask-and-table-lookup method
+  to do the combined operations quickly.  See the comments with
+  prepare_range_limit_table (in jdmaster.c) for more info. }
+
+  range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));
+
+  { Pass 1: process columns from input, store into work array. }
+
+  inptr := coef_block;
+  quantptr := FLOAT_MULT_TYPE_FIELD_PTR (compptr^.dct_table);
+  wsptr := @workspace;
+  for ctr := pred(DCTSIZE) downto 0 do
+  begin
+    { Due to quantization, we will usually find that many of the input
+      coefficients are zero, especially the AC terms.  We can exploit this
+      by short-circuiting the IDCT calculation for any column in which all
+      the AC terms are zero.  In that case each output is equal to the
+      DC coefficient (with scale factor as needed).
+      With typical images and quantization tables, half or more of the
+      column DCT calculations can be simplified this way. }
+
+    if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and
+       (inptr^[DCTSIZE*3]=0) and (inptr^[DCTSIZE*4]=0) and
+       (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and
+       (inptr^[DCTSIZE*7]=0) then
+    begin
+      { AC terms all zero }
+      FAST_FLOAT(dcval) := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]);
+
+      wsptr^[DCTSIZE*0] := dcval;
+      wsptr^[DCTSIZE*1] := dcval;
+      wsptr^[DCTSIZE*2] := dcval;
+      wsptr^[DCTSIZE*3] := dcval;
+      wsptr^[DCTSIZE*4] := dcval;
+      wsptr^[DCTSIZE*5] := dcval;
+      wsptr^[DCTSIZE*6] := dcval;
+      wsptr^[DCTSIZE*7] := dcval;
+
+      Inc(JCOEF_PTR(inptr));    { advance pointers to next column }
+      Inc(FLOAT_MULT_TYPE_PTR(quantptr));
+      Inc(FAST_FLOAT_PTR(wsptr));
+      continue;
+    end;
+
+    { Even part }
+
+    tmp0 := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]);
+    tmp1 := DEQUANTIZE(inptr^[DCTSIZE*2], quantptr^[DCTSIZE*2]);
+    tmp2 := DEQUANTIZE(inptr^[DCTSIZE*4], quantptr^[DCTSIZE*4]);
+    tmp3 := DEQUANTIZE(inptr^[DCTSIZE*6], quantptr^[DCTSIZE*6]);
+
+    tmp10 := tmp0 + tmp2; { phase 3 }
+    tmp11 := tmp0 - tmp2;
+
+    tmp13 := tmp1 + tmp3; { phases 5-3 }
+    tmp12 := (tmp1 - tmp3) * ({FAST_FLOAT}(1.414213562)) - tmp13; { 2*c4 }
+
+    tmp0 := tmp10 + tmp13;  { phase 2 }
+    tmp3 := tmp10 - tmp13;
+    tmp1 := tmp11 + tmp12;
+    tmp2 := tmp11 - tmp12;
+
+    { Odd part }
+
+    tmp4 := DEQUANTIZE(inptr^[DCTSIZE*1], quantptr^[DCTSIZE*1]);
+    tmp5 := DEQUANTIZE(inptr^[DCTSIZE*3], quantptr^[DCTSIZE*3]);
+    tmp6 := DEQUANTIZE(inptr^[DCTSIZE*5], quantptr^[DCTSIZE*5]);
+    tmp7 := DEQUANTIZE(inptr^[DCTSIZE*7], quantptr^[DCTSIZE*7]);
+
+    z13 := tmp6 + tmp5;   { phase 6 }
+    z10 := tmp6 - tmp5;
+    z11 := tmp4 + tmp7;
+    z12 := tmp4 - tmp7;
+
+    tmp7 := z11 + z13;    { phase 5 }
+    tmp11 := (z11 - z13) * ({FAST_FLOAT}(1.414213562)); { 2*c4 }
+
+    z5 := (z10 + z12) * ({FAST_FLOAT}(1.847759065)); { 2*c2 }
+    tmp10 := ({FAST_FLOAT}(1.082392200)) * z12 - z5; { 2*(c2-c6) }
+    tmp12 := ({FAST_FLOAT}(-2.613125930)) * z10 + z5; { -2*(c2+c6) }
+
+    tmp6 := tmp12 - tmp7; { phase 2 }
+    tmp5 := tmp11 - tmp6;
+    tmp4 := tmp10 + tmp5;
+
+    wsptr^[DCTSIZE*0] := tmp0 + tmp7;
+    wsptr^[DCTSIZE*7] := tmp0 - tmp7;
+    wsptr^[DCTSIZE*1] := tmp1 + tmp6;
+    wsptr^[DCTSIZE*6] := tmp1 - tmp6;
+    wsptr^[DCTSIZE*2] := tmp2 + tmp5;
+    wsptr^[DCTSIZE*5] := tmp2 - tmp5;
+    wsptr^[DCTSIZE*4] := tmp3 + tmp4;
+    wsptr^[DCTSIZE*3] := tmp3 - tmp4;
+
+    Inc(JCOEF_PTR(inptr));    { advance pointers to next column }
+    Inc(FLOAT_MULT_TYPE_PTR(quantptr));
+    Inc(FAST_FLOAT_PTR(wsptr));
+  end;
+
+  { Pass 2: process rows from work array, store into output array. }
+  { Note that we must descale the results by a factor of 8 = 2**3. }
+
+  wsptr := @workspace;
+  for ctr := 0 to pred(DCTSIZE) do
+  begin
+    outptr := JSAMPROW(@(output_buf^[ctr]^[output_col]));
+    { Rows of zeroes can be exploited in the same way as we did with columns.
+      However, the column calculation has created many nonzero AC terms, so
+      the simplification applies less often (typically 5% to 10% of the time).
+      And testing floats for zero is relatively expensive, so we don't bother. }
+
+    { Even part }
+
+    tmp10 := wsptr^[0] + wsptr^[4];
+    tmp11 := wsptr^[0] - wsptr^[4];
+
+    tmp13 := wsptr^[2] + wsptr^[6];
+    tmp12 := (wsptr^[2] - wsptr^[6]) * ({FAST_FLOAT}(1.414213562)) - tmp13;
+
+    tmp0 := tmp10 + tmp13;
+    tmp3 := tmp10 - tmp13;
+    tmp1 := tmp11 + tmp12;
+    tmp2 := tmp11 - tmp12;
+
+    { Odd part }
+
+    z13 := wsptr^[5] + wsptr^[3];
+    z10 := wsptr^[5] - wsptr^[3];
+    z11 := wsptr^[1] + wsptr^[7];
+    z12 := wsptr^[1] - wsptr^[7];
+
+    tmp7 := z11 + z13;
+    tmp11 := (z11 - z13) * ({FAST_FLOAT}(1.414213562));
+
+    z5 := (z10 + z12) * ({FAST_FLOAT}(1.847759065)); { 2*c2 }
+    tmp10 := ({FAST_FLOAT}(1.082392200)) * z12 - z5; { 2*(c2-c6) }
+    tmp12 := ({FAST_FLOAT}(-2.613125930)) * z10 + z5; { -2*(c2+c6) }
+
+    tmp6 := tmp12 - tmp7;
+    tmp5 := tmp11 - tmp6;
+    tmp4 := tmp10 + tmp5;
+
+    { Final output stage: scale down by a factor of 8 and range-limit }
+
+    outptr^[0] := range_limit^[ int(DESCALE( INT32(Round((tmp0 + tmp7))), 3))
+          and RANGE_MASK];
+    outptr^[7] := range_limit^[ int(DESCALE( INT32(Round((tmp0 - tmp7))), 3))
+          and RANGE_MASK];
+    outptr^[1] := range_limit^[ int(DESCALE( INT32(Round((tmp1 + tmp6))), 3))
+          and RANGE_MASK];
+    outptr^[6] := range_limit^[ int(DESCALE( INT32(Round((tmp1 - tmp6))), 3))
+          and RANGE_MASK];
+    outptr^[2] := range_limit^[ int(DESCALE( INT32(Round((tmp2 + tmp5))), 3))
+          and RANGE_MASK];
+    outptr^[5] := range_limit^[ int(DESCALE( INT32(Round((tmp2 - tmp5))), 3))
+          and RANGE_MASK];
+    outptr^[4] := range_limit^[ int(DESCALE( INT32(Round((tmp3 + tmp4))), 3))
+          and RANGE_MASK];
+    outptr^[3] := range_limit^[ int(DESCALE( INT32(Round((tmp3 - tmp4))), 3))
+          and RANGE_MASK];
+
+    Inc(FAST_FLOAT_PTR(wsptr), DCTSIZE);  { advance pointer to next row }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjidctfst.pas b/src/lib/vampimg/JpegLib/imjidctfst.pas
new file mode 100644 (file)
index 0000000..f66c731
--- /dev/null
@@ -0,0 +1,410 @@
+unit imjidctfst;
+
+{ This file contains a fast, not so accurate integer implementation of the
+  inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+  must also perform dequantization of the input coefficients.
+
+  A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+  on each row (or vice versa, but it's more convenient to emit a row at
+  a time).  Direct algorithms are also available, but they are much more
+  complex and seem not to be any faster when reduced to code.
+
+  This implementation is based on Arai, Agui, and Nakajima's algorithm for
+  scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+  Japanese, but the algorithm is described in the Pennebaker & Mitchell
+  JPEG textbook (see REFERENCES section in file README).  The following code
+  is based directly on figure 4-8 in P&M.
+  While an 8-point DCT cannot be done in less than 11 multiplies, it is
+  possible to arrange the computation so that many of the multiplies are
+  simple scalings of the final outputs.  These multiplies can then be
+  folded into the multiplications or divisions by the JPEG quantization
+  table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+  to be done in the DCT itself.
+  The primary disadvantage of this method is that with fixed-point math,
+  accuracy is lost due to imprecise representation of the scaled
+  quantization values.  The smaller the quantization table entry, the less
+  precise the scaled value, so this implementation does worse with high-
+  quality-setting files than with low-quality ones. }
+
+{ Original : jidctfst.c ; Copyright (C) 1994-1996, Thomas G. Lane. }
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdct;       { Private declarations for DCT subsystem }
+
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_ifast (cinfo : j_decompress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               coef_block : JCOEFPTR;
+               output_buf : JSAMPARRAY;
+                           output_col : JDIMENSION);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+{ Scaling decisions are generally the same as in the LL&M algorithm;
+  see jidctint.c for more details.  However, we choose to descale
+  (right shift) multiplication products as soon as they are formed,
+  rather than carrying additional fractional bits into subsequent additions.
+  This compromises accuracy slightly, but it lets us save a few shifts.
+  More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+  everywhere except in the multiplications proper; this saves a good deal
+  of work on 16-bit-int machines.
+
+  The dequantized coefficients are not integers because the AA&N scaling
+  factors have been incorporated.  We represent them scaled up by PASS1_BITS,
+  so that the first and second IDCT rounds have the same input scaling.
+  For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
+  avoid a descaling shift; this compromises accuracy rather drastically
+  for small quantization table entries, but it saves a lot of shifts.
+  For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
+  so we use a much larger scaling factor to preserve accuracy.
+
+  A final compromise is to represent the multiplicative constants to only
+  8 fractional bits, rather than 13.  This saves some shifting work on some
+  machines, and may also reduce the cost of multiplication (since there
+  are fewer one-bits in the constants). }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  CONST_BITS = 8;
+  PASS1_BITS = 2;
+{$else}
+const
+  CONST_BITS = 8;
+  PASS1_BITS = 1; { lose a little precision to avoid overflow }
+{$endif}
+
+
+const
+  FIX_1_082392200 = INT32(Round((INT32(1) shl CONST_BITS)*1.082392200));  {277}
+  FIX_1_414213562 = INT32(Round((INT32(1) shl CONST_BITS)*1.414213562));  {362}
+  FIX_1_847759065 = INT32(Round((INT32(1) shl CONST_BITS)*1.847759065));  {473}
+  FIX_2_613125930 = INT32(Round((INT32(1) shl CONST_BITS)*2.613125930));  {669}
+
+
+{ Descale and correctly round an INT32 value that's scaled by N bits.
+  We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+  the fudge factor is correct for either sign of X. }
+
+function DESCALE(x : INT32; n : int) : INT32;
+var
+  shift_temp : INT32;
+begin
+{$ifdef USE_ACCURATE_ROUNDING}
+  shift_temp := x + (INT32(1) shl (n-1));
+{$else}
+{ We can gain a little more speed, with a further compromise in accuracy,
+  by omitting the addition in a descaling shift.  This yields an incorrectly
+  rounded result half the time... }
+  shift_temp := x;
+{$endif}
+
+{$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+  if shift_temp < 0 then
+    Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+  else
+{$endif}
+    Descale :=  (shift_temp shr n);
+end;
+
+
+{ Multiply a DCTELEM variable by an INT32 constant, and immediately
+  descale to yield a DCTELEM result. }
+
+  {(DCTELEM( DESCALE((var) * (const), CONST_BITS))}
+  function Multiply(Avar, Aconst: Integer): DCTELEM;
+  begin
+    Multiply := DCTELEM( Avar*INT32(Aconst) div (INT32(1) shl CONST_BITS));
+  end;
+
+
+{ Dequantize a coefficient by multiplying it by the multiplier-table
+  entry; produce a DCTELEM result.  For 8-bit data a 16x16->16
+  multiplication will do.  For 12-bit data, the multiplier table is
+  declared INT32, so a 32-bit multiply will be used. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+  function DEQUANTIZE(coef,quantval : int) : int;
+  begin
+    Dequantize := ( IFAST_MULT_TYPE(coef) * quantval);
+  end;
+{$else}
+  function DEQUANTIZE(coef,quantval : INT32) : int;
+  begin
+    Dequantize := DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS);
+  end;
+{$endif}
+
+
+{ Like DESCALE, but applies to a DCTELEM and produces an int.
+  We assume that int right shift is unsigned if INT32 right shift is. }
+
+function IDESCALE(x : DCTELEM; n : int) : int;
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  DCTELEMBITS = 16; { DCTELEM may be 16 or 32 bits }
+{$else}
+const
+  DCTELEMBITS = 32; { DCTELEM must be 32 bits }
+{$endif}
+var
+  ishift_temp : DCTELEM;
+begin
+{$ifndef USE_ACCURATE_ROUNDING}
+  ishift_temp := x + (INT32(1) shl (n-1));
+{$else}
+{ We can gain a little more speed, with a further compromise in accuracy,
+  by omitting the addition in a descaling shift.  This yields an incorrectly
+  rounded result half the time... }
+  ishift_temp := x;
+{$endif}
+
+{$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+  if ishift_temp < 0 then
+    IDescale :=  (ishift_temp shr n)
+             or ((not DCTELEM(0)) shl (DCTELEMBITS-n))
+  else
+{$endif}
+    IDescale :=  (ishift_temp shr n);
+end;
+
+
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_ifast (cinfo : j_decompress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               coef_block : JCOEFPTR;
+               output_buf : JSAMPARRAY;
+                           output_col : JDIMENSION);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = coef_bits_field; { buffers data between passes }
+var
+  tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : DCTELEM;
+  tmp10, tmp11, tmp12, tmp13 : DCTELEM;
+  z5, z10, z11, z12, z13 : DCTELEM;
+  inptr : JCOEFPTR;
+  quantptr : IFAST_MULT_TYPE_FIELD_PTR;
+  wsptr : PWorkspace;
+  outptr : JSAMPROW;
+  range_limit : JSAMPROW;
+  ctr : int;
+  workspace : TWorkspace;        { buffers data between passes }
+  {SHIFT_TEMPS}     { for DESCALE }
+  {ISHIFT_TEMPS}    { for IDESCALE }
+var
+  dcval : int;
+var
+  dcval_ : JSAMPLE;
+begin
+{ Each IDCT routine is responsible for range-limiting its results and
+  converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+  be quite far out of range if the input data is corrupt, so a bulletproof
+  range-limiting step is required.  We use a mask-and-table-lookup method
+  to do the combined operations quickly.  See the comments with
+  prepare_range_limit_table (in jdmaster.c) for more info. }
+
+  range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));
+  { Pass 1: process columns from input, store into work array. }
+
+  inptr := coef_block;
+  quantptr := IFAST_MULT_TYPE_FIELD_PTR(compptr^.dct_table);
+  wsptr := @workspace;
+  for ctr := pred(DCTSIZE) downto 0 do
+  begin
+    { Due to quantization, we will usually find that many of the input
+      coefficients are zero, especially the AC terms.  We can exploit this
+      by short-circuiting the IDCT calculation for any column in which all
+      the AC terms are zero.  In that case each output is equal to the
+      DC coefficient (with scale factor as needed).
+      With typical images and quantization tables, half or more of the
+      column DCT calculations can be simplified this way. }
+
+    if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and (inptr^[DCTSIZE*3]=0) and
+       (inptr^[DCTSIZE*4]=0) and (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and
+       (inptr^[DCTSIZE*7]=0) then
+    begin
+      { AC terms all zero }
+      dcval := int(DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]));
+
+      wsptr^[DCTSIZE*0] := dcval;
+      wsptr^[DCTSIZE*1] := dcval;
+      wsptr^[DCTSIZE*2] := dcval;
+      wsptr^[DCTSIZE*3] := dcval;
+      wsptr^[DCTSIZE*4] := dcval;
+      wsptr^[DCTSIZE*5] := dcval;
+      wsptr^[DCTSIZE*6] := dcval;
+      wsptr^[DCTSIZE*7] := dcval;
+
+      Inc(JCOEF_PTR(inptr));    { advance pointers to next column }
+      Inc(IFAST_MULT_TYPE_PTR(quantptr));
+      Inc(int_ptr(wsptr));
+      continue;
+    end;
+
+    { Even part }
+
+    tmp0 := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]);
+    tmp1 := DEQUANTIZE(inptr^[DCTSIZE*2], quantptr^[DCTSIZE*2]);
+    tmp2 := DEQUANTIZE(inptr^[DCTSIZE*4], quantptr^[DCTSIZE*4]);
+    tmp3 := DEQUANTIZE(inptr^[DCTSIZE*6], quantptr^[DCTSIZE*6]);
+
+    tmp10 := tmp0 + tmp2; { phase 3 }
+    tmp11 := tmp0 - tmp2;
+
+    tmp13 := tmp1 + tmp3; { phases 5-3 }
+    tmp12 := MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; { 2*c4 }
+
+    tmp0 := tmp10 + tmp13;  { phase 2 }
+    tmp3 := tmp10 - tmp13;
+    tmp1 := tmp11 + tmp12;
+    tmp2 := tmp11 - tmp12;
+
+    { Odd part }
+
+    tmp4 := DEQUANTIZE(inptr^[DCTSIZE*1], quantptr^[DCTSIZE*1]);
+    tmp5 := DEQUANTIZE(inptr^[DCTSIZE*3], quantptr^[DCTSIZE*3]);
+    tmp6 := DEQUANTIZE(inptr^[DCTSIZE*5], quantptr^[DCTSIZE*5]);
+    tmp7 := DEQUANTIZE(inptr^[DCTSIZE*7], quantptr^[DCTSIZE*7]);
+
+    z13 := tmp6 + tmp5;   { phase 6 }
+    z10 := tmp6 - tmp5;
+    z11 := tmp4 + tmp7;
+    z12 := tmp4 - tmp7;
+
+    tmp7 := z11 + z13;    { phase 5 }
+    tmp11 := MULTIPLY(z11 - z13, FIX_1_414213562); { 2*c4 }
+
+    z5 := MULTIPLY(z10 + z12, FIX_1_847759065); { 2*c2 }
+    tmp10 := MULTIPLY(z12, FIX_1_082392200) - z5; { 2*(c2-c6) }
+    tmp12 := MULTIPLY(z10, - FIX_2_613125930) + z5; { -2*(c2+c6) }
+
+    tmp6 := tmp12 - tmp7; { phase 2 }
+    tmp5 := tmp11 - tmp6;
+    tmp4 := tmp10 + tmp5;
+
+    wsptr^[DCTSIZE*0] := int (tmp0 + tmp7);
+    wsptr^[DCTSIZE*7] := int (tmp0 - tmp7);
+    wsptr^[DCTSIZE*1] := int (tmp1 + tmp6);
+    wsptr^[DCTSIZE*6] := int (tmp1 - tmp6);
+    wsptr^[DCTSIZE*2] := int (tmp2 + tmp5);
+    wsptr^[DCTSIZE*5] := int (tmp2 - tmp5);
+    wsptr^[DCTSIZE*4] := int (tmp3 + tmp4);
+    wsptr^[DCTSIZE*3] := int (tmp3 - tmp4);
+
+    Inc(JCOEF_PTR(inptr));    { advance pointers to next column }
+    Inc(IFAST_MULT_TYPE_PTR(quantptr));
+    Inc(int_ptr(wsptr));
+  end;
+
+  { Pass 2: process rows from work array, store into output array. }
+  { Note that we must descale the results by a factor of 8 == 2**3, }
+  { and also undo the PASS1_BITS scaling. }
+
+  wsptr := @workspace;
+  for ctr := 0 to pred(DCTSIZE) do
+  begin
+    outptr := JSAMPROW(@output_buf^[ctr]^[output_col]);
+    { Rows of zeroes can be exploited in the same way as we did with columns.
+      However, the column calculation has created many nonzero AC terms, so
+      the simplification applies less often (typically 5% to 10% of the time).
+      On machines with very fast multiplication, it's possible that the
+      test takes more time than it's worth.  In that case this section
+      may be commented out. }
+
+{$ifndef NO_ZERO_ROW_TEST}
+    if (wsptr^[1]=0) and (wsptr^[2]=0) and (wsptr^[3]=0) and (wsptr^[4]=0) and
+       (wsptr^[5]=0) and (wsptr^[6]=0) and (wsptr^[7]=0) then
+    begin
+      { AC terms all zero }
+      dcval_ := range_limit^[IDESCALE(wsptr^[0], PASS1_BITS+3)
+                          and RANGE_MASK];
+
+      outptr^[0] := dcval_;
+      outptr^[1] := dcval_;
+      outptr^[2] := dcval_;
+      outptr^[3] := dcval_;
+      outptr^[4] := dcval_;
+      outptr^[5] := dcval_;
+      outptr^[6] := dcval_;
+      outptr^[7] := dcval_;
+
+      Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row }
+      continue;
+    end;
+{$endif}
+
+    { Even part }
+
+    tmp10 := (DCTELEM(wsptr^[0]) + DCTELEM(wsptr^[4]));
+    tmp11 := (DCTELEM(wsptr^[0]) - DCTELEM(wsptr^[4]));
+
+    tmp13 := (DCTELEM(wsptr^[2]) + DCTELEM(wsptr^[6]));
+    tmp12 := MULTIPLY(DCTELEM(wsptr^[2]) - DCTELEM(wsptr^[6]), FIX_1_414213562)
+      - tmp13;
+
+    tmp0 := tmp10 + tmp13;
+    tmp3 := tmp10 - tmp13;
+    tmp1 := tmp11 + tmp12;
+    tmp2 := tmp11 - tmp12;
+
+    { Odd part }
+
+    z13 := DCTELEM(wsptr^[5]) + DCTELEM(wsptr^[3]);
+    z10 := DCTELEM(wsptr^[5]) - DCTELEM(wsptr^[3]);
+    z11 := DCTELEM(wsptr^[1]) + DCTELEM(wsptr^[7]);
+    z12 := DCTELEM(wsptr^[1]) - DCTELEM(wsptr^[7]);
+
+    tmp7 := z11 + z13;    { phase 5 }
+    tmp11 := MULTIPLY(z11 - z13, FIX_1_414213562); { 2*c4 }
+
+    z5 := MULTIPLY(z10 + z12, FIX_1_847759065); { 2*c2 }
+    tmp10 := MULTIPLY(z12, FIX_1_082392200) - z5; { 2*(c2-c6) }
+    tmp12 := MULTIPLY(z10, - FIX_2_613125930) + z5; { -2*(c2+c6) }
+
+    tmp6 := tmp12 - tmp7; { phase 2 }
+    tmp5 := tmp11 - tmp6;
+    tmp4 := tmp10 + tmp5;
+
+    { Final output stage: scale down by a factor of 8 and range-limit }
+
+    outptr^[0] := range_limit^[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
+          and RANGE_MASK];
+    outptr^[7] := range_limit^[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
+          and RANGE_MASK];
+    outptr^[1] := range_limit^[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
+          and RANGE_MASK];
+    outptr^[6] := range_limit^[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
+          and RANGE_MASK];
+    outptr^[2] := range_limit^[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
+          and RANGE_MASK];
+    outptr^[5] := range_limit^[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
+          and RANGE_MASK];
+    outptr^[4] := range_limit^[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
+          and RANGE_MASK];
+    outptr^[3] := range_limit^[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
+          and RANGE_MASK];
+
+    Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjidctint.pas b/src/lib/vampimg/JpegLib/imjidctint.pas
new file mode 100644 (file)
index 0000000..e51628b
--- /dev/null
@@ -0,0 +1,440 @@
+unit imjidctint;
+{$Q+}
+
+{ This file contains a slow-but-accurate integer implementation of the
+  inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+  must also perform dequantization of the input coefficients.
+
+  A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+  on each row (or vice versa, but it's more convenient to emit a row at
+  a time).  Direct algorithms are also available, but they are much more
+  complex and seem not to be any faster when reduced to code.
+
+  This implementation is based on an algorithm described in
+    C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+    Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+    Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+  The primary algorithm described there uses 11 multiplies and 29 adds.
+  We use their alternate method with 12 multiplies and 32 adds.
+  The advantage of this method is that no data path contains more than one
+  multiplication; this allows a very simple and accurate implementation in
+  scaled fixed-point arithmetic, with a minimal number of shifts. }
+
+{ Original : jidctint.c ;  Copyright (C) 1991-1998, Thomas G. Lane. }
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdct;         { Private declarations for DCT subsystem }
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_islow (cinfo : j_decompress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               coef_block : JCOEFPTR;
+               output_buf : JSAMPARRAY;
+                           output_col : JDIMENSION);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+{ The poop on this scaling stuff is as follows:
+
+  Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
+  larger than the true IDCT outputs.  The final outputs are therefore
+  a factor of N larger than desired; since N=8 this can be cured by
+  a simple right shift at the end of the algorithm.  The advantage of
+  this arrangement is that we save two multiplications per 1-D IDCT,
+  because the y0 and y4 inputs need not be divided by sqrt(N).
+
+  We have to do addition and subtraction of the integer inputs, which
+  is no problem, and multiplication by fractional constants, which is
+  a problem to do in integer arithmetic.  We multiply all the constants
+  by CONST_SCALE and convert them to integer constants (thus retaining
+  CONST_BITS bits of precision in the constants).  After doing a
+  multiplication we have to divide the product by CONST_SCALE, with proper
+  rounding, to produce the correct output.  This division can be done
+  cheaply as a right shift of CONST_BITS bits.  We postpone shifting
+  as long as possible so that partial sums can be added together with
+  full fractional precision.
+
+  The outputs of the first pass are scaled up by PASS1_BITS bits so that
+  they are represented to better-than-integral precision.  These outputs
+  require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+  with the recommended scaling.  (To scale up 12-bit sample data further, an
+  intermediate INT32 array would be needed.)
+
+  To avoid overflow of the 32-bit intermediate results in pass 2, we must
+  have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis
+  shows that the values given below are the most effective. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  CONST_BITS = 13;
+  PASS1_BITS = 2;
+{$else}
+const
+  CONST_BITS = 13;
+  PASS1_BITS = 1; { lose a little precision to avoid overflow }
+{$endif}
+
+const
+  CONST_SCALE = (INT32(1) shl CONST_BITS);
+
+const
+  FIX_0_298631336 = INT32(Round(CONST_SCALE * 0.298631336));  {2446}
+  FIX_0_390180644 = INT32(Round(CONST_SCALE * 0.390180644));  {3196}
+  FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100));  {4433}
+  FIX_0_765366865 = INT32(Round(CONST_SCALE * 0.765366865));  {6270}
+  FIX_0_899976223 = INT32(Round(CONST_SCALE * 0.899976223));  {7373}
+  FIX_1_175875602 = INT32(Round(CONST_SCALE * 1.175875602));  {9633}
+  FIX_1_501321110 = INT32(Round(CONST_SCALE * 1.501321110));  {12299}
+  FIX_1_847759065 = INT32(Round(CONST_SCALE * 1.847759065));  {15137}
+  FIX_1_961570560 = INT32(Round(CONST_SCALE * 1.961570560));  {16069}
+  FIX_2_053119869 = INT32(Round(CONST_SCALE * 2.053119869));  {16819}
+  FIX_2_562915447 = INT32(Round(CONST_SCALE * 2.562915447));  {20995}
+  FIX_3_072711026 = INT32(Round(CONST_SCALE * 3.072711026));  {25172}
+
+
+
+{ Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+  For 8-bit samples with the recommended scaling, all the variable
+  and constant values involved are no more than 16 bits wide, so a
+  16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+  For 12-bit samples, a full 32-bit multiplication will be needed. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+
+   {$IFDEF BASM16}
+     {$IFNDEF WIN32}
+   {MULTIPLY16C16(var,const)}
+   function Multiply(X, Y: Integer): integer; assembler;
+   asm
+     mov ax, X
+     imul Y
+     mov al, ah
+     mov ah, dl
+   end;
+     {$ENDIF}
+   {$ENDIF}
+
+   function Multiply(X, Y: INT32): INT32;
+   begin
+     Multiply := INT32(X) * INT32(Y);
+   end;
+
+
+{$else}
+  {#define MULTIPLY(var,const)  ((var) * (const))}
+   function Multiply(X, Y: INT32): INT32;
+   begin
+     Multiply := INT32(X) * INT32(Y);
+   end;
+{$endif}
+
+
+{ Dequantize a coefficient by multiplying it by the multiplier-table
+  entry; produce an int result.  In this module, both inputs and result
+  are 16 bits or less, so either int or short multiply will work. }
+
+function DEQUANTIZE(coef,quantval : int) : int;
+begin
+  Dequantize := ( ISLOW_MULT_TYPE(coef) * quantval);
+end;
+
+{ Descale and correctly round an INT32 value that's scaled by N bits.
+  We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+  the fudge factor is correct for either sign of X. }
+
+function DESCALE(x : INT32; n : int) : INT32;
+var
+  shift_temp : INT32;
+begin
+{$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+  shift_temp := x + (INT32(1) shl (n-1));
+  if shift_temp < 0 then
+    Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+  else
+    Descale :=  (shift_temp shr n);
+{$else}
+  Descale := (x + (INT32(1) shl (n-1)) shr n;
+{$endif}
+end;
+
+{ Perform dequantization and inverse DCT on one block of coefficients. }
+
+{GLOBAL}
+procedure jpeg_idct_islow (cinfo : j_decompress_ptr;
+                           compptr : jpeg_component_info_ptr;
+               coef_block : JCOEFPTR;
+               output_buf : JSAMPARRAY;
+                           output_col : JDIMENSION);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = coef_bits_field; { buffers data between passes }
+var
+  tmp0, tmp1, tmp2, tmp3 : INT32;
+  tmp10, tmp11, tmp12, tmp13 : INT32;
+  z1, z2, z3, z4, z5 : INT32;
+  inptr : JCOEFPTR;
+  quantptr : ISLOW_MULT_TYPE_FIELD_PTR;
+  wsptr : PWorkspace;
+  outptr : JSAMPROW;
+  range_limit : JSAMPROW;
+  ctr : int;
+  workspace : TWorkspace;
+  {SHIFT_TEMPS}
+var
+  dcval : int;
+var
+  dcval_ : JSAMPLE;
+begin
+{ Each IDCT routine is responsible for range-limiting its results and
+  converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+  be quite far out of range if the input data is corrupt, so a bulletproof
+  range-limiting step is required.  We use a mask-and-table-lookup method
+  to do the combined operations quickly.  See the comments with
+  prepare_range_limit_table (in jdmaster.c) for more info. }
+
+  range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));
+
+
+  { Pass 1: process columns from input, store into work array. }
+  { Note results are scaled up by sqrt(8) compared to a true IDCT; }
+  { furthermore, we scale the results by 2**PASS1_BITS. }
+
+  inptr := coef_block;
+  quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table);
+  wsptr := PWorkspace(@workspace);
+  for ctr := pred(DCTSIZE) downto 0 do
+  begin
+    { Due to quantization, we will usually find that many of the input
+      coefficients are zero, especially the AC terms.  We can exploit this
+      by short-circuiting the IDCT calculation for any column in which all
+      the AC terms are zero.  In that case each output is equal to the
+      DC coefficient (with scale factor as needed).
+      With typical images and quantization tables, half or more of the
+      column DCT calculations can be simplified this way. }
+
+    if ((inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and
+        (inptr^[DCTSIZE*3]=0) and (inptr^[DCTSIZE*4]=0) and
+        (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and
+  (inptr^[DCTSIZE*7]=0)) then
+    begin
+      { AC terms all zero }
+      dcval := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]) shl PASS1_BITS;
+
+      wsptr^[DCTSIZE*0] := dcval;
+      wsptr^[DCTSIZE*1] := dcval;
+      wsptr^[DCTSIZE*2] := dcval;
+      wsptr^[DCTSIZE*3] := dcval;
+      wsptr^[DCTSIZE*4] := dcval;
+      wsptr^[DCTSIZE*5] := dcval;
+      wsptr^[DCTSIZE*6] := dcval;
+      wsptr^[DCTSIZE*7] := dcval;
+
+      Inc(JCOEF_PTR(inptr));    { advance pointers to next column }
+      Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+      Inc(int_ptr(wsptr));
+      continue;
+    end;
+
+    { Even part: reverse the even part of the forward DCT. }
+    { The rotator is sqrt(2)*c(-6). }
+
+    z2 := DEQUANTIZE(inptr^[DCTSIZE*2], quantptr^[DCTSIZE*2]);
+    z3 := DEQUANTIZE(inptr^[DCTSIZE*6], quantptr^[DCTSIZE*6]);
+
+    z1 := MULTIPLY(z2 + z3, FIX_0_541196100);
+    tmp2 := z1 + MULTIPLY(z3, - FIX_1_847759065);
+    tmp3 := z1 + MULTIPLY(z2, FIX_0_765366865);
+
+    z2 := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]);
+    z3 := DEQUANTIZE(inptr^[DCTSIZE*4], quantptr^[DCTSIZE*4]);
+
+    tmp0 := (z2 + z3) shl CONST_BITS;
+    tmp1 := (z2 - z3) shl CONST_BITS;
+
+    tmp10 := tmp0 + tmp3;
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    { Odd part per figure 8; the matrix is unitary and hence its
+      transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively. }
+
+    tmp0 := DEQUANTIZE(inptr^[DCTSIZE*7], quantptr^[DCTSIZE*7]);
+    tmp1 := DEQUANTIZE(inptr^[DCTSIZE*5], quantptr^[DCTSIZE*5]);
+    tmp2 := DEQUANTIZE(inptr^[DCTSIZE*3], quantptr^[DCTSIZE*3]);
+    tmp3 := DEQUANTIZE(inptr^[DCTSIZE*1], quantptr^[DCTSIZE*1]);
+
+    z1 := tmp0 + tmp3;
+    z2 := tmp1 + tmp2;
+    z3 := tmp0 + tmp2;
+    z4 := tmp1 + tmp3;
+    z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 }
+
+    tmp0 := MULTIPLY(tmp0, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) }
+    tmp1 := MULTIPLY(tmp1, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) }
+    tmp2 := MULTIPLY(tmp2, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) }
+    tmp3 := MULTIPLY(tmp3, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) }
+    z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) }
+    z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) }
+    z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) }
+    z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) }
+
+    Inc(z3, z5);
+    Inc(z4, z5);
+
+    Inc(tmp0, z1 + z3);
+    Inc(tmp1, z2 + z4);
+    Inc(tmp2, z2 + z3);
+    Inc(tmp3, z1 + z4);
+
+    { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 }
+
+    wsptr^[DCTSIZE*0] := int (DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS));
+    wsptr^[DCTSIZE*7] := int (DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS));
+    wsptr^[DCTSIZE*1] := int (DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS));
+    wsptr^[DCTSIZE*6] := int (DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS));
+    wsptr^[DCTSIZE*2] := int (DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS));
+    wsptr^[DCTSIZE*5] := int (DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS));
+    wsptr^[DCTSIZE*3] := int (DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS));
+    wsptr^[DCTSIZE*4] := int (DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS));
+
+    Inc(JCOEF_PTR(inptr));    { advance pointers to next column }
+    Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+    Inc(int_ptr(wsptr));
+  end;
+
+  { Pass 2: process rows from work array, store into output array. }
+  { Note that we must descale the results by a factor of 8 == 2**3, }
+  { and also undo the PASS1_BITS scaling. }
+
+  wsptr := @workspace;
+  for ctr := 0 to pred(DCTSIZE) do
+  begin
+    outptr := output_buf^[ctr];
+    Inc(JSAMPLE_PTR(outptr), output_col);
+    { Rows of zeroes can be exploited in the same way as we did with columns.
+      However, the column calculation has created many nonzero AC terms, so
+      the simplification applies less often (typically 5% to 10% of the time).
+      On machines with very fast multiplication, it's possible that the
+      test takes more time than it's worth.  In that case this section
+      may be commented out. }
+
+{$ifndef NO_ZERO_ROW_TEST}
+    if ((wsptr^[1]=0) and (wsptr^[2]=0) and (wsptr^[3]=0) and (wsptr^[4]=0)
+       and (wsptr^[5]=0) and (wsptr^[6]=0) and (wsptr^[7]=0)) then
+    begin
+      { AC terms all zero }
+      JSAMPLE(dcval_) := range_limit^[int(DESCALE(INT32(wsptr^[0]),
+                          PASS1_BITS+3)) and RANGE_MASK];
+
+      outptr^[0] := dcval_;
+      outptr^[1] := dcval_;
+      outptr^[2] := dcval_;
+      outptr^[3] := dcval_;
+      outptr^[4] := dcval_;
+      outptr^[5] := dcval_;
+      outptr^[6] := dcval_;
+      outptr^[7] := dcval_;
+
+      Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row }
+      continue;
+    end;
+{$endif}
+
+    { Even part: reverse the even part of the forward DCT. }
+    { The rotator is sqrt(2)*c(-6). }
+
+    z2 := INT32 (wsptr^[2]);
+    z3 := INT32 (wsptr^[6]);
+
+    z1 := MULTIPLY(z2 + z3, FIX_0_541196100);
+    tmp2 := z1 + MULTIPLY(z3, - FIX_1_847759065);
+    tmp3 := z1 + MULTIPLY(z2, FIX_0_765366865);
+
+    tmp0 := (INT32(wsptr^[0]) + INT32(wsptr^[4])) shl CONST_BITS;
+    tmp1 := (INT32(wsptr^[0]) - INT32(wsptr^[4])) shl CONST_BITS;
+
+    tmp10 := tmp0 + tmp3;
+    tmp13 := tmp0 - tmp3;
+    tmp11 := tmp1 + tmp2;
+    tmp12 := tmp1 - tmp2;
+
+    { Odd part per figure 8; the matrix is unitary and hence its
+      transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively. }
+
+    tmp0 := INT32(wsptr^[7]);
+    tmp1 := INT32(wsptr^[5]);
+    tmp2 := INT32(wsptr^[3]);
+    tmp3 := INT32(wsptr^[1]);
+
+    z1 := tmp0 + tmp3;
+    z2 := tmp1 + tmp2;
+    z3 := tmp0 + tmp2;
+    z4 := tmp1 + tmp3;
+    z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 }
+
+    tmp0 := MULTIPLY(tmp0, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) }
+    tmp1 := MULTIPLY(tmp1, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) }
+    tmp2 := MULTIPLY(tmp2, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) }
+    tmp3 := MULTIPLY(tmp3, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) }
+    z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) }
+    z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) }
+    z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) }
+    z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) }
+
+    Inc(z3, z5);
+    Inc(z4, z5);
+
+    Inc(tmp0, z1 + z3);
+    Inc(tmp1, z2 + z4);
+    Inc(tmp2, z2 + z3);
+    Inc(tmp3, z1 + z4);
+
+    { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 }
+
+    outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp3,
+            CONST_BITS+PASS1_BITS+3))
+          and RANGE_MASK];
+    outptr^[7] := range_limit^[ int(DESCALE(tmp10 - tmp3,
+            CONST_BITS+PASS1_BITS+3))
+          and RANGE_MASK];
+    outptr^[1] := range_limit^[ int(DESCALE(tmp11 + tmp2,
+            CONST_BITS+PASS1_BITS+3))
+          and RANGE_MASK];
+    outptr^[6] := range_limit^[ int(DESCALE(tmp11 - tmp2,
+                                          CONST_BITS+PASS1_BITS+3))
+                            and RANGE_MASK];
+    outptr^[2] := range_limit^[ int(DESCALE(tmp12 + tmp1,
+                                          CONST_BITS+PASS1_BITS+3))
+                            and RANGE_MASK];
+    outptr^[5] := range_limit^[ int(DESCALE(tmp12 - tmp1,
+                                          CONST_BITS+PASS1_BITS+3))
+                            and RANGE_MASK];
+    outptr^[3] := range_limit^[ int(DESCALE(tmp13 + tmp0,
+                                          CONST_BITS+PASS1_BITS+3))
+                            and RANGE_MASK];
+    outptr^[4] := range_limit^[ int(DESCALE(tmp13 - tmp0,
+                                          CONST_BITS+PASS1_BITS+3))
+                            and RANGE_MASK];
+
+    Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row }
+  end;
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjidctred.pas b/src/lib/vampimg/JpegLib/imjidctred.pas
new file mode 100644 (file)
index 0000000..27a0e43
--- /dev/null
@@ -0,0 +1,525 @@
+unit imjidctred;
+
+
+{ This file contains inverse-DCT routines that produce reduced-size output:
+  either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block.
+
+  The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M)
+  algorithm used in jidctint.c.  We simply replace each 8-to-8 1-D IDCT step
+  with an 8-to-4 step that produces the four averages of two adjacent outputs
+  (or an 8-to-2 step producing two averages of four outputs, for 2x2 output).
+  These steps were derived by computing the corresponding values at the end
+  of the normal LL&M code, then simplifying as much as possible.
+
+  1x1 is trivial: just take the DC coefficient divided by 8.
+
+  See jidctint.c for additional comments. }
+
+
+{ Original : jidctred.c ; Copyright (C) 1994-1998, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib,
+  imjdct;           { Private declarations for DCT subsystem }
+
+{ Perform dequantization and inverse DCT on one block of coefficients,
+  producing a reduced-size 1x1 output block. }
+
+{GLOBAL}
+procedure jpeg_idct_1x1 (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   coef_block : JCOEFPTR;
+                   output_buf : JSAMPARRAY;
+                         output_col : JDIMENSION);
+
+{ Perform dequantization and inverse DCT on one block of coefficients,
+  producing a reduced-size 2x2 output block. }
+
+{GLOBAL}
+procedure jpeg_idct_2x2 (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   coef_block : JCOEFPTR;
+                         output_buf : JSAMPARRAY;
+                         output_col : JDIMENSION);
+
+{ Perform dequantization and inverse DCT on one block of coefficients,
+  producing a reduced-size 4x4 output block. }
+
+{GLOBAL}
+procedure jpeg_idct_4x4 (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   coef_block : JCOEFPTR;
+                   output_buf : JSAMPARRAY;
+                         output_col : JDIMENSION);
+
+implementation
+
+{ This module is specialized to the case DCTSIZE = 8. }
+
+{$ifndef DCTSIZE_IS_8}
+  Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err }
+{$endif}
+
+
+{ Scaling is the same as in jidctint.c. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+const
+  CONST_BITS = 13;
+  PASS1_BITS = 2;
+{$else}
+const
+  CONST_BITS = 13;
+  PASS1_BITS = 1; { lose a little precision to avoid overflow }
+{$endif}
+
+const
+  FIX_0_211164243 = INT32(Round((INT32(1) shl CONST_BITS) * 0.211164243)); {1730}
+  FIX_0_509795579 = INT32(Round((INT32(1) shl CONST_BITS) * 0.509795579)); {4176}
+  FIX_0_601344887 = INT32(Round((INT32(1) shl CONST_BITS) * 0.601344887)); {4926}
+  FIX_0_720959822 = INT32(Round((INT32(1) shl CONST_BITS) * 0.720959822)); {5906}
+  FIX_0_765366865 = INT32(Round((INT32(1) shl CONST_BITS) * 0.765366865)); {6270}
+  FIX_0_850430095 = INT32(Round((INT32(1) shl CONST_BITS) * 0.850430095)); {6967}
+  FIX_0_899976223 = INT32(Round((INT32(1) shl CONST_BITS) * 0.899976223)); {7373}
+  FIX_1_061594337 = INT32(Round((INT32(1) shl CONST_BITS) * 1.061594337)); {8697}
+  FIX_1_272758580 = INT32(Round((INT32(1) shl CONST_BITS) * 1.272758580)); {10426}
+  FIX_1_451774981 = INT32(Round((INT32(1) shl CONST_BITS) * 1.451774981)); {11893}
+  FIX_1_847759065 = INT32(Round((INT32(1) shl CONST_BITS) * 1.847759065)); {15137}
+  FIX_2_172734803 = INT32(Round((INT32(1) shl CONST_BITS) * 2.172734803)); {17799}
+  FIX_2_562915447 = INT32(Round((INT32(1) shl CONST_BITS) * 2.562915447)); {20995}
+  FIX_3_624509785 = INT32(Round((INT32(1) shl CONST_BITS) * 3.624509785)); {29692}
+
+
+{ Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+  For 8-bit samples with the recommended scaling, all the variable
+  and constant values involved are no more than 16 bits wide, so a
+  16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+  For 12-bit samples, a full 32-bit multiplication will be needed. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+
+   {function Multiply(X, Y: Integer): integer; assembler;
+   asm
+     mov ax, X
+     imul Y
+     mov al, ah
+     mov ah, dl
+   end;}
+
+   {MULTIPLY16C16(var,const)}
+   function Multiply(X, Y: Integer): INT32;
+   begin
+     Multiply := X*INT32(Y);
+   end;
+
+
+{$else}
+   function Multiply(X, Y: INT32): INT32;
+   begin
+     Multiply := X*Y;
+   end;
+{$endif}
+
+
+{ Dequantize a coefficient by multiplying it by the multiplier-table
+  entry; produce an int result.  In this module, both inputs and result
+  are 16 bits or less, so either int or short multiply will work. }
+
+function DEQUANTIZE(coef,quantval : int) : int;
+begin
+  Dequantize := ( ISLOW_MULT_TYPE(coef) * quantval);
+end;
+
+
+{ Descale and correctly round an INT32 value that's scaled by N bits.
+  We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+  the fudge factor is correct for either sign of X. }
+
+function DESCALE(x : INT32; n : int) : INT32;
+var
+  shift_temp : INT32;
+begin
+{$ifdef RIGHT_SHIFT_IS_UNSIGNED}
+  shift_temp := x + (INT32(1) shl (n-1));
+  if shift_temp < 0 then
+    Descale :=  (shift_temp shr n) or ((not INT32(0)) shl (32-n))
+  else
+    Descale :=  (shift_temp shr n);
+{$else}
+  Descale := (x + (INT32(1) shl (n-1)) shr n;
+{$endif}
+end;
+
+{ Perform dequantization and inverse DCT on one block of coefficients,
+  producing a reduced-size 4x4 output block. }
+
+{GLOBAL}
+procedure jpeg_idct_4x4 (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   coef_block : JCOEFPTR;
+                   output_buf : JSAMPARRAY;
+                         output_col : JDIMENSION);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = array[0..(DCTSIZE*4)-1] of int; { buffers data between passes }
+var
+  tmp0, tmp2, tmp10, tmp12 : INT32;
+  z1, z2, z3, z4 : INT32;
+  inptr : JCOEFPTR;
+  quantptr : ISLOW_MULT_TYPE_FIELD_PTR;
+  wsptr : PWorkspace;
+  outptr : JSAMPROW;
+  range_limit : JSAMPROW;
+  ctr : int;
+  workspace : TWorkspace; { buffers data between passes }
+  {SHIFT_TEMPS}
+var
+  dcval : int;
+var
+  dcval_ : JSAMPLE;
+begin
+{ Each IDCT routine is responsible for range-limiting its results and
+  converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+  be quite far out of range if the input data is corrupt, so a bulletproof
+  range-limiting step is required.  We use a mask-and-table-lookup method
+  to do the combined operations quickly.  See the comments with
+  prepare_range_limit_table (in jdmaster.c) for more info. }
+
+  range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));
+
+  { Pass 1: process columns from input, store into work array. }
+
+  inptr := coef_block;
+  quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table);
+  wsptr := @workspace;
+  for ctr := DCTSIZE downto 1 do
+  begin
+    { Don't bother to process column 4, because second pass won't use it }
+    if (ctr = DCTSIZE-4) then
+    begin
+      Inc(JCOEF_PTR(inptr));
+      Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+      Inc(int_ptr(wsptr));
+
+      continue;
+    end;
+    if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and (inptr^[DCTSIZE*3]=0) and
+       (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and (inptr^[DCTSIZE*7]=0) then
+    begin
+      { AC terms all zero; we need not examine term 4 for 4x4 output }
+      dcval := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) *
+                      quantptr^[DCTSIZE*0]) shl PASS1_BITS;
+
+      wsptr^[DCTSIZE*0] := dcval;
+      wsptr^[DCTSIZE*1] := dcval;
+      wsptr^[DCTSIZE*2] := dcval;
+      wsptr^[DCTSIZE*3] := dcval;
+
+      Inc(JCOEF_PTR(inptr));
+      Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+      Inc(int_ptr(wsptr));
+
+      continue;
+    end;
+
+    { Even part }
+
+    tmp0 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * quantptr^[DCTSIZE*0]);
+
+    tmp0 := tmp0 shl (CONST_BITS+1);
+
+    z2 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*2]) * quantptr^[DCTSIZE*2]);
+    z3 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*6]) * quantptr^[DCTSIZE*6]);
+
+    tmp2 := MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865);
+
+    tmp10 := tmp0 + tmp2;
+    tmp12 := tmp0 - tmp2;
+
+    { Odd part }
+
+    z1 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*7]) * quantptr^[DCTSIZE*7];
+    z2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*5]) * quantptr^[DCTSIZE*5];
+    z3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*3]) * quantptr^[DCTSIZE*3];
+    z4 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*1]) * quantptr^[DCTSIZE*1];
+
+    tmp0 := MULTIPLY(z1, - FIX_0_211164243) { sqrt(2) * (c3-c1) }
+    + MULTIPLY(z2, FIX_1_451774981) { sqrt(2) * (c3+c7) }
+    + MULTIPLY(z3, - FIX_2_172734803) { sqrt(2) * (-c1-c5) }
+    + MULTIPLY(z4, FIX_1_061594337); { sqrt(2) * (c5+c7) }
+
+    tmp2 := MULTIPLY(z1, - FIX_0_509795579) { sqrt(2) * (c7-c5) }
+    + MULTIPLY(z2, - FIX_0_601344887) { sqrt(2) * (c5-c1) }
+    + MULTIPLY(z3, FIX_0_899976223) { sqrt(2) * (c3-c7) }
+    + MULTIPLY(z4, FIX_2_562915447); { sqrt(2) * (c1+c3) }
+
+    { Final output stage }
+
+    wsptr^[DCTSIZE*0] := int(DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1));
+    wsptr^[DCTSIZE*3] := int(DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1));
+    wsptr^[DCTSIZE*1] := int(DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1));
+    wsptr^[DCTSIZE*2] := int(DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1));
+
+    Inc(JCOEF_PTR(inptr));
+    Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+    Inc(int_ptr(wsptr));
+  end;
+
+  { Pass 2: process 4 rows from work array, store into output array. }
+
+  wsptr := @workspace;
+  for ctr := 0 to pred(4) do
+  begin
+    outptr := JSAMPROW(@ output_buf^[ctr]^[output_col]);
+    { It's not clear whether a zero row test is worthwhile here ... }
+
+{$ifndef NO_ZERO_ROW_TEST}
+    if (wsptr^[1]=0) and (wsptr^[2]=0) and (wsptr^[3]=0) and
+       (wsptr^[5]=0) and (wsptr^[6]=0) and (wsptr^[7]=0) then
+    begin
+      { AC terms all zero }
+      dcval_ := range_limit^[int(DESCALE(INT32(wsptr^[0]), PASS1_BITS+3))
+          and RANGE_MASK];
+
+      outptr^[0] := dcval_;
+      outptr^[1] := dcval_;
+      outptr^[2] := dcval_;
+      outptr^[3] := dcval_;
+
+      Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row }
+      continue;
+    end;
+{$endif}
+
+    { Even part }
+
+    tmp0 := (INT32(wsptr^[0])) shl (CONST_BITS+1);
+
+    tmp2 := MULTIPLY(INT32(wsptr^[2]), FIX_1_847759065)
+    + MULTIPLY(INT32(wsptr^[6]), - FIX_0_765366865);
+
+    tmp10 := tmp0 + tmp2;
+    tmp12 := tmp0 - tmp2;
+
+    { Odd part }
+
+    z1 := INT32(wsptr^[7]);
+    z2 := INT32(wsptr^[5]);
+    z3 := INT32(wsptr^[3]);
+    z4 := INT32(wsptr^[1]);
+
+    tmp0 := MULTIPLY(z1, - FIX_0_211164243) { sqrt(2) * (c3-c1) }
+    + MULTIPLY(z2, FIX_1_451774981) { sqrt(2) * (c3+c7) }
+    + MULTIPLY(z3, - FIX_2_172734803) { sqrt(2) * (-c1-c5) }
+    + MULTIPLY(z4, FIX_1_061594337); { sqrt(2) * (c5+c7) }
+
+    tmp2 := MULTIPLY(z1, - FIX_0_509795579) { sqrt(2) * (c7-c5) }
+    + MULTIPLY(z2, - FIX_0_601344887) { sqrt(2) * (c5-c1) }
+    + MULTIPLY(z3, FIX_0_899976223) { sqrt(2) * (c3-c7) }
+    + MULTIPLY(z4, FIX_2_562915447); { sqrt(2) * (c1+c3) }
+
+    { Final output stage }
+
+    outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp2,
+            CONST_BITS+PASS1_BITS+3+1))
+          and RANGE_MASK];
+    outptr^[3] := range_limit^[ int(DESCALE(tmp10 - tmp2,
+            CONST_BITS+PASS1_BITS+3+1))
+          and RANGE_MASK];
+    outptr^[1] := range_limit^[ int(DESCALE(tmp12 + tmp0,
+            CONST_BITS+PASS1_BITS+3+1))
+          and RANGE_MASK];
+    outptr^[2] := range_limit^[ int(DESCALE(tmp12 - tmp0,
+            CONST_BITS+PASS1_BITS+3+1))
+          and RANGE_MASK];
+
+    Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row }
+  end;
+end;
+
+
+{ Perform dequantization and inverse DCT on one block of coefficients,
+  producing a reduced-size 2x2 output block. }
+
+{GLOBAL}
+procedure jpeg_idct_2x2 (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   coef_block : JCOEFPTR;
+                         output_buf : JSAMPARRAY;
+                         output_col : JDIMENSION);
+type
+  PWorkspace = ^TWorkspace;
+  TWorkspace = array[0..(DCTSIZE*2)-1] of int; { buffers data between passes }
+var
+  tmp0, tmp10, z1 : INT32;
+  inptr : JCOEFPTR;
+  quantptr : ISLOW_MULT_TYPE_FIELD_PTR;
+  wsptr : PWorkspace;
+  outptr : JSAMPROW;
+  range_limit : JSAMPROW;
+  ctr : int;
+  workspace : TWorkspace;  { buffers data between passes }
+  {SHIFT_TEMPS}
+var
+  dcval : int;
+var
+  dcval_ : JSAMPLE;
+begin
+{ Each IDCT routine is responsible for range-limiting its results and
+  converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+  be quite far out of range if the input data is corrupt, so a bulletproof
+  range-limiting step is required.  We use a mask-and-table-lookup method
+  to do the combined operations quickly.  See the comments with
+  prepare_range_limit_table (in jdmaster.c) for more info. }
+
+  range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));
+  { Pass 1: process columns from input, store into work array. }
+
+  inptr := coef_block;
+  quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table);
+  wsptr := @workspace;
+  for ctr := DCTSIZE downto 1 do
+  begin
+    { Don't bother to process columns 2,4,6 }
+    if (ctr = DCTSIZE-2) or (ctr = DCTSIZE-4) or (ctr = DCTSIZE-6) then
+    begin
+      Inc(JCOEF_PTR(inptr));
+      Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+      Inc(int_ptr(wsptr));
+
+      continue;
+    end;
+    if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*3]=0) and
+       (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*7]=0) then
+    begin
+      { AC terms all zero; we need not examine terms 2,4,6 for 2x2 output }
+      dcval := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) *
+                 quantptr^[DCTSIZE*0]) shl PASS1_BITS;
+
+      wsptr^[DCTSIZE*0] := dcval;
+      wsptr^[DCTSIZE*1] := dcval;
+
+      Inc(JCOEF_PTR(inptr));
+      Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+      Inc(int_ptr(wsptr));
+
+      continue;
+    end;
+
+    { Even part }
+
+    z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * quantptr^[DCTSIZE*0]);
+
+    tmp10 := z1 shl (CONST_BITS+2);
+
+    { Odd part }
+
+    z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*7]) * quantptr^[DCTSIZE*7]);
+    tmp0 := MULTIPLY(z1, - FIX_0_720959822); { sqrt(2) * (c7-c5+c3-c1) }
+    z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*5]) * quantptr^[DCTSIZE*5]);
+    Inc(tmp0, MULTIPLY(z1, FIX_0_850430095)); { sqrt(2) * (-c1+c3+c5+c7) }
+    z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*3]) * quantptr^[DCTSIZE*3]);
+    Inc(tmp0, MULTIPLY(z1, - FIX_1_272758580)); { sqrt(2) * (-c1+c3-c5-c7) }
+    z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*1]) * quantptr^[DCTSIZE*1]);
+    Inc(tmp0, MULTIPLY(z1, FIX_3_624509785)); { sqrt(2) * (c1+c3+c5+c7) }
+
+    { Final output stage }
+
+    wsptr^[DCTSIZE*0] := int (DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2));
+    wsptr^[DCTSIZE*1] := int (DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2));
+
+    Inc(JCOEF_PTR(inptr));
+    Inc(ISLOW_MULT_TYPE_PTR(quantptr));
+    Inc(int_ptr(wsptr));
+  end;
+
+  { Pass 2: process 2 rows from work array, store into output array. }
+
+  wsptr := @workspace;
+  for ctr := 0 to pred(2) do
+  begin
+    outptr := JSAMPROW(@ output_buf^[ctr]^[output_col]);
+    { It's not clear whether a zero row test is worthwhile here ... }
+
+{$ifndef NO_ZERO_ROW_TEST}
+    if (wsptr^[1]=0) and (wsptr^[3]=0) and (wsptr^[5]=0) and (wsptr^[7]= 0) then
+    begin
+      { AC terms all zero }
+      dcval_ := range_limit^[ int(DESCALE(INT32(wsptr^[0]), PASS1_BITS+3))
+          and RANGE_MASK];
+
+      outptr^[0] := dcval_;
+      outptr^[1] := dcval_;
+
+      Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row }
+      continue;
+    end;
+{$endif}
+
+    { Even part }
+
+    tmp10 := (INT32 (wsptr^[0])) shl (CONST_BITS+2);
+
+    { Odd part }
+
+    tmp0 := MULTIPLY( INT32(wsptr^[7]), - FIX_0_720959822) { sqrt(2) * (c7-c5+c3-c1) }
+    + MULTIPLY( INT32(wsptr^[5]), FIX_0_850430095) { sqrt(2) * (-c1+c3+c5+c7) }
+    + MULTIPLY( INT32(wsptr^[3]), - FIX_1_272758580) { sqrt(2) * (-c1+c3-c5-c7) }
+    + MULTIPLY( INT32(wsptr^[1]), FIX_3_624509785); { sqrt(2) * (c1+c3+c5+c7) }
+
+    { Final output stage }
+
+    outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp0,
+            CONST_BITS+PASS1_BITS+3+2))
+          and RANGE_MASK];
+    outptr^[1] := range_limit^[ int(DESCALE(tmp10 - tmp0,
+            CONST_BITS+PASS1_BITS+3+2))
+          and RANGE_MASK];
+
+    Inc(int_ptr(wsptr), DCTSIZE);   { advance pointer to next row }
+  end;
+end;
+
+
+{ Perform dequantization and inverse DCT on one block of coefficients,
+  producing a reduced-size 1x1 output block. }
+
+{GLOBAL}
+procedure jpeg_idct_1x1 (cinfo : j_decompress_ptr;
+                         compptr : jpeg_component_info_ptr;
+                   coef_block : JCOEFPTR;
+                   output_buf : JSAMPARRAY;
+                         output_col : JDIMENSION);
+var
+  dcval : int;
+  quantptr : ISLOW_MULT_TYPE_FIELD_PTR;
+  range_limit : JSAMPROW;
+  {SHIFT_TEMPS}
+begin
+{ Each IDCT routine is responsible for range-limiting its results and
+  converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could
+  be quite far out of range if the input data is corrupt, so a bulletproof
+  range-limiting step is required.  We use a mask-and-table-lookup method
+  to do the combined operations quickly.  See the comments with
+  prepare_range_limit_table (in jdmaster.c) for more info. }
+
+  range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));
+  { Pass 1: process columns from input, store into work array. }
+
+  { We hardly need an inverse DCT routine for this: just take the
+    average pixel value, which is one-eighth of the DC coefficient. }
+
+  quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table);
+  dcval := (ISLOW_MULT_TYPE(coef_block^[0]) * quantptr^[0]);
+  dcval := int (DESCALE( INT32(dcval), 3));
+
+  output_buf^[0]^[output_col] := range_limit^[dcval and RANGE_MASK];
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjinclude.pas b/src/lib/vampimg/JpegLib/imjinclude.pas
new file mode 100644 (file)
index 0000000..dcaa684
--- /dev/null
@@ -0,0 +1,126 @@
+unit imjinclude;
+
+{ This file exists to provide a single place to fix any problems with
+  including the wrong system include files.  (Common problems are taken
+  care of by the standard jconfig symbols, but on really weird systems
+  you may have to edit this file.)
+
+  NOTE: this file is NOT intended to be included by applications using the
+  JPEG library.  Most applications need only include jpeglib.h. }
+
+{ Original: jinclude.h Copyright (C) 1991-1994, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+{ Include auto-config file to find out which system include files we need. }
+
+uses
+{$ifdef Delphi_Stream}
+  classes,
+{$endif}
+  imjmorecfg;
+
+{ Nomssi:
+  To write a dest/source manager that handle streams rather than files,
+  you can edit the FILEptr definition and the JFREAD() and JFWRITE()
+  functions in this unit, you don't need to change the default managers
+  JDATASRC and JDATADST. }
+
+{$ifdef Delphi_Stream}
+type
+  FILEptr = ^TStream;
+{$else}
+  {$ifdef Delphi_Jpeg}
+  type
+    FILEptr = TCustomMemoryStream;
+  {$else}
+  type
+    FILEptr = ^File;
+  {$endif}
+{$endif}
+
+{ We need the NULL macro and size_t typedef.
+  On an ANSI-conforming system it is sufficient to include <stddef.h>.
+  Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
+  pull in <sys/types.h> as well.
+  Note that the core JPEG library does not require <stdio.h>;
+  only the default error handler and data source/destination modules do.
+  But we must pull it in because of the references to FILE in jpeglib.h.
+  You can remove those references if you want to compile without <stdio.h>.}
+
+
+
+{ We need memory copying and zeroing functions, plus strncpy().
+  ANSI and System V implementations declare these in <string.h>.
+  BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
+  Some systems may declare memset and memcpy in <memory.h>.
+
+  NOTE: we assume the size parameters to these functions are of type size_t.
+  Change the casts in these macros if not! }
+
+procedure MEMZERO(target : pointer; size : size_t);
+
+procedure MEMCOPY(dest, src : pointer; size : size_t);
+
+{function SIZEOF(object) : size_t;}
+
+function JFREAD(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t;
+
+function JFWRITE(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t;
+
+implementation
+
+procedure MEMZERO(target : pointer; size : size_t);
+begin
+  FillChar(target^, size, 0);
+end;
+
+procedure MEMCOPY(dest, src : pointer; size : size_t);
+begin
+  Move(src^, dest^, size);
+end;
+
+{ In ANSI C, and indeed any rational implementation, size_t is also the
+  type returned by sizeof().  However, it seems there are some irrational
+  implementations out there, in which sizeof() returns an int even though
+  size_t is defined as long or unsigned long.  To ensure consistent results
+  we always use this SIZEOF() macro in place of using sizeof() directly. }
+
+
+{#define
+  SIZEOF(object)  (size_t(sizeof(object))}
+
+
+{ The modules that use fread() and fwrite() always invoke them through
+  these macros.  On some systems you may need to twiddle the argument casts.
+  CAUTION: argument order is different from underlying functions! }
+
+
+function JFREAD(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t;
+var
+  count : uint;
+begin
+  {$ifdef Delphi_Stream}
+  count := fp^.Read(buf^, sizeofbuf);
+  {$else}
+     blockread(fp^, buf^, sizeofbuf, count);
+  {$endif}
+  JFREAD := size_t(count);
+end;
+
+function JFWRITE(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t;
+var
+  count : uint;
+begin
+  {$ifdef Delphi_Stream}
+  count := fp^.Write(buf^, sizeofbuf);
+  {$else}
+     blockwrite(fp^, buf^, sizeofbuf, count);
+  {$endif}
+  JFWRITE := size_t(count);
+end;
+
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjmemmgr.pas b/src/lib/vampimg/JpegLib/imjmemmgr.pas
new file mode 100644 (file)
index 0000000..ca8239d
--- /dev/null
@@ -0,0 +1,1283 @@
+unit imjmemmgr;
+
+{ This file contains the JPEG system-independent memory management
+  routines.  This code is usable across a wide variety of machines; most
+  of the system dependencies have been isolated in a separate file.
+  The major functions provided here are:
+    * pool-based allocation and freeing of memory;
+    * policy decisions about how to divide available memory among the
+      virtual arrays;
+    * control logic for swapping virtual arrays between main memory and
+      backing storage.
+  The separate system-dependent file provides the actual backing-storage
+  access code, and it contains the policy decision about how much total
+  main memory to use.
+  This file is system-dependent in the sense that some of its functions
+  are unnecessary in some systems.  For example, if there is enough virtual
+  memory so that backing storage will never be used, much of the virtual
+  array control logic could be removed.  (Of course, if you have that much
+  memory then you shouldn't care about a little bit of unused code...) }
+
+{ Original : jmemmgr.c ; Copyright (C) 1991-1997, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+   imjmorecfg,
+   imjinclude,
+   imjdeferr,
+   imjerror,
+   imjpeglib,
+   imjutils,
+{$IFDEF VER70}
+{$ifndef NO_GETENV}
+   Dos,                   { DOS unit should declare getenv() }
+                               { function GetEnv(name : string) : string; }
+{$endif}
+   imjmemdos;                     { import the system-dependent declarations }
+{$ELSE}
+   imjmemnobs;
+  {$DEFINE NO_GETENV}
+{$ENDIF}
+
+{ Memory manager initialization.
+  When this is called, only the error manager pointer is valid in cinfo! }
+
+{GLOBAL}
+procedure jinit_memory_mgr (cinfo : j_common_ptr);
+
+implementation
+
+
+{ Some important notes:
+    The allocation routines provided here must never return NIL.
+    They should exit to error_exit if unsuccessful.
+
+    It's not a good idea to try to merge the sarray and barray routines,
+    even though they are textually almost the same, because samples are
+    usually stored as bytes while coefficients are shorts or ints.  Thus,
+    in machines where byte pointers have a different representation from
+    word pointers, the resulting machine code could not be the same.  }
+
+
+{ Many machines require storage alignment: longs must start on 4-byte
+  boundaries, doubles on 8-byte boundaries, etc.  On such machines, malloc()
+  always returns pointers that are multiples of the worst-case alignment
+  requirement, and we had better do so too.
+  There isn't any really portable way to determine the worst-case alignment
+  requirement.  This module assumes that the alignment requirement is
+  multiples of sizeof(ALIGN_TYPE).
+  By default, we define ALIGN_TYPE as double.  This is necessary on some
+  workstations (where doubles really do need 8-byte alignment) and will work
+  fine on nearly everything.  If your machine has lesser alignment needs,
+  you can save a few bytes by making ALIGN_TYPE smaller.
+  The only place I know of where this will NOT work is certain Macintosh
+  680x0 compilers that define double as a 10-byte IEEE extended float.
+  Doing 10-byte alignment is counterproductive because longwords won't be
+  aligned well.  Put "#define ALIGN_TYPE long" in jconfig.h if you have
+  such a compiler. }
+
+{$ifndef ALIGN_TYPE} { so can override from jconfig.h }
+type
+  ALIGN_TYPE = double;
+{$endif}
+
+
+{ We allocate objects from "pools", where each pool is gotten with a single
+  request to jpeg_get_small() or jpeg_get_large().  There is no per-object
+  overhead within a pool, except for alignment padding.  Each pool has a
+  header with a link to the next pool of the same class.
+  Small and large pool headers are identical except that the latter's
+  link pointer must be FAR on 80x86 machines.
+  Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
+  field.  This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
+  of the alignment requirement of ALIGN_TYPE. }
+
+type
+  small_pool_ptr = ^small_pool_hdr;
+  small_pool_hdr = record
+  case byte of
+    0:(hdr : record
+               next : small_pool_ptr;   { next in list of pools }
+               bytes_used : size_t;     { how many bytes already used within pool }
+               bytes_left : size_t;     { bytes still available in this pool }
+             end);
+    1:(dummy : ALIGN_TYPE);             { included in union to ensure alignment }
+  end; {small_pool_hdr;}
+
+type
+  large_pool_ptr = ^large_pool_hdr; {FAR}
+  large_pool_hdr = record
+  case byte of
+    0:(hdr : record
+               next : large_pool_ptr;   { next in list of pools }
+               bytes_used : size_t;     { how many bytes already used within pool }
+               bytes_left : size_t;     { bytes still available in this pool }
+             end);
+    1:(dummy : ALIGN_TYPE);             { included in union to ensure alignment }
+  end; {large_pool_hdr;}
+
+
+{ Here is the full definition of a memory manager object. }
+
+type
+  my_mem_ptr = ^my_memory_mgr;
+  my_memory_mgr = record
+    pub : jpeg_memory_mgr;  { public fields }
+
+    { Each pool identifier (lifetime class) names a linked list of pools. }
+    small_list : array[0..JPOOL_NUMPOOLS-1] of small_pool_ptr ;
+    large_list : array[0..JPOOL_NUMPOOLS-1] of large_pool_ptr ;
+
+    { Since we only have one lifetime class of virtual arrays, only one
+      linked list is necessary (for each datatype).  Note that the virtual
+      array control blocks being linked together are actually stored somewhere
+      in the small-pool list. }
+
+    virt_sarray_list : jvirt_sarray_ptr;
+    virt_barray_list : jvirt_barray_ptr;
+
+    { This counts total space obtained from jpeg_get_small/large }
+    total_space_allocated : long;
+
+    { alloc_sarray and alloc_barray set this value for use by virtual
+      array routines. }
+
+    last_rowsperchunk : JDIMENSION; { from most recent alloc_sarray/barray }
+  end; {my_memory_mgr;}
+
+  {$ifndef AM_MEMORY_MANAGER} { only jmemmgr.c defines these }
+
+{ The control blocks for virtual arrays.
+  Note that these blocks are allocated in the "small" pool area.
+  System-dependent info for the associated backing store (if any) is hidden
+  inside the backing_store_info struct. }
+type
+  jvirt_sarray_control = record
+    mem_buffer : JSAMPARRAY;  { => the in-memory buffer }
+    rows_in_array : JDIMENSION; { total virtual array height }
+    samplesperrow : JDIMENSION; { width of array (and of memory buffer) }
+    maxaccess : JDIMENSION; { max rows accessed by access_virt_sarray }
+    rows_in_mem : JDIMENSION; { height of memory buffer }
+    rowsperchunk : JDIMENSION;  { allocation chunk size in mem_buffer }
+    cur_start_row : JDIMENSION; { first logical row # in the buffer }
+    first_undef_row : JDIMENSION; { row # of first uninitialized row }
+    pre_zero : boolean;   { pre-zero mode requested? }
+    dirty : boolean;    { do current buffer contents need written? }
+    b_s_open : boolean;   { is backing-store data valid? }
+    next : jvirt_sarray_ptr;  { link to next virtual sarray control block }
+    b_s_info : backing_store_info;  { System-dependent control info }
+  end;
+
+  jvirt_barray_control = record
+    mem_buffer : JBLOCKARRAY; { => the in-memory buffer }
+    rows_in_array : JDIMENSION; { total virtual array height }
+    blocksperrow : JDIMENSION;  { width of array (and of memory buffer) }
+    maxaccess : JDIMENSION; { max rows accessed by access_virt_barray }
+    rows_in_mem : JDIMENSION; { height of memory buffer }
+    rowsperchunk : JDIMENSION;  { allocation chunk size in mem_buffer }
+    cur_start_row : JDIMENSION; { first logical row # in the buffer }
+    first_undef_row : JDIMENSION; { row # of first uninitialized row }
+    pre_zero : boolean;   { pre-zero mode requested? }
+    dirty : boolean;    { do current buffer contents need written? }
+    b_s_open : boolean;   { is backing-store data valid? }
+    next : jvirt_barray_ptr;  { link to next virtual barray control block }
+    b_s_info : backing_store_info;  { System-dependent control info }
+  end;
+  {$endif}  { AM_MEMORY_MANAGER}
+
+{$ifdef MEM_STATS}        { optional extra stuff for statistics }
+
+{LOCAL}
+procedure print_mem_stats (cinfo : j_common_ptr; pool_id : int);
+var
+  mem : my_mem_ptr;
+  shdr_ptr : small_pool_ptr;
+  lhdr_ptr : large_pool_ptr;
+begin
+  mem := my_mem_ptr (cinfo^.mem);
+
+  { Since this is only a debugging stub, we can cheat a little by using
+    fprintf directly rather than going through the trace message code.
+    This is helpful because message parm array can't handle longs. }
+
+  WriteLn(output, 'Freeing pool ', pool_id,', total space := ',
+     mem^.total_space_allocated);
+
+  lhdr_ptr := mem^.large_list[pool_id];
+  while (lhdr_ptr <> NIL) do
+  begin
+    WriteLn(output, '  Large chunk used ',
+      long (lhdr_ptr^.hdr.bytes_used));
+    lhdr_ptr := lhdr_ptr^.hdr.next;
+  end;
+
+  shdr_ptr := mem^.small_list[pool_id];
+
+  while (shdr_ptr <> NIL) do
+  begin
+    WriteLn(output, '  Small chunk used ',
+                    long (shdr_ptr^.hdr.bytes_used), ' free ',
+                    long (shdr_ptr^.hdr.bytes_left) );
+    shdr_ptr := shdr_ptr^.hdr.next;
+  end;
+end;
+
+{$endif} { MEM_STATS }
+
+
+{LOCAL}
+procedure out_of_memory (cinfo : j_common_ptr; which : int);
+{ Report an out-of-memory error and stop execution }
+{ If we compiled MEM_STATS support, report alloc requests before dying }
+begin
+{$ifdef MEM_STATS}
+  cinfo^.err^.trace_level := 2; { force self_destruct to report stats }
+{$endif}
+  ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
+end;
+
+
+{ Allocation of "small" objects.
+
+  For these, we use pooled storage.  When a new pool must be created,
+  we try to get enough space for the current request plus a "slop" factor,
+  where the slop will be the amount of leftover space in the new pool.
+  The speed vs. space tradeoff is largely determined by the slop values.
+  A different slop value is provided for each pool class (lifetime),
+  and we also distinguish the first pool of a class from later ones.
+  NOTE: the values given work fairly well on both 16- and 32-bit-int
+  machines, but may be too small if longs are 64 bits or more. }
+
+const
+  first_pool_slop : array[0..JPOOL_NUMPOOLS-1] of size_t  =
+  (1600,      { first PERMANENT pool }
+  16000);     { first IMAGE pool }
+
+const
+  extra_pool_slop : array[0..JPOOL_NUMPOOLS-1] of size_t =
+  (0,     { additional PERMANENT pools }
+  5000);      { additional IMAGE pools }
+
+const
+  MIN_SLOP = 50;    { greater than 0 to avoid futile looping }
+
+
+{METHODDEF}
+function alloc_small (cinfo : j_common_ptr;
+                      pool_id : int;
+                      sizeofobject : size_t) : pointer;
+type
+  byteptr = ^byte;
+{ Allocate a "small" object }
+var
+  mem : my_mem_ptr;
+  hdr_ptr, prev_hdr_ptr : small_pool_ptr;
+  data_ptr : byteptr;
+  odd_bytes, min_request, slop : size_t;
+begin
+  mem := my_mem_ptr (cinfo^.mem);
+
+  { Check for unsatisfiable request (do now to ensure no overflow below) }
+  if (sizeofobject > size_t(MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) then
+    out_of_memory(cinfo, 1);  { request exceeds malloc's ability }
+
+  { Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) }
+  odd_bytes := sizeofobject mod SIZEOF(ALIGN_TYPE);
+  if (odd_bytes > 0) then
+    Inc(sizeofobject, SIZEOF(ALIGN_TYPE) - odd_bytes);
+
+  { See if space is available in any existing pool }
+  if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_BAD_POOL_ID, pool_id); { safety check }
+  prev_hdr_ptr := NIL;
+  hdr_ptr := mem^.small_list[pool_id];
+  while (hdr_ptr <> NIL) do
+  begin
+    if (hdr_ptr^.hdr.bytes_left >= sizeofobject) then
+      break;      { found pool with enough space }
+    prev_hdr_ptr := hdr_ptr;
+    hdr_ptr := hdr_ptr^.hdr.next;
+  end;
+
+  { Time to make a new pool? }
+  if (hdr_ptr = NIL) then
+  begin
+    { min_request is what we need now, slop is what will be leftover }
+    min_request := sizeofobject + SIZEOF(small_pool_hdr);
+    if (prev_hdr_ptr = NIL) then  { first pool in class? }
+      slop := first_pool_slop[pool_id]
+    else
+      slop := extra_pool_slop[pool_id];
+    { Don't ask for more than MAX_ALLOC_CHUNK }
+    if (slop > size_t (MAX_ALLOC_CHUNK-min_request)) then
+      slop := size_t (MAX_ALLOC_CHUNK-min_request);
+    { Try to get space, if fail reduce slop and try again }
+    while TRUE do
+    begin
+      hdr_ptr := small_pool_ptr(jpeg_get_small(cinfo, min_request + slop));
+      if (hdr_ptr <> NIL) then
+  break;
+      slop := slop div 2;
+      if (slop < MIN_SLOP) then   { give up when it gets real small }
+  out_of_memory(cinfo, 2);  { jpeg_get_small failed }
+    end;
+    Inc(mem^.total_space_allocated, min_request + slop);
+    { Success, initialize the new pool header and add to end of list }
+    hdr_ptr^.hdr.next := NIL;
+    hdr_ptr^.hdr.bytes_used := 0;
+    hdr_ptr^.hdr.bytes_left := sizeofobject + slop;
+    if (prev_hdr_ptr = NIL) then       { first pool in class? }
+      mem^.small_list[pool_id] := hdr_ptr
+    else
+      prev_hdr_ptr^.hdr.next := hdr_ptr;
+  end;
+
+  { OK, allocate the object from the current pool }
+  data_ptr := byteptr (hdr_ptr);
+  Inc(small_pool_ptr(data_ptr));  { point to first data byte in pool }
+  Inc(data_ptr, hdr_ptr^.hdr.bytes_used); { point to place for object }
+  Inc(hdr_ptr^.hdr.bytes_used, sizeofobject);
+  Dec(hdr_ptr^.hdr.bytes_left, sizeofobject);
+
+  alloc_small := pointer(data_ptr);
+end;
+
+
+{ Allocation of "large" objects.
+
+  The external semantics of these are the same as "small" objects,
+  except that FAR pointers are used on 80x86.  However the pool
+  management heuristics are quite different.  We assume that each
+  request is large enough that it may as well be passed directly to
+  jpeg_get_large; the pool management just links everything together
+  so that we can free it all on demand.
+  Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
+  structures.  The routines that create these structures (see below)
+  deliberately bunch rows together to ensure a large request size. }
+
+{METHODDEF}
+function alloc_large (cinfo : j_common_ptr;
+                      pool_id : int;
+                      sizeofobject : size_t) : pointer;
+{ Allocate a "large" object }
+var
+  mem : my_mem_ptr;
+  hdr_ptr : large_pool_ptr;
+  odd_bytes : size_t;
+var
+  dest_ptr : large_pool_ptr;
+begin
+  mem := my_mem_ptr (cinfo^.mem);
+
+  { Check for unsatisfiable request (do now to ensure no overflow below) }
+  if (sizeofobject > size_t (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) then
+    out_of_memory(cinfo, 3);  { request exceeds malloc's ability }
+
+  { Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) }
+  odd_bytes := sizeofobject mod SIZEOF(ALIGN_TYPE);
+  if (odd_bytes > 0) then
+    Inc(sizeofobject, SIZEOF(ALIGN_TYPE) - odd_bytes);
+
+  { Always make a new pool }
+  if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
+
+  hdr_ptr := large_pool_ptr (jpeg_get_large(cinfo, sizeofobject +
+              SIZEOF(large_pool_hdr)));
+  if (hdr_ptr = NIL) then
+    out_of_memory(cinfo, 4);  { jpeg_get_large failed }
+  Inc(mem^.total_space_allocated, sizeofobject + SIZEOF(large_pool_hdr));
+
+  { Success, initialize the new pool header and add to list }
+  hdr_ptr^.hdr.next := mem^.large_list[pool_id];
+  { We maintain space counts in each pool header for statistical purposes,
+    even though they are not needed for allocation. }
+
+  hdr_ptr^.hdr.bytes_used := sizeofobject;
+  hdr_ptr^.hdr.bytes_left := 0;
+  mem^.large_list[pool_id] := hdr_ptr;
+
+  {alloc_large := pointerFAR (hdr_ptr + 1); - point to first data byte in pool }
+  dest_ptr := hdr_ptr;
+  Inc(large_pool_ptr(dest_ptr));
+  alloc_large := dest_ptr;
+end;
+
+
+{ Creation of 2-D sample arrays.
+  The pointers are in near heap, the samples themselves in FAR heap.
+
+  To minimize allocation overhead and to allow I/O of large contiguous
+  blocks, we allocate the sample rows in groups of as many rows as possible
+  without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
+  NB: the virtual array control routines, later in this file, know about
+  this chunking of rows.  The rowsperchunk value is left in the mem manager
+  object so that it can be saved away if this sarray is the workspace for
+  a virtual array. }
+
+{METHODDEF}
+function alloc_sarray (cinfo : j_common_ptr;
+                       pool_id : int;
+                 samplesperrow : JDIMENSION;
+                       numrows : JDIMENSION) : JSAMPARRAY;
+{ Allocate a 2-D sample array }
+var
+  mem : my_mem_ptr;
+  the_result : JSAMPARRAY;
+  workspace : JSAMPROW;
+  rowsperchunk, currow, i : JDIMENSION;
+  ltemp : long;
+begin
+  mem := my_mem_ptr(cinfo^.mem);
+
+  { Calculate max # of rows allowed in one allocation chunk }
+  ltemp := (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) div
+    (long(samplesperrow) * SIZEOF(JSAMPLE));
+  if (ltemp <= 0) then
+    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+  if (ltemp < long(numrows)) then
+    rowsperchunk := JDIMENSION (ltemp)
+  else
+    rowsperchunk := numrows;
+  mem^.last_rowsperchunk := rowsperchunk;
+
+  { Get space for row pointers (small object) }
+  the_result := JSAMPARRAY (alloc_small(cinfo, pool_id,
+            size_t (numrows * SIZEOF(JSAMPROW))));
+
+  { Get the rows themselves (large objects) }
+  currow := 0;
+  while (currow < numrows) do
+  begin
+    {rowsperchunk := MIN(rowsperchunk, numrows - currow);}
+    if rowsperchunk > numrows - currow then
+      rowsperchunk := numrows - currow;
+
+    workspace := JSAMPROW (alloc_large(cinfo, pool_id,
+  size_t (size_t(rowsperchunk) * size_t(samplesperrow)
+      * SIZEOF(JSAMPLE))) );
+    for i := pred(rowsperchunk) downto 0 do
+    begin
+      the_result^[currow] := workspace;
+      Inc(currow);
+      Inc(JSAMPLE_PTR(workspace), samplesperrow);
+    end;
+  end;
+
+  alloc_sarray := the_result;
+end;
+
+
+{ Creation of 2-D coefficient-block arrays.
+  This is essentially the same as the code for sample arrays, above. }
+
+{METHODDEF}
+function alloc_barray (cinfo : j_common_ptr;
+                       pool_id : int;
+                 blocksperrow : JDIMENSION;
+                       numrows : JDIMENSION) : JBLOCKARRAY;
+{ Allocate a 2-D coefficient-block array }
+var
+  mem : my_mem_ptr;
+  the_result : JBLOCKARRAY;
+  workspace : JBLOCKROW;
+  rowsperchunk, currow, i : JDIMENSION;
+  ltemp : long;
+begin
+  mem := my_mem_ptr(cinfo^.mem);
+
+  { Calculate max # of rows allowed in one allocation chunk }
+  ltemp := (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) div
+    (long(blocksperrow) * SIZEOF(JBLOCK));
+
+  if (ltemp <= 0) then
+    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+  if (ltemp < long(numrows)) then
+    rowsperchunk := JDIMENSION (ltemp)
+  else
+    rowsperchunk := numrows;
+  mem^.last_rowsperchunk := rowsperchunk;
+
+  { Get space for row pointers (small object) }
+  the_result := JBLOCKARRAY (alloc_small(cinfo, pool_id,
+             size_t (numrows * SIZEOF(JBLOCKROW))) );
+
+  { Get the rows themselves (large objects) }
+  currow := 0;
+  while (currow < numrows) do
+  begin
+    {rowsperchunk := MIN(rowsperchunk, numrows - currow);}
+    if rowsperchunk > numrows - currow then
+      rowsperchunk := numrows - currow;
+
+    workspace := JBLOCKROW (alloc_large(cinfo, pool_id,
+  size_t (size_t(rowsperchunk) * size_t(blocksperrow)
+      * SIZEOF(JBLOCK))) );
+    for i := rowsperchunk downto 1 do
+    begin
+      the_result^[currow] := workspace;
+      Inc(currow);
+      Inc(JBLOCK_PTR(workspace), blocksperrow);
+    end;
+  end;
+
+  alloc_barray := the_result;
+end;
+
+
+{ About virtual array management:
+
+  The above "normal" array routines are only used to allocate strip buffers
+  (as wide as the image, but just a few rows high).  Full-image-sized buffers
+  are handled as "virtual" arrays.  The array is still accessed a strip at a
+  time, but the memory manager must save the whole array for repeated
+  accesses.  The intended implementation is that there is a strip buffer in
+  memory (as high as is possible given the desired memory limit), plus a
+  backing file that holds the rest of the array.
+
+  The request_virt_array routines are told the total size of the image and
+  the maximum number of rows that will be accessed at once.  The in-memory
+  buffer must be at least as large as the maxaccess value.
+
+  The request routines create control blocks but not the in-memory buffers.
+  That is postponed until realize_virt_arrays is called.  At that time the
+  total amount of space needed is known (approximately, anyway), so free
+  memory can be divided up fairly.
+
+  The access_virt_array routines are responsible for making a specific strip
+  area accessible (after reading or writing the backing file, if necessary).
+  Note that the access routines are told whether the caller intends to modify
+  the accessed strip; during a read-only pass this saves having to rewrite
+  data to disk.  The access routines are also responsible for pre-zeroing
+  any newly accessed rows, if pre-zeroing was requested.
+
+  In current usage, the access requests are usually for nonoverlapping
+  strips; that is, successive access start_row numbers differ by exactly
+  num_rows := maxaccess.  This means we can get good performance with simple
+  buffer dump/reload logic, by making the in-memory buffer be a multiple
+  of the access height; then there will never be accesses across bufferload
+  boundaries.  The code will still work with overlapping access requests,
+  but it doesn't handle bufferload overlaps very efficiently. }
+
+
+{METHODDEF}
+function request_virt_sarray (cinfo : j_common_ptr;
+                              pool_id : int;
+                              pre_zero : boolean;
+                  samplesperrow : JDIMENSION;
+                              numrows : JDIMENSION;
+                  maxaccess : JDIMENSION) : jvirt_sarray_ptr;
+{ Request a virtual 2-D sample array }
+var
+  mem : my_mem_ptr;
+  the_result : jvirt_sarray_ptr;
+begin
+  mem := my_mem_ptr (cinfo^.mem);
+
+  { Only IMAGE-lifetime virtual arrays are currently supported }
+  if (pool_id <> JPOOL_IMAGE) then
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
+
+  { get control block }
+  the_result := jvirt_sarray_ptr (alloc_small(cinfo, pool_id,
+          SIZEOF(jvirt_sarray_control)) );
+
+  the_result^.mem_buffer := NIL;  { marks array not yet realized }
+  the_result^.rows_in_array := numrows;
+  the_result^.samplesperrow := samplesperrow;
+  the_result^.maxaccess := maxaccess;
+  the_result^.pre_zero := pre_zero;
+  the_result^.b_s_open := FALSE;  { no associated backing-store object }
+  the_result^.next := mem^.virt_sarray_list; { add to list of virtual arrays }
+  mem^.virt_sarray_list := the_result;
+
+  request_virt_sarray := the_result;
+end;
+
+
+{METHODDEF}
+function request_virt_barray (cinfo : j_common_ptr;
+                              pool_id : int;
+                              pre_zero : boolean;
+                  blocksperrow : JDIMENSION;
+                              numrows : JDIMENSION;
+                  maxaccess : JDIMENSION) : jvirt_barray_ptr;
+{ Request a virtual 2-D coefficient-block array }
+var
+  mem : my_mem_ptr;
+  the_result : jvirt_barray_ptr;
+begin
+  mem := my_mem_ptr(cinfo^.mem);
+
+  { Only IMAGE-lifetime virtual arrays are currently supported }
+  if (pool_id <> JPOOL_IMAGE) then
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
+
+  { get control block }
+  the_result := jvirt_barray_ptr(alloc_small(cinfo, pool_id,
+          SIZEOF(jvirt_barray_control)) );
+
+  the_result^.mem_buffer := NIL;  { marks array not yet realized }
+  the_result^.rows_in_array := numrows;
+  the_result^.blocksperrow := blocksperrow;
+  the_result^.maxaccess := maxaccess;
+  the_result^.pre_zero := pre_zero;
+  the_result^.b_s_open := FALSE;  { no associated backing-store object }
+  the_result^.next := mem^.virt_barray_list; { add to list of virtual arrays }
+  mem^.virt_barray_list := the_result;
+
+  request_virt_barray := the_result;
+end;
+
+
+{METHODDEF}
+procedure realize_virt_arrays (cinfo : j_common_ptr);
+{ Allocate the in-memory buffers for any unrealized virtual arrays }
+var
+  mem : my_mem_ptr;
+  space_per_minheight, maximum_space, avail_mem : long;
+  minheights, max_minheights : long;
+  sptr : jvirt_sarray_ptr;
+  bptr : jvirt_barray_ptr;
+begin
+  mem := my_mem_ptr (cinfo^.mem);
+  { Compute the minimum space needed (maxaccess rows in each buffer)
+    and the maximum space needed (full image height in each buffer).
+    These may be of use to the system-dependent jpeg_mem_available routine. }
+
+  space_per_minheight := 0;
+  maximum_space := 0;
+  sptr := mem^.virt_sarray_list;
+  while (sptr <> NIL) do
+  begin
+    if (sptr^.mem_buffer = NIL) then
+    begin { if not realized yet }
+      Inc(space_per_minheight, long(sptr^.maxaccess) *
+           long(sptr^.samplesperrow) * SIZEOF(JSAMPLE));
+      Inc(maximum_space, long(sptr^.rows_in_array) *
+           long(sptr^.samplesperrow) * SIZEOF(JSAMPLE));
+    end;
+    sptr := sptr^.next;
+  end;
+  bptr := mem^.virt_barray_list;
+  while (bptr <> NIL) do
+  begin
+    if (bptr^.mem_buffer = NIL) then
+    begin { if not realized yet }
+      Inc(space_per_minheight, long(bptr^.maxaccess) *
+           long(bptr^.blocksperrow) * SIZEOF(JBLOCK));
+      Inc(maximum_space, long(bptr^.rows_in_array) *
+           long(bptr^.blocksperrow) * SIZEOF(JBLOCK));
+    end;
+    bptr := bptr^.next;
+  end;
+
+  if (space_per_minheight <= 0) then
+    exit;     { no unrealized arrays, no work }
+
+  { Determine amount of memory to actually use; this is system-dependent. }
+  avail_mem := jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
+         mem^.total_space_allocated);
+
+  { If the maximum space needed is available, make all the buffers full
+    height; otherwise parcel it out with the same number of minheights
+    in each buffer. }
+
+  if (avail_mem >= maximum_space) then
+    max_minheights := long(1000000000)
+  else
+  begin
+    max_minheights := avail_mem div space_per_minheight;
+    { If there doesn't seem to be enough space, try to get the minimum
+      anyway.  This allows a "stub" implementation of jpeg_mem_available(). }
+    if (max_minheights <= 0) then
+      max_minheights := 1;
+  end;
+
+  { Allocate the in-memory buffers and initialize backing store as needed. }
+
+  sptr := mem^.virt_sarray_list;
+  while (sptr <> NIL) do
+  begin
+    if (sptr^.mem_buffer = NIL) then
+    begin { if not realized yet }
+      minheights := (long(sptr^.rows_in_array) - long(1)) div LongInt(sptr^.maxaccess) + long(1);
+      if (minheights <= max_minheights) then
+      begin
+  { This buffer fits in memory }
+  sptr^.rows_in_mem := sptr^.rows_in_array;
+      end
+      else
+      begin
+  { It doesn't fit in memory, create backing store. }
+  sptr^.rows_in_mem := JDIMENSION(max_minheights) * sptr^.maxaccess;
+  jpeg_open_backing_store(cinfo,
+                                @sptr^.b_s_info,
+        long(sptr^.rows_in_array) *
+        long(sptr^.samplesperrow) *
+        long(SIZEOF(JSAMPLE)));
+  sptr^.b_s_open := TRUE;
+      end;
+      sptr^.mem_buffer := alloc_sarray(cinfo, JPOOL_IMAGE,
+              sptr^.samplesperrow, sptr^.rows_in_mem);
+      sptr^.rowsperchunk := mem^.last_rowsperchunk;
+      sptr^.cur_start_row := 0;
+      sptr^.first_undef_row := 0;
+      sptr^.dirty := FALSE;
+    end;
+    sptr := sptr^.next;
+  end;
+
+  bptr := mem^.virt_barray_list;
+  while (bptr <> NIL) do
+  begin
+    if (bptr^.mem_buffer = NIL) then
+    begin { if not realized yet }
+      minheights := (long(bptr^.rows_in_array) - long(1)) div LongInt(bptr^.maxaccess) + long(1);
+      if (minheights <= max_minheights) then
+      begin
+  { This buffer fits in memory }
+  bptr^.rows_in_mem := bptr^.rows_in_array;
+      end
+      else
+      begin
+  { It doesn't fit in memory, create backing store. }
+  bptr^.rows_in_mem := JDIMENSION (max_minheights) * bptr^.maxaccess;
+  jpeg_open_backing_store(cinfo,
+                                @bptr^.b_s_info,
+        long(bptr^.rows_in_array) *
+        long(bptr^.blocksperrow) *
+        long(SIZEOF(JBLOCK)));
+  bptr^.b_s_open := TRUE;
+      end;
+      bptr^.mem_buffer := alloc_barray(cinfo, JPOOL_IMAGE,
+              bptr^.blocksperrow, bptr^.rows_in_mem);
+      bptr^.rowsperchunk := mem^.last_rowsperchunk;
+      bptr^.cur_start_row := 0;
+      bptr^.first_undef_row := 0;
+      bptr^.dirty := FALSE;
+    end;
+    bptr := bptr^.next;
+  end;
+end;
+
+
+{LOCAL}
+procedure do_sarray_io (cinfo : j_common_ptr;
+                        ptr : jvirt_sarray_ptr;
+                        writing : boolean);
+{ Do backing store read or write of a virtual sample array }
+var
+  bytesperrow, file_offset, byte_count, rows, thisrow, i : long;
+begin
+
+  bytesperrow := long(ptr^.samplesperrow * SIZEOF(JSAMPLE));
+  file_offset := LongInt(ptr^.cur_start_row) * bytesperrow;
+  { Loop to read or write each allocation chunk in mem_buffer }
+  i := 0;
+  while i < long(ptr^.rows_in_mem) do
+  begin
+
+    { One chunk, but check for short chunk at end of buffer }
+    {rows := MIN(long(ptr^.rowsperchunk), long(ptr^.rows_in_mem - i));}
+    rows := long(ptr^.rowsperchunk);
+    if rows > long(ptr^.rows_in_mem) - i then
+      rows := long(ptr^.rows_in_mem) - i;
+    { Transfer no more than is currently defined }
+    thisrow := long (ptr^.cur_start_row) + i;
+    {rows := MIN(rows, long(ptr^.first_undef_row) - thisrow);}
+    if (rows > long(ptr^.first_undef_row) - thisrow) then
+      rows := long(ptr^.first_undef_row) - thisrow;
+    { Transfer no more than fits in file }
+    {rows := MIN(rows, long(ptr^.rows_in_array) - thisrow);}
+    if (rows > long(ptr^.rows_in_array) - thisrow) then
+      rows := long(ptr^.rows_in_array) - thisrow;
+
+    if (rows <= 0) then        { this chunk might be past end of file! }
+      break;
+    byte_count := rows * bytesperrow;
+    if (writing) then
+      ptr^.b_s_info.write_backing_store (cinfo,
+                                        @ptr^.b_s_info,
+          pointer {FAR} (ptr^.mem_buffer^[i]),
+          file_offset, byte_count)
+    else
+      ptr^.b_s_info.read_backing_store (cinfo,
+                                        @ptr^.b_s_info,
+          pointer {FAR} (ptr^.mem_buffer^[i]),
+          file_offset, byte_count);
+    Inc(file_offset, byte_count);
+    Inc(i, ptr^.rowsperchunk);
+  end;
+end;
+
+
+{LOCAL}
+procedure do_barray_io (cinfo : j_common_ptr;
+                       ptr : jvirt_barray_ptr;
+                       writing : boolean);
+{ Do backing store read or write of a virtual coefficient-block array }
+var
+  bytesperrow, file_offset, byte_count, rows, thisrow, i : long;
+begin
+  bytesperrow := long (ptr^.blocksperrow) * SIZEOF(JBLOCK);
+  file_offset := LongInt(ptr^.cur_start_row) * bytesperrow;
+  { Loop to read or write each allocation chunk in mem_buffer }
+  i := 0;
+  while (i < long(ptr^.rows_in_mem)) do
+  begin
+    { One chunk, but check for short chunk at end of buffer }
+    {rows := MIN(long(ptr^.rowsperchunk), long(ptr^.rows_in_mem - i));}
+    rows := long(ptr^.rowsperchunk);
+    if rows > long(ptr^.rows_in_mem) - i then
+      rows := long(ptr^.rows_in_mem) - i;
+    { Transfer no more than is currently defined }
+    thisrow := long (ptr^.cur_start_row) + i;
+    {rows := MIN(rows, long(ptr^.first_undef_row - thisrow));}
+    if rows > long(ptr^.first_undef_row) - thisrow then
+      rows := long(ptr^.first_undef_row) - thisrow;
+    { Transfer no more than fits in file }
+    {rows := MIN(rows, long (ptr^.rows_in_array - thisrow));}
+    if (rows > long (ptr^.rows_in_array) - thisrow) then
+      rows := long (ptr^.rows_in_array) - thisrow;
+
+    if (rows <= 0) then   { this chunk might be past end of file! }
+      break;
+    byte_count := rows * bytesperrow;
+    if (writing) then
+      ptr^.b_s_info.write_backing_store (cinfo,
+                                         @ptr^.b_s_info,
+                                   {FAR} pointer(ptr^.mem_buffer^[i]),
+            file_offset, byte_count)
+    else
+      ptr^.b_s_info.read_backing_store (cinfo,
+                                        @ptr^.b_s_info,
+          {FAR} pointer(ptr^.mem_buffer^[i]),
+          file_offset, byte_count);
+    Inc(file_offset, byte_count);
+    Inc(i, ptr^.rowsperchunk);
+  end;
+end;
+
+
+{METHODDEF}
+function access_virt_sarray (cinfo : j_common_ptr;
+                             ptr : jvirt_sarray_ptr;
+                 start_row : JDIMENSION;
+                             num_rows : JDIMENSION;
+                 writable : boolean ) : JSAMPARRAY;
+{ Access the part of a virtual sample array starting at start_row }
+{ and extending for num_rows rows.  writable is true if  }
+{ caller intends to modify the accessed area. }
+var
+  end_row : JDIMENSION;
+  undef_row : JDIMENSION;
+var
+  bytesperrow : size_t;
+var
+  ltemp : long;
+begin
+  end_row := start_row + num_rows;
+  { debugging check }
+  if (end_row > ptr^.rows_in_array) or (num_rows > ptr^.maxaccess) or
+     (ptr^.mem_buffer = NIL) then
+    ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+  { Make the desired part of the virtual array accessible }
+  if (start_row < ptr^.cur_start_row) or
+     (end_row > ptr^.cur_start_row+ptr^.rows_in_mem) then
+  begin
+    if (not ptr^.b_s_open) then
+      ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+    { Flush old buffer contents if necessary }
+    if (ptr^.dirty) then
+    begin
+      do_sarray_io(cinfo, ptr, TRUE);
+      ptr^.dirty := FALSE;
+    end;
+    { Decide what part of virtual array to access.
+      Algorithm: if target address > current window, assume forward scan,
+      load starting at target address.  If target address < current window,
+      assume backward scan, load so that target area is top of window.
+      Note that when switching from forward write to forward read, will have
+      start_row := 0, so the limiting case applies and we load from 0 anyway. }
+    if (start_row > ptr^.cur_start_row) then
+    begin
+      ptr^.cur_start_row := start_row;
+    end
+    else
+    begin
+      { use long arithmetic here to avoid overflow & unsigned problems }
+
+
+      ltemp := long(end_row) - long(ptr^.rows_in_mem);
+      if (ltemp < 0) then
+  ltemp := 0;   { don't fall off front end of file }
+      ptr^.cur_start_row := JDIMENSION(ltemp);
+    end;
+    { Read in the selected part of the array.
+      During the initial write pass, we will do no actual read
+      because the selected part is all undefined. }
+
+    do_sarray_io(cinfo, ptr, FALSE);
+  end;
+  { Ensure the accessed part of the array is defined; prezero if needed.
+    To improve locality of access, we only prezero the part of the array
+    that the caller is about to access, not the entire in-memory array. }
+  if (ptr^.first_undef_row < end_row) then
+  begin
+    if (ptr^.first_undef_row < start_row) then
+    begin
+      if (writable) then  { writer skipped over a section of array }
+  ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+      undef_row := start_row; { but reader is allowed to read ahead }
+    end
+    else
+    begin
+      undef_row := ptr^.first_undef_row;
+    end;
+    if (writable) then
+      ptr^.first_undef_row := end_row;
+    if (ptr^.pre_zero) then
+    begin
+      bytesperrow := size_t(ptr^.samplesperrow) * SIZEOF(JSAMPLE);
+      Dec(undef_row, ptr^.cur_start_row); { make indexes relative to buffer }
+      Dec(end_row, ptr^.cur_start_row);
+      while (undef_row < end_row) do
+      begin
+  jzero_far({FAR} pointer(ptr^.mem_buffer^[undef_row]), bytesperrow);
+  Inc(undef_row);
+      end;
+    end
+    else
+    begin
+      if (not writable) then  { reader looking at undefined data }
+  ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+    end;
+  end;
+  { Flag the buffer dirty if caller will write in it }
+  if (writable) then
+    ptr^.dirty := TRUE;
+  { Return address of proper part of the buffer }
+  access_virt_sarray := JSAMPARRAY(@ ptr^.mem_buffer^[start_row - ptr^.cur_start_row]);
+end;
+
+
+{METHODDEF}
+function access_virt_barray (cinfo : j_common_ptr;
+                             ptr : jvirt_barray_ptr;
+                 start_row : JDIMENSION;
+                             num_rows : JDIMENSION;
+                 writable : boolean) : JBLOCKARRAY;
+{ Access the part of a virtual block array starting at start_row }
+{ and extending for num_rows rows.  writable is true if  }
+{ caller intends to modify the accessed area. }
+var
+  end_row : JDIMENSION;
+  undef_row : JDIMENSION;
+  ltemp : long;
+var
+  bytesperrow : size_t;
+begin
+  end_row := start_row + num_rows;
+
+  { debugging check }
+  if (end_row > ptr^.rows_in_array) or (num_rows > ptr^.maxaccess) or
+     (ptr^.mem_buffer = NIL) then
+    ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+  { Make the desired part of the virtual array accessible }
+  if (start_row < ptr^.cur_start_row) or
+     (end_row > ptr^.cur_start_row+ptr^.rows_in_mem) then
+  begin
+    if (not ptr^.b_s_open) then
+      ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+    { Flush old buffer contents if necessary }
+    if (ptr^.dirty) then
+    begin
+      do_barray_io(cinfo, ptr, TRUE);
+      ptr^.dirty := FALSE;
+    end;
+    { Decide what part of virtual array to access.
+      Algorithm: if target address > current window, assume forward scan,
+      load starting at target address.  If target address < current window,
+      assume backward scan, load so that target area is top of window.
+      Note that when switching from forward write to forward read, will have
+      start_row := 0, so the limiting case applies and we load from 0 anyway. }
+
+    if (start_row > ptr^.cur_start_row) then
+    begin
+      ptr^.cur_start_row := start_row;
+    end
+    else
+    begin
+      { use long arithmetic here to avoid overflow & unsigned problems }
+
+      ltemp := long(end_row) - long(ptr^.rows_in_mem);
+      if (ltemp < 0) then
+  ltemp := 0;   { don't fall off front end of file }
+      ptr^.cur_start_row := JDIMENSION (ltemp);
+    end;
+    { Read in the selected part of the array.
+      During the initial write pass, we will do no actual read
+      because the selected part is all undefined. }
+
+    do_barray_io(cinfo, ptr, FALSE);
+  end;
+  { Ensure the accessed part of the array is defined; prezero if needed.
+    To improve locality of access, we only prezero the part of the array
+    that the caller is about to access, not the entire in-memory array. }
+
+  if (ptr^.first_undef_row < end_row) then
+  begin
+    if (ptr^.first_undef_row < start_row) then
+    begin
+      if (writable) then  { writer skipped over a section of array }
+  ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+      undef_row := start_row; { but reader is allowed to read ahead }
+    end
+    else
+    begin
+      undef_row := ptr^.first_undef_row;
+    end;
+    if (writable) then
+      ptr^.first_undef_row := end_row;
+    if (ptr^.pre_zero) then
+    begin
+      bytesperrow := size_t (ptr^.blocksperrow) * SIZEOF(JBLOCK);
+      Dec(undef_row, ptr^.cur_start_row); { make indexes relative to buffer }
+      Dec(end_row, ptr^.cur_start_row);
+      while (undef_row < end_row) do
+      begin
+  jzero_far({FAR}pointer(ptr^.mem_buffer^[undef_row]), bytesperrow);
+  Inc(undef_row);
+      end;
+    end
+    else
+    begin
+      if (not writable) then  { reader looking at undefined data }
+  ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+    end;
+  end;
+  { Flag the buffer dirty if caller will write in it }
+  if (writable) then
+    ptr^.dirty := TRUE;
+  { Return address of proper part of the buffer }
+  access_virt_barray := JBLOCKARRAY(@ ptr^.mem_buffer^[start_row - ptr^.cur_start_row]);
+end;
+
+
+{ Release all objects belonging to a specified pool. }
+
+{METHODDEF}
+procedure free_pool (cinfo : j_common_ptr; pool_id : int);
+var
+  mem : my_mem_ptr;
+  shdr_ptr : small_pool_ptr;
+  lhdr_ptr : large_pool_ptr;
+  space_freed : size_t;
+var
+  sptr : jvirt_sarray_ptr;
+  bptr : jvirt_barray_ptr;
+var
+  next_lhdr_ptr : large_pool_ptr;
+  next_shdr_ptr : small_pool_ptr;
+begin
+  mem := my_mem_ptr(cinfo^.mem);
+
+  if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then
+    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
+
+{$ifdef MEM_STATS}
+  if (cinfo^.err^.trace_level > 1) then
+    print_mem_stats(cinfo, pool_id); { print pool's memory usage statistics }
+{$endif}
+
+  { If freeing IMAGE pool, close any virtual arrays first }
+  if (pool_id = JPOOL_IMAGE) then
+  begin
+    sptr := mem^.virt_sarray_list;
+    while (sptr <> NIL) do
+    begin
+      if (sptr^.b_s_open) then
+      begin { there may be no backing store }
+  sptr^.b_s_open := FALSE;  { prevent recursive close if error }
+  sptr^.b_s_info.close_backing_store (cinfo, @sptr^.b_s_info);
+      end;
+      sptr := sptr^.next;
+    end;
+    mem^.virt_sarray_list := NIL;
+    bptr := mem^.virt_barray_list;
+    while (bptr <> NIL) do
+    begin
+      if (bptr^.b_s_open) then
+      begin { there may be no backing store }
+  bptr^.b_s_open := FALSE;  { prevent recursive close if error }
+  bptr^.b_s_info.close_backing_store (cinfo, @bptr^.b_s_info);
+      end;
+      bptr := bptr^.next;
+    end;
+    mem^.virt_barray_list := NIL;
+  end;
+
+  { Release large objects }
+  lhdr_ptr := mem^.large_list[pool_id];
+  mem^.large_list[pool_id] := NIL;
+
+  while (lhdr_ptr <> NIL) do
+  begin
+    next_lhdr_ptr := lhdr_ptr^.hdr.next;
+    space_freed := lhdr_ptr^.hdr.bytes_used +
+      lhdr_ptr^.hdr.bytes_left +
+      SIZEOF(large_pool_hdr);
+    jpeg_free_large(cinfo, {FAR} pointer(lhdr_ptr), space_freed);
+    Dec(mem^.total_space_allocated, space_freed);
+    lhdr_ptr := next_lhdr_ptr;
+  end;
+
+  { Release small objects }
+  shdr_ptr := mem^.small_list[pool_id];
+  mem^.small_list[pool_id] := NIL;
+
+  while (shdr_ptr <> NIL) do
+  begin
+    next_shdr_ptr := shdr_ptr^.hdr.next;
+    space_freed := shdr_ptr^.hdr.bytes_used +
+      shdr_ptr^.hdr.bytes_left +
+      SIZEOF(small_pool_hdr);
+    jpeg_free_small(cinfo, pointer(shdr_ptr), space_freed);
+    Dec(mem^.total_space_allocated, space_freed);
+    shdr_ptr := next_shdr_ptr;
+  end;
+end;
+
+
+{ Close up shop entirely.
+  Note that this cannot be called unless cinfo^.mem is non-NIL. }
+
+{METHODDEF}
+procedure self_destruct (cinfo : j_common_ptr);
+var
+  pool : int;
+begin
+  { Close all backing store, release all memory.
+    Releasing pools in reverse order might help avoid fragmentation
+    with some (brain-damaged) malloc libraries. }
+
+  for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT do
+  begin
+    free_pool(cinfo, pool);
+  end;
+
+  { Release the memory manager control block too. }
+  jpeg_free_small(cinfo, pointer(cinfo^.mem), SIZEOF(my_memory_mgr));
+  cinfo^.mem := NIL;    { ensures I will be called only once }
+
+  jpeg_mem_term(cinfo);   { system-dependent cleanup }
+end;
+
+
+{ Memory manager initialization.
+  When this is called, only the error manager pointer is valid in cinfo! }
+
+{GLOBAL}
+procedure jinit_memory_mgr (cinfo : j_common_ptr);
+var
+  mem : my_mem_ptr;
+  max_to_use : long;
+  pool : int;
+  test_mac : size_t;
+{$ifndef NO_GETENV}
+var
+  memenv : string;
+  code : integer;
+{$endif}
+begin
+  cinfo^.mem := NIL;    { for safety if init fails }
+
+  { Check for configuration errors.
+    SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
+    doesn't reflect any real hardware alignment requirement.
+    The test is a little tricky: for X>0, X and X-1 have no one-bits
+    in common if and only if X is a power of 2, ie has only one one-bit.
+    Some compilers may give an "unreachable code" warning here; ignore it. }
+  if ((SIZEOF(ALIGN_TYPE) and (SIZEOF(ALIGN_TYPE)-1)) <> 0) then
+    ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
+  { MAX_ALLOC_CHUNK must be representable as type size_t, and must be
+    a multiple of SIZEOF(ALIGN_TYPE).
+    Again, an "unreachable code" warning may be ignored here.
+    But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. }
+
+  test_mac := size_t (MAX_ALLOC_CHUNK);
+  if (long (test_mac) <> MAX_ALLOC_CHUNK) or
+      ((MAX_ALLOC_CHUNK mod SIZEOF(ALIGN_TYPE)) <> 0) then
+    ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+
+  max_to_use := jpeg_mem_init(cinfo); { system-dependent initialization }
+
+  { Attempt to allocate memory manager's control block }
+  mem := my_mem_ptr (jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)));
+
+  if (mem = NIL) then
+  begin
+    jpeg_mem_term(cinfo); { system-dependent cleanup }
+    ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
+  end;
+
+  { OK, fill in the method pointers }
+  mem^.pub.alloc_small := alloc_small;
+  mem^.pub.alloc_large := alloc_large;
+  mem^.pub.alloc_sarray := alloc_sarray;
+  mem^.pub.alloc_barray := alloc_barray;
+  mem^.pub.request_virt_sarray := request_virt_sarray;
+  mem^.pub.request_virt_barray := request_virt_barray;
+  mem^.pub.realize_virt_arrays := realize_virt_arrays;
+  mem^.pub.access_virt_sarray := access_virt_sarray;
+  mem^.pub.access_virt_barray := access_virt_barray;
+  mem^.pub.free_pool := free_pool;
+  mem^.pub.self_destruct := self_destruct;
+
+  { Make MAX_ALLOC_CHUNK accessible to other modules }
+  mem^.pub.max_alloc_chunk := MAX_ALLOC_CHUNK;
+
+  { Initialize working state }
+  mem^.pub.max_memory_to_use := max_to_use;
+
+  for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT do
+  begin
+    mem^.small_list[pool] := NIL;
+    mem^.large_list[pool] := NIL;
+  end;
+  mem^.virt_sarray_list := NIL;
+  mem^.virt_barray_list := NIL;
+
+  mem^.total_space_allocated := SIZEOF(my_memory_mgr);
+
+  { Declare ourselves open for business }
+  cinfo^.mem := @mem^.pub;
+
+  { Check for an environment variable JPEGMEM; if found, override the
+    default max_memory setting from jpeg_mem_init.  Note that the
+    surrounding application may again override this value.
+    If your system doesn't support getenv(), define NO_GETENV to disable
+    this feature. }
+
+{$ifndef NO_GETENV}
+  memenv := getenv('JPEGMEM');
+  if (memenv <> '') then
+  begin
+    Val(memenv, max_to_use, code);
+    if (Code = 0) then
+    begin
+      max_to_use := max_to_use * long(1000);
+      mem^.pub.max_memory_to_use := max_to_use * long(1000);
+    end;
+  end;
+{$endif}
+
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjmemnobs.pas b/src/lib/vampimg/JpegLib/imjmemnobs.pas
new file mode 100644 (file)
index 0000000..750fd80
--- /dev/null
@@ -0,0 +1,259 @@
+unit imjmemnobs;
+{ Delphi3 -- > jmemnobs from jmemwin }
+{ This file provides an Win32-compatible implementation of the system-
+  dependent portion of the JPEG memory manager. }
+
+{ Check jmemnobs.c }
+{ Copyright (C) 1996, Jacques Nomssi Nzali }
+
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjdeferr,
+  imjerror,
+  imjpeglib;
+
+{ The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may
+  be requested in a single call to jpeg_get_large (and jpeg_get_small for that
+  matter, but that case should never come into play).  This macro is needed
+  to model the 64Kb-segment-size limit of far addressing on 80x86 machines.
+  On those machines, we expect that jconfig.h will provide a proper value.
+  On machines with 32-bit flat address spaces, any large constant may be used.
+
+  NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type
+  size_t and will be a multiple of sizeof(align_type). }
+
+const
+  MAX_ALLOC_CHUNK = long(1000000000);
+
+{GLOBAL}
+procedure jpeg_open_backing_store (cinfo : j_common_ptr;
+                                   info : backing_store_ptr;
+                                   total_bytes_needed : long);
+
+{ These routines take care of any system-dependent initialization and
+  cleanup required. }
+
+{GLOBAL}
+function jpeg_mem_init (cinfo : j_common_ptr) : long;
+
+{GLOBAL}
+procedure jpeg_mem_term (cinfo : j_common_ptr);
+
+{ These two functions are used to allocate and release small chunks of
+  memory.  (Typically the total amount requested through jpeg_get_small is
+  no more than 20K or so; this will be requested in chunks of a few K each.)
+  Behavior should be the same as for the standard library functions malloc
+  and free; in particular, jpeg_get_small must return NIL on failure.
+  On most systems, these ARE malloc and free.  jpeg_free_small is passed the
+  size of the object being freed, just in case it's needed.
+  On an 80x86 machine using small-data memory model, these manage near heap. }
+
+
+{ Near-memory allocation and freeing are controlled by the regular library
+  routines malloc() and free(). }
+
+{GLOBAL}
+function jpeg_get_small (cinfo : j_common_ptr;
+                         sizeofobject : size_t) : pointer;
+
+{GLOBAL}
+{object is a reserved word in Borland Pascal }
+procedure jpeg_free_small (cinfo : j_common_ptr;
+                           an_object : pointer;
+                           sizeofobject : size_t);
+
+{ These two functions are used to allocate and release large chunks of
+  memory (up to the total free space designated by jpeg_mem_available).
+  The interface is the same as above, except that on an 80x86 machine,
+  far pointers are used.  On most other machines these are identical to
+  the jpeg_get/free_small routines; but we keep them separate anyway,
+  in case a different allocation strategy is desirable for large chunks. }
+
+
+{ "Large" objects are allocated in far memory, if possible }
+
+
+{GLOBAL}
+function jpeg_get_large (cinfo : j_common_ptr;
+                         sizeofobject : size_t) : voidp; {far}
+
+{GLOBAL}
+procedure jpeg_free_large (cinfo : j_common_ptr;
+                          {var?} an_object : voidp; {FAR}
+                          sizeofobject : size_t);
+
+{ This routine computes the total memory space available for allocation.
+  It's impossible to do this in a portable way; our current solution is
+  to make the user tell us (with a default value set at compile time).
+  If you can actually get the available space, it's a good idea to subtract
+  a slop factor of 5% or so. }
+
+{GLOBAL}
+function jpeg_mem_available (cinfo : j_common_ptr;
+                             min_bytes_needed : long;
+                             max_bytes_needed : long;
+                             already_allocated : long) : long;
+
+
+implementation
+
+{ This structure holds whatever state is needed to access a single
+  backing-store object.  The read/write/close method pointers are called
+  by jmemmgr.c to manipulate the backing-store object; all other fields
+  are private to the system-dependent backing store routines. }
+
+
+
+{ These two functions are used to allocate and release small chunks of
+  memory.  (Typically the total amount requested through jpeg_get_small is
+  no more than 20K or so; this will be requested in chunks of a few K each.)
+  Behavior should be the same as for the standard library functions malloc
+  and free; in particular, jpeg_get_small must return NIL on failure.
+  On most systems, these ARE malloc and free.  jpeg_free_small is passed the
+  size of the object being freed, just in case it's needed.
+  On an 80x86 machine using small-data memory model, these manage near heap. }
+
+
+{ Near-memory allocation and freeing are controlled by the regular library
+  routines malloc() and free(). }
+
+{GLOBAL}
+function jpeg_get_small (cinfo : j_common_ptr;
+                         sizeofobject : size_t) : pointer;
+var
+  p : pointer;
+begin
+  GetMem(p, sizeofobject);
+  jpeg_get_small := p;
+end;
+
+{GLOBAL}
+{object is a reserved word in Object Pascal }
+procedure jpeg_free_small (cinfo : j_common_ptr;
+                           an_object : pointer;
+                           sizeofobject : size_t);
+begin
+  FreeMem(an_object, sizeofobject);
+end;
+
+{ These two functions are used to allocate and release large chunks of
+  memory (up to the total free space designated by jpeg_mem_available).
+  The interface is the same as above, except that on an 80x86 machine,
+  far pointers are used.  On most other machines these are identical to
+  the jpeg_get/free_small routines; but we keep them separate anyway,
+  in case a different allocation strategy is desirable for large chunks. }
+
+
+
+{GLOBAL}
+function jpeg_get_large (cinfo : j_common_ptr;
+                         sizeofobject : size_t) : voidp; {far}
+var
+  p : pointer;
+begin
+  GetMem(p, sizeofobject);
+  jpeg_get_large := p;
+end;
+
+{GLOBAL}
+procedure jpeg_free_large (cinfo : j_common_ptr;
+                          {var?} an_object : voidp; {FAR}
+                          sizeofobject : size_t);
+begin
+  Freemem(an_object, sizeofobject);
+end;
+
+{ This routine computes the total space still available for allocation by
+  jpeg_get_large.  If more space than this is needed, backing store will be
+  used.  NOTE: any memory already allocated must not be counted.
+
+  There is a minimum space requirement, corresponding to the minimum
+  feasible buffer sizes; jmemmgr.c will request that much space even if
+  jpeg_mem_available returns zero.  The maximum space needed, enough to hold
+  all working storage in memory, is also passed in case it is useful.
+  Finally, the total space already allocated is passed.  If no better
+  method is available, cinfo^.mem^.max_memory_to_use - already_allocated
+  is often a suitable calculation.
+
+  It is OK for jpeg_mem_available to underestimate the space available
+  (that'll just lead to more backing-store access than is really necessary).
+  However, an overestimate will lead to failure.  Hence it's wise to subtract
+  a slop factor from the true available space.  5% should be enough.
+
+  On machines with lots of virtual memory, any large constant may be returned.
+  Conversely, zero may be returned to always use the minimum amount of memory.}
+
+
+
+{ This routine computes the total memory space available for allocation.
+  It's impossible to do this in a portable way; our current solution is
+  to make the user tell us (with a default value set at compile time).
+  If you can actually get the available space, it's a good idea to subtract
+  a slop factor of 5% or so. }
+
+const
+  DEFAULT_MAX_MEM = long(300000);   { for total usage about 450K }
+
+{GLOBAL}
+function jpeg_mem_available (cinfo : j_common_ptr;
+                             min_bytes_needed : long;
+                             max_bytes_needed : long;
+                             already_allocated : long) : long;
+begin
+  {jpeg_mem_available := cinfo^.mem^.max_memory_to_use - already_allocated;}
+  jpeg_mem_available := max_bytes_needed;
+end;
+
+
+{ Initial opening of a backing-store object.  This must fill in the
+  read/write/close pointers in the object.  The read/write routines
+  may take an error exit if the specified maximum file size is exceeded.
+  (If jpeg_mem_available always returns a large value, this routine can
+  just take an error exit.) }
+
+
+
+{ Initial opening of a backing-store object. }
+
+{GLOBAL}
+procedure jpeg_open_backing_store (cinfo : j_common_ptr;
+                                   info : backing_store_ptr;
+                                   total_bytes_needed : long);
+begin
+  ERREXIT(cinfo, JERR_NO_BACKING_STORE);
+end;
+
+{ These routines take care of any system-dependent initialization and
+  cleanup required.  jpeg_mem_init will be called before anything is
+  allocated (and, therefore, nothing in cinfo is of use except the error
+  manager pointer).  It should return a suitable default value for
+  max_memory_to_use; this may subsequently be overridden by the surrounding
+  application.  (Note that max_memory_to_use is only important if
+  jpeg_mem_available chooses to consult it ... no one else will.)
+  jpeg_mem_term may assume that all requested memory has been freed and that
+  all opened backing-store objects have been closed. }
+
+
+{ These routines take care of any system-dependent initialization and
+  cleanup required. }
+
+
+{GLOBAL}
+function jpeg_mem_init (cinfo : j_common_ptr) : long;
+begin
+  jpeg_mem_init := DEFAULT_MAX_MEM;   { default for max_memory_to_use }
+end;
+
+{GLOBAL}
+procedure jpeg_mem_term (cinfo : j_common_ptr);
+begin
+
+end;
+
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjmorecfg.pas b/src/lib/vampimg/JpegLib/imjmorecfg.pas
new file mode 100644 (file)
index 0000000..fddf3f5
--- /dev/null
@@ -0,0 +1,219 @@
+unit imjmorecfg;
+
+{ This file contains additional configuration options that customize the
+  JPEG software for special applications or support machine-dependent
+  optimizations.  Most users will not need to touch this file. }
+
+{ Source: jmorecfg.h; Copyright (C) 1991-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+type
+  int = Integer;
+  uInt = Cardinal;
+  short = SmallInt;
+  ushort = Word;
+  long = LongInt;
+
+type
+  voidp = pointer;
+
+type
+  int_ptr = ^int;
+  size_t = int;
+
+{ Define BITS_IN_JSAMPLE as either
+    8   for 8-bit sample values (the usual setting)
+    12  for 12-bit sample values
+  Only 8 and 12 are legal data precisions for lossy JPEG according to the
+  JPEG standard, and the IJG code does not support anything else!
+  We do not support run-time selection of data precision, sorry. }
+
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}   { use 8 or 12 }
+const
+  BITS_IN_JSAMPLE = 8;
+{$else}
+const
+  BITS_IN_JSAMPLE = 12;
+{$endif}
+
+
+{ Maximum number of components (color channels) allowed in JPEG image.
+  To meet the letter of the JPEG spec, set this to 255.  However, darn
+  few applications need more than 4 channels (maybe 5 for CMYK + alpha
+  mask).  We recommend 10 as a reasonable compromise; use 4 if you are
+  really short on memory.  (Each allowed component costs a hundred or so
+  bytes of storage, whether actually used in an image or not.) }
+
+
+const
+  MAX_COMPONENTS = 10;          { maximum number of image components }
+
+
+{ Basic data types.
+  You may need to change these if you have a machine with unusual data
+  type sizes; for example, "char" not 8 bits, "short" not 16 bits,
+  or "long" not 32 bits.  We don't care whether "int" is 16 or 32 bits,
+  but it had better be at least 16. }
+
+
+{ Representation of a single sample (pixel element value).
+  We frequently allocate large arrays of these, so it's important to keep
+  them small.  But if you have memory to burn and access to char or short
+  arrays is very slow on your hardware, you might want to change these. }
+
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+{ JSAMPLE should be the smallest type that will hold the values 0..255.
+  You can use a signed char by having GETJSAMPLE mask it with $FF. }
+
+{ CHAR_IS_UNSIGNED }
+type
+  JSAMPLE = byte; { Pascal unsigned char }
+  GETJSAMPLE = int;
+
+const
+  MAXJSAMPLE = 255;
+  CENTERJSAMPLE = 128;
+
+{$endif}
+
+{$ifndef BITS_IN_JSAMPLE_IS_8}
+{ JSAMPLE should be the smallest type that will hold the values 0..4095.
+  On nearly all machines "short" will do nicely. }
+
+type
+  JSAMPLE = short;
+  GETJSAMPLE = int;
+
+const
+  MAXJSAMPLE = 4095;
+  CENTERJSAMPLE = 2048;
+
+{$endif} { BITS_IN_JSAMPLE = 12 }
+
+
+{ Representation of a DCT frequency coefficient.
+  This should be a signed value of at least 16 bits; "short" is usually OK.
+  Again, we allocate large arrays of these, but you can change to int
+  if you have memory to burn and "short" is really slow. }
+type
+  JCOEF = int;
+  JCOEF_PTR = ^JCOEF;
+
+
+{ Compressed datastreams are represented as arrays of JOCTET.
+  These must be EXACTLY 8 bits wide, at least once they are written to
+  external storage.  Note that when using the stdio data source/destination
+  managers, this is also the data type passed to fread/fwrite. }
+
+
+type
+  JOCTET = Byte;
+  jTOctet = 0..(MaxInt div SizeOf(JOCTET))-1;
+  JOCTET_FIELD = array[jTOctet] of JOCTET;
+  JOCTET_FIELD_PTR = ^JOCTET_FIELD;
+  JOCTETPTR = ^JOCTET;
+
+  GETJOCTET = JOCTET; { A work around }
+
+
+{ These typedefs are used for various table entries and so forth.
+  They must be at least as wide as specified; but making them too big
+  won't cost a huge amount of memory, so we don't provide special
+  extraction code like we did for JSAMPLE.  (In other words, these
+  typedefs live at a different point on the speed/space tradeoff curve.) }
+
+
+{ UINT8 must hold at least the values 0..255. }
+
+type
+  UINT8 = Byte;
+
+{ UINT16 must hold at least the values 0..65535. }
+
+  UINT16 = Word;
+
+{ INT16 must hold at least the values -32768..32767. }
+
+  INT16 = SmallInt;
+
+{ INT32 must hold at least signed 32-bit values. }
+
+  INT32 = LongInt;
+type
+  INT32PTR = ^INT32;
+
+{ Datatype used for image dimensions.  The JPEG standard only supports
+  images up to 64K*64K due to 16-bit fields in SOF markers.  Therefore
+  "unsigned int" is sufficient on all machines.  However, if you need to
+  handle larger images and you don't mind deviating from the spec, you
+  can change this datatype. }
+
+type
+  JDIMENSION = uInt;
+
+const
+  JPEG_MAX_DIMENSION = 65500;  { a tad under 64K to prevent overflows }
+
+
+{ Ordering of RGB data in scanlines passed to or from the application.
+  If your application wants to deal with data in the order B,G,R, just
+  change these macros.  You can also deal with formats such as R,G,B,X
+  (one extra byte per pixel) by changing RGB_PIXELSIZE.  Note that changing
+  the offsets will also change the order in which colormap data is organized.
+  RESTRICTIONS:
+  1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.
+  2. These macros only affect RGB<=>YCbCr color conversion, so they are not
+     useful if you are using JPEG color spaces other than YCbCr or grayscale.
+  3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE
+     is not 3 (they don't understand about dummy color components!).  So you
+     can't use color quantization if you change that value. }
+
+{$ifdef RGB_RED_IS_0}
+const
+  RGB_RED       = 0;    { Offset of Red in an RGB scanline element }
+  RGB_GREEN     = 1;    { Offset of Green }
+  RGB_BLUE      = 2;    { Offset of Blue }
+{$else}
+const
+  RGB_RED       = 2;    { Offset of Red in an RGB scanline element }
+  RGB_GREEN     = 1;    { Offset of Green }
+  RGB_BLUE      = 0;    { Offset of Blue }
+{$endif}
+
+{$ifdef RGB_PIXELSIZE_IS_3}
+const
+  RGB_PIXELSIZE = 3;    { JSAMPLEs per RGB scanline element }
+{$else}
+const
+  RGB_PIXELSIZE = ??;   { Nomssi: deliberate syntax error. Set this value }
+{$endif}
+
+{ Definitions for speed-related optimizations. }
+
+{ On some machines (notably 68000 series) "int" is 32 bits, but multiplying
+  two 16-bit shorts is faster than multiplying two ints.  Define MULTIPLIER
+  as short on such a machine.  MULTIPLIER must be at least 16 bits wide. }
+type
+  MULTIPLIER = int;     { type for fastest integer multiply }
+
+
+{ FAST_FLOAT should be either float or double, whichever is done faster
+  by your compiler.  (Note that this type is only used in the floating point
+  DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)
+  Typically, float is faster in ANSI C compilers, while double is faster in
+  pre-ANSI compilers (because they insist on converting to double anyway).
+  The code below therefore chooses float if we have ANSI-style prototypes. }
+
+type
+  FAST_FLOAT = double; {float}
+
+
+implementation
+
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjpeglib.pas b/src/lib/vampimg/JpegLib/imjpeglib.pas
new file mode 100644 (file)
index 0000000..dc35daa
--- /dev/null
@@ -0,0 +1,1300 @@
+unit imjpeglib;
+
+{ This file defines the application interface for the JPEG library.
+  Most applications using the library need only include this file,
+  and perhaps jerror.h if they want to know the exact error codes. }
+
+{ Source:jpeglib.h+jpegint.h; Copyright (C) 1991-1998, Thomas G. Lane. }
+
+
+interface
+
+{$I imjconfig.inc}
+
+{ First we include the configuration files that record how this
+  installation of the JPEG library is set up.  jconfig.h can be
+  generated automatically for many systems.  jmorecfg.h contains
+  manual configuration options that most people need not worry about. }
+
+uses
+  imjdeferr,
+  imjmorecfg;                     { seldom changed options }
+
+{ Version ID for the JPEG library.
+  Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". }
+
+
+Const
+  JPEG_LIB_VERSION = 62;        { Version 6b }
+
+
+{ These marker codes are exported since applications and data source modules
+  are likely to want to use them. }
+
+const
+  JPEG_RST0     = $D0;  { RST0 marker code }
+  JPEG_EOI      = $D9;  { EOI marker code }
+  JPEG_APP0     = $E0;  { APP0 marker code }
+  JPEG_COM      = $FE;  { COM marker code }
+
+
+{ Various constants determining the sizes of things.
+  All of these are specified by the JPEG standard, so don't change them
+  if you want to be compatible. }
+
+const
+  DCTSIZE             = 8;      { The basic DCT block is 8x8 samples }
+  DCTSIZE2            = 64;     { DCTSIZE squared; # of elements in a block }
+  NUM_QUANT_TBLS      = 4;      { Quantization tables are numbered 0..3 }
+  NUM_HUFF_TBLS       = 4;      { Huffman tables are numbered 0..3 }
+  NUM_ARITH_TBLS      = 16;     { Arith-coding tables are numbered 0..15 }
+  MAX_COMPS_IN_SCAN   = 4;      { JPEG limit on # of components in one scan }
+  MAX_SAMP_FACTOR     = 4;      { JPEG limit on sampling factors }
+{ Unfortunately, some bozo at Adobe saw no reason to be bound by the standard;
+  the PostScript DCT filter can emit files with many more than 10 blocks/MCU.
+  If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU
+  to handle it.  We even let you do this from the jconfig.h file.  However,
+  we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
+  sometimes emits noncompliant files doesn't mean you should too. }
+  C_MAX_BLOCKS_IN_MCU = 10;     { compressor's limit on blocks per MCU }
+  D_MAX_BLOCKS_IN_MCU = 10;     { decompressor's limit on blocks per MCU }
+
+
+{ Data structures for images (arrays of samples and of DCT coefficients).
+  On 80x86 machines, the image arrays are too big for near pointers,
+  but the pointer arrays can fit in near memory. }
+
+type
+{ for typecasting }
+  JSAMPLE_PTR = ^JSAMPLE;
+  JSAMPROW_PTR = ^JSAMPROW;
+  JBLOCKROW_PTR = ^JBLOCKROW;
+
+  jTSample = 0..(MaxInt div SIZEOF(JSAMPLE))-1;
+  JSAMPLE_ARRAY = Array[jTSample] of JSAMPLE;  {far}
+  JSAMPROW = ^JSAMPLE_ARRAY;  { ptr to one image row of pixel samples. }
+
+  jTRow = 0..(MaxInt div SIZEOF(JSAMPROW))-1;
+  JSAMPROW_ARRAY = Array[jTRow] of JSAMPROW;
+  JSAMPARRAY = ^JSAMPROW_ARRAY;  { ptr to some rows (a 2-D sample array) }
+
+  jTArray = 0..(MaxInt div SIZEOF(JSAMPARRAY))-1;
+  JSAMP_ARRAY = Array[jTArray] of JSAMPARRAY;
+  JSAMPIMAGE = ^JSAMP_ARRAY;  { a 3-D sample array: top index is color }
+
+  JBLOCK = Array[0..DCTSIZE2-1] of JCOEF;   { one block of coefficients }
+  JBLOCK_PTR = ^JBLOCK;
+
+  jTBlockRow = 0..(MaxInt div SIZEOF(JBLOCK))-1;
+  JBLOCK_ROWS = Array[jTBlockRow] of JBLOCK;
+  JBLOCKROW = ^JBLOCK_ROWS; {far} { pointer to one row of coefficient blocks }
+
+
+  jTBlockArray = 0..(MaxInt div SIZEOF(JBLOCKROW))-1;
+  JBLOCK_ARRAY = Array[jTBlockArray] of JBLOCKROW;
+  JBLOCKARRAY = ^JBLOCK_ARRAY;    { a 2-D array of coefficient blocks }
+
+  jTBlockImage = 0..(MaxInt div SIZEOF(JBLOCKARRAY))-1;
+  JBLOCK_IMAGE = Array[jTBlockImage] of JBLOCKARRAY;
+  JBLOCKIMAGE = ^JBLOCK_IMAGE;   { a 3-D array of coefficient blocks }
+
+  jTCoef = 0..(MaxInt div SIZEOF(JCOEF))-1;
+  JCOEF_ROW = Array[jTCoef] of JCOEF;
+  JCOEFPTR = ^JCOEF_ROW; {far}   { useful in a couple of places }
+
+
+type
+  jTByte = 0..(MaxInt div SIZEOF(byte))-1;
+  JByteArray = Array[jTByte] of byte;
+  JBytePtr = ^JByteArray;
+type
+  byteptr = ^byte;
+
+{ Types for JPEG compression parameters and working tables. }
+
+
+{ DCT coefficient quantization tables. }
+
+type
+  JQUANT_TBL_PTR = ^JQUANT_TBL;
+  JQUANT_TBL = record
+  { This array gives the coefficient quantizers in natural array order
+    (not the zigzag order in which they are stored in a JPEG DQT marker).
+    CAUTION: IJG versions prior to v6a kept this array in zigzag order. }
+    quantval : Array[0..DCTSIZE2-1] of UINT16;
+                               { quantization step for each coefficient }
+  { This field is used only during compression.  It's initialized FALSE when
+    the table is created, and set TRUE when it's been output to the file.
+    You could suppress output of a table by setting this to TRUE.
+    (See jpeg_suppress_tables for an example.) }
+    sent_table : boolean;      { TRUE when table has been output }
+  end;
+  JQUANT_TBL_FIELD = Array[0..(MaxInt div SizeOf(JQUANT_TBL))-1] of JQUANT_TBL;
+
+{ Huffman coding tables. }
+
+type
+  JHUFF_TBL_PTR = ^JHUFF_TBL;
+  JHUFF_TBL = record
+  { These two fields directly represent the contents of a JPEG DHT marker }
+    bits : Array[0..17-1] of UINT8; { bits[k] = # of symbols with codes of }
+                                    { length k bits; bits[0] is unused }
+    huffval : Array[0..256-1] of UINT8;
+                                    { The symbols, in order of incr code length }
+  { This field is used only during compression.  It's initialized FALSE when
+    the table is created, and set TRUE when it's been output to the file.
+    You could suppress output of a table by setting this to TRUE.
+    (See jpeg_suppress_tables for an example.) }
+    sent_table : boolean;           { TRUE when table has been output }
+  end;
+  JHUFF_TBL_FIELD = Array[0..(MaxInt div SizeOf(JHUFF_TBL))-1] of JHUFF_TBL;
+
+{ Declarations for both compression & decompression }
+
+type
+  J_BUF_MODE = (    { Operating modes for buffer controllers }
+  JBUF_PASS_THRU,   { Plain stripwise operation }
+  { Remaining modes require a full-image buffer to have been created }
+  JBUF_SAVE_SOURCE, { Run source subobject only, save output }
+  JBUF_CRANK_DEST,  { Run dest subobject only, using saved data }
+  JBUF_SAVE_AND_PASS  { Run both subobjects, save output }
+               );
+
+{ Values of global_state field (jdapi.c has some dependencies on ordering!) }
+const
+  CSTATE_START        = 100;    { after create_compress }
+  CSTATE_SCANNING     = 101;    { start_compress done, write_scanlines OK }
+  CSTATE_RAW_OK       = 102;    { start_compress done, write_raw_data OK }
+  CSTATE_WRCOEFS      = 103;    { jpeg_write_coefficients done }
+  DSTATE_START        = 200;    { after create_decompress }
+  DSTATE_INHEADER     = 201;    { reading header markers, no SOS yet }
+  DSTATE_READY        = 202;    { found SOS, ready for start_decompress }
+  DSTATE_PRELOAD      = 203;    { reading multiscan file in start_decompress}
+  DSTATE_PRESCAN      = 204;    { performing dummy pass for 2-pass quant }
+  DSTATE_SCANNING     = 205;    { start_decompress done, read_scanlines OK }
+  DSTATE_RAW_OK       = 206;    { start_decompress done, read_raw_data OK }
+  DSTATE_BUFIMAGE     = 207;    { expecting jpeg_start_output }
+  DSTATE_BUFPOST      = 208;    { looking for SOS/EOI in jpeg_finish_output }
+  DSTATE_RDCOEFS      = 209;    { reading file in jpeg_read_coefficients }
+  DSTATE_STOPPING     = 210;    { looking for EOI in jpeg_finish_decompress }
+
+
+
+{ Basic info about one component (color channel). }
+
+type
+  jpeg_component_info_ptr = ^jpeg_component_info;
+  jpeg_component_info = record
+    { These values are fixed over the whole image. }
+    { For compression, they must be supplied by parameter setup; }
+    { for decompression, they are read from the SOF marker. }
+    component_id : int;           { identifier for this component (0..255) }
+    component_index : int;        { its index in SOF or cinfo^.comp_info[] }
+    h_samp_factor : int;          { horizontal sampling factor (1..4) }
+    v_samp_factor : int;          { vertical sampling factor (1..4) }
+    quant_tbl_no : int;           { quantization table selector (0..3) }
+    { These values may vary between scans. }
+    { For compression, they must be supplied by parameter setup; }
+    { for decompression, they are read from the SOS marker. }
+    { The decompressor output side may not use these variables. }
+    dc_tbl_no : int;              { DC entropy table selector (0..3) }
+    ac_tbl_no : int;              { AC entropy table selector (0..3) }
+
+    { Remaining fields should be treated as private by applications. }
+
+    { These values are computed during compression or decompression startup: }
+    { Component's size in DCT blocks.
+      Any dummy blocks added to complete an MCU are not counted; therefore
+      these values do not depend on whether a scan is interleaved or not. }
+    width_in_blocks : JDIMENSION;
+    height_in_blocks : JDIMENSION;
+    { Size of a DCT block in samples.  Always DCTSIZE for compression.
+      For decompression this is the size of the output from one DCT block,
+      reflecting any scaling we choose to apply during the IDCT step.
+      Values of 1,2,4,8 are likely to be supported.  Note that different
+      components may receive different IDCT scalings. }
+
+    DCT_scaled_size : int;
+    { The downsampled dimensions are the component's actual, unpadded number
+      of samples at the main buffer (preprocessing/compression interface), thus
+      downsampled_width = ceil(image_width * Hi/Hmax)
+      and similarly for height.  For decompression, IDCT scaling is included, so
+      downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)}
+
+    downsampled_width : JDIMENSION;        { actual width in samples }
+    downsampled_height : JDIMENSION;       { actual height in samples }
+    { This flag is used only for decompression.  In cases where some of the
+      components will be ignored (eg grayscale output from YCbCr image),
+      we can skip most computations for the unused components. }
+
+    component_needed : boolean;     { do we need the value of this component? }
+
+    { These values are computed before starting a scan of the component. }
+    { The decompressor output side may not use these variables. }
+    MCU_width : int;      { number of blocks per MCU, horizontally }
+    MCU_height : int;     { number of blocks per MCU, vertically }
+    MCU_blocks : int;     { MCU_width * MCU_height }
+    MCU_sample_width : int;       { MCU width in samples, MCU_width*DCT_scaled_size }
+    last_col_width : int;         { # of non-dummy blocks across in last MCU }
+    last_row_height : int;        { # of non-dummy blocks down in last MCU }
+
+    { Saved quantization table for component; NIL if none yet saved.
+      See jdinput.c comments about the need for this information.
+      This field is currently used only for decompression. }
+
+    quant_table : JQUANT_TBL_PTR;
+
+    { Private per-component storage for DCT or IDCT subsystem. }
+    dct_table : pointer;
+  end; { record jpeg_component_info }
+
+  jTCinfo = 0..(MaxInt div SizeOf(jpeg_component_info))-1;
+  jpeg_component_info_array = array[jTCinfo] of jpeg_component_info;
+  jpeg_component_info_list_ptr = ^jpeg_component_info_array;
+
+
+{ The script for encoding a multiple-scan file is an array of these: }
+
+type
+  jpeg_scan_info_ptr = ^jpeg_scan_info;
+  jpeg_scan_info = record
+    comps_in_scan : int;                { number of components encoded in this scan }
+    component_index : Array[0..MAX_COMPS_IN_SCAN-1] of int;
+                                        { their SOF/comp_info[] indexes }
+    Ss, Se : int;                       { progressive JPEG spectral selection parms }
+    Ah, Al : int;                       { progressive JPEG successive approx. parms }
+  end;
+
+{ The decompressor can save APPn and COM markers in a list of these: }
+
+type
+  jpeg_saved_marker_ptr = ^jpeg_marker_struct;
+  jpeg_marker_struct = record
+    next : jpeg_saved_marker_ptr;    { next in list, or NULL }
+    marker : UINT8;                  { marker code: JPEG_COM, or JPEG_APP0+n }
+    original_length : uint;          { # bytes of data in the file }
+    data_length : uint;              { # bytes of data saved at data[] }
+    data : JOCTET_FIELD_PTR;         { the data contained in the marker }
+   { the marker length word is not counted in data_length or original_length }
+  end;
+
+{ Known color spaces. }
+
+type
+  J_COLOR_SPACE = (
+  JCS_UNKNOWN,            { error/unspecified }
+  JCS_GRAYSCALE,          { monochrome }
+  JCS_RGB,                { red/green/blue }
+  JCS_YCbCr,              { Y/Cb/Cr (also known as YUV) }
+  JCS_CMYK,               { C/M/Y/K }
+  JCS_YCCK                { Y/Cb/Cr/K }
+                  );
+
+{ DCT/IDCT algorithm options. }
+
+type
+  J_DCT_METHOD = (
+  JDCT_ISLOW,   { slow but accurate integer algorithm }
+  JDCT_IFAST,   { faster, less accurate integer method }
+  JDCT_FLOAT    { floating-point: accurate, fast on fast HW }
+                 );
+
+const
+  JDCT_DEFAULT = JDCT_ISLOW;
+  JDCT_FASTEST = JDCT_IFAST;
+
+{ Dithering options for decompression. }
+
+type
+  J_DITHER_MODE = (
+    JDITHER_NONE,               { no dithering }
+    JDITHER_ORDERED,            { simple ordered dither }
+    JDITHER_FS                  { Floyd-Steinberg error diffusion dither }
+                  );
+
+
+const
+  JPOOL_PERMANENT  = 0; { lasts until master record is destroyed }
+  JPOOL_IMAGE      = 1; { lasts until done with image/datastream }
+  JPOOL_NUMPOOLS   = 2;
+
+
+{ "Object" declarations for JPEG modules that may be supplied or called
+  directly by the surrounding application.
+  As with all objects in the JPEG library, these structs only define the
+  publicly visible methods and state variables of a module.  Additional
+  private fields may exist after the public ones. }
+
+
+{ Error handler object }
+
+const
+  JMSG_LENGTH_MAX  = 200;  { recommended size of format_message buffer }
+  JMSG_STR_PARM_MAX = 80;
+
+const
+  TEMP_NAME_LENGTH = 64;   { max length of a temporary file's name }
+type
+  TEMP_STRING = string[TEMP_NAME_LENGTH];
+
+{$ifdef USE_MSDOS_MEMMGR}  { DOS-specific junk }
+type
+  XMSH = ushort;           { type of extended-memory handles }
+  EMSH = ushort;           { type of expanded-memory handles }
+
+  handle_union = record
+    case byte of
+    0:(file_handle : short);    { DOS file handle if it's a temp file }
+    1:(xms_handle : XMSH);      { handle if it's a chunk of XMS }
+    2:(ems_handle : EMSH);      { handle if it's a chunk of EMS }
+  end;
+{$endif} { USE_MSDOS_MEMMGR }
+
+type
+  jpeg_error_mgr_ptr = ^jpeg_error_mgr;
+  jpeg_memory_mgr_ptr = ^jpeg_memory_mgr;
+  jpeg_progress_mgr_ptr = ^jpeg_progress_mgr;
+
+
+{$ifdef common}
+{ Common fields between JPEG compression and decompression master structs. }
+    err : jpeg_error_mgr_ptr;            { Error handler module }
+    mem : jpeg_memory_mgr_ptr;           { Memory manager module }
+    progress : jpeg_progress_mgr_ptr;    { Progress monitor, or NIL if none }
+    client_data : voidp;                 { Available for use by application }
+    is_decompressor : boolean;     { so common code can tell which is which }
+    global_state : int;            { for checking call sequence validity }
+{$endif}
+
+  j_common_ptr = ^jpeg_common_struct;
+  j_compress_ptr = ^jpeg_compress_struct;
+  j_decompress_ptr = ^jpeg_decompress_struct;
+
+  {$ifdef AM_MEMORY_MANAGER}  { only jmemmgr.c defines these }
+
+{ This structure holds whatever state is needed to access a single
+  backing-store object.  The read/write/close method pointers are called
+  by jmemmgr.c to manipulate the backing-store object; all other fields
+  are private to the system-dependent backing store routines. }
+
+
+  backing_store_ptr = ^backing_store_info;
+  backing_store_info = record
+  { Methods for reading/writing/closing this backing-store object }
+    read_backing_store : procedure (cinfo : j_common_ptr;
+            info : backing_store_ptr;
+            buffer_address : pointer; {far}
+            file_offset : long;
+                                    byte_count : long);
+    write_backing_store : procedure (cinfo : j_common_ptr;
+             info : backing_store_ptr;
+             buffer_address : pointer;  {far}
+             file_offset : long;
+                                     byte_count : long);
+
+    close_backing_store : procedure (cinfo : j_common_ptr;
+             info : backing_store_ptr);
+
+  { Private fields for system-dependent backing-store management }
+  {$ifdef USE_MSDOS_MEMMGR}
+    { For the MS-DOS manager (jmemdos.c), we need: }
+    handle : handle_union;            { reference to backing-store storage object }
+    temp_name : TEMP_STRING;  { name if it's a file }
+  {$else}
+    { For a typical implementation with temp files, we need: }
+    temp_file : file;                 { stdio reference to temp file }
+    temp_name : TEMP_STRING;  { name of temp file }
+  {$endif}
+ end;
+
+
+{ The control blocks for virtual arrays.
+  Note that these blocks are allocated in the "small" pool area.
+  System-dependent info for the associated backing store (if any) is hidden
+  inside the backing_store_info struct. }
+
+  jvirt_sarray_ptr = ^jvirt_sarray_control;
+  jvirt_sarray_control = record
+    mem_buffer : JSAMPARRAY;    { => the in-memory buffer }
+    rows_in_array : JDIMENSION; { total virtual array height }
+    samplesperrow : JDIMENSION; { width of array (and of memory buffer) }
+    maxaccess : JDIMENSION;     { max rows accessed by access_virt_sarray }
+    rows_in_mem : JDIMENSION;   { height of memory buffer }
+    rowsperchunk : JDIMENSION;  { allocation chunk size in mem_buffer }
+    cur_start_row : JDIMENSION; { first logical row # in the buffer }
+    first_undef_row : JDIMENSION; { row # of first uninitialized row }
+    pre_zero : boolean;         { pre-zero mode requested? }
+    dirty : boolean;            { do current buffer contents need written? }
+    b_s_open : boolean;         { is backing-store data valid? }
+    next : jvirt_sarray_ptr;    { link to next virtual sarray control block }
+    b_s_info : backing_store_info; { System-dependent control info }
+  end;
+
+  jvirt_barray_ptr = ^jvirt_barray_control;
+  jvirt_barray_control = record
+    mem_buffer : JBLOCKARRAY;   { => the in-memory buffer }
+    rows_in_array : JDIMENSION; { total virtual array height }
+    blocksperrow : JDIMENSION;  { width of array (and of memory buffer) }
+    maxaccess : JDIMENSION;     { max rows accessed by access_virt_barray }
+    rows_in_mem : JDIMENSION;   { height of memory buffer }
+    rowsperchunk : JDIMENSION;  { allocation chunk size in mem_buffer }
+    cur_start_row : JDIMENSION; { first logical row # in the buffer }
+    first_undef_row : JDIMENSION; { row # of first uninitialized row }
+    pre_zero : boolean;         { pre-zero mode requested? }
+    dirty : boolean;            { do current buffer contents need written? }
+    b_s_open : boolean;         { is backing-store data valid? }
+    next : jvirt_barray_ptr;    { link to next virtual barray control block }
+    b_s_info : backing_store_info;  { System-dependent control info }
+  end;
+
+  {$endif} { AM_MEMORY_MANAGER }
+
+{ Declarations for compression modules }
+
+{ Master control module }
+  jpeg_comp_master_ptr = ^jpeg_comp_master;
+  jpeg_comp_master = record
+    prepare_for_pass : procedure(cinfo : j_compress_ptr);
+    pass_startup : procedure(cinfo : j_compress_ptr);
+    finish_pass : procedure(cinfo : j_compress_ptr);
+
+    { State variables made visible to other modules }
+    call_pass_startup : Boolean;   { True if pass_startup must be called }
+    is_last_pass : Boolean;        { True during last pass }
+  end;
+
+{ Main buffer control (downsampled-data buffer) }
+  jpeg_c_main_controller_ptr = ^jpeg_c_main_controller;
+  jpeg_c_main_controller = record
+    start_pass : procedure(cinfo : j_compress_ptr; pass_mode : J_BUF_MODE);
+    process_data : procedure(cinfo : j_compress_ptr;
+                             input_buf : JSAMPARRAY;
+                             var in_row_ctr : JDIMENSION;
+           in_rows_avail : JDIMENSION);
+  end;
+
+{ Compression preprocessing (downsampling input buffer control) }
+  jpeg_c_prep_controller_ptr = ^jpeg_c_prep_controller;
+  jpeg_c_prep_controller = record
+    start_pass : procedure(cinfo : j_compress_ptr; pass_mode : J_BUF_MODE);
+    pre_process_data : procedure(cinfo : j_compress_ptr;
+         input_buf : JSAMPARRAY;
+         var in_row_ctr : JDIMENSION;
+         in_rows_avail : JDIMENSION;
+         output_buf : JSAMPIMAGE;
+         var out_row_group_ctr : JDIMENSION;
+         out_row_groups_avail : JDIMENSION);
+  end;
+
+{ Coefficient buffer control }
+  jpeg_c_coef_controller_ptr = ^jpeg_c_coef_controller;
+  jpeg_c_coef_controller = record
+    start_pass : procedure(cinfo : j_compress_ptr; pass_mode : J_BUF_MODE);
+    compress_data : function(cinfo : j_compress_ptr;
+                             input_buf : JSAMPIMAGE) : boolean;
+  end;
+
+{ Colorspace conversion }
+  jpeg_color_converter_ptr = ^jpeg_color_converter;
+  jpeg_color_converter = record
+    start_pass : procedure(cinfo : j_compress_ptr);
+    color_convert : procedure(cinfo : j_compress_ptr;
+                              input_buf : JSAMPARRAY;
+                              output_buf : JSAMPIMAGE;
+            output_row : JDIMENSION;
+                              num_rows : int);
+  end;
+
+{ Downsampling }
+  jpeg_downsampler_ptr = ^jpeg_downsampler;
+  jpeg_downsampler = record
+    start_pass : procedure(cinfo : j_compress_ptr);
+    downsample : procedure(cinfo : j_compress_ptr;
+         input_buf : JSAMPIMAGE;
+                           in_row_index :  JDIMENSION;
+         output_buf : JSAMPIMAGE;
+         out_row_group_index: JDIMENSION);
+    need_context_rows : Boolean;  { TRUE if need rows above & below }
+  end;
+
+{ Forward DCT (also controls coefficient quantization) }
+  jpeg_forward_dct_ptr = ^jpeg_forward_dct;
+  jpeg_forward_dct = record
+    start_pass : procedure(cinfo : j_compress_ptr);
+    { perhaps this should be an array??? }
+    forward_DCT : procedure(cinfo : j_compress_ptr;
+          compptr : jpeg_component_info_ptr;
+          sample_data : JSAMPARRAY;
+                            coef_blocks : JBLOCKROW;
+          start_row : JDIMENSION;
+                            start_col : JDIMENSION;
+          num_blocks : JDIMENSION);
+  end;
+
+{ Entropy encoding }
+
+  jpeg_entropy_encoder_ptr = ^jpeg_entropy_encoder;
+  jpeg_entropy_encoder = record
+    start_pass : procedure(cinfo : j_compress_ptr; gather_statistics : boolean);
+    encode_mcu : function(cinfo : j_compress_ptr;
+                          const MCU_data: array of JBLOCKROW) : boolean;
+    finish_pass : procedure(cinfo : j_compress_ptr);
+  end;
+
+{ Marker writing }
+  jpeg_marker_writer_ptr = ^jpeg_marker_writer;
+  jpeg_marker_writer = record
+    write_file_header : procedure(cinfo : j_compress_ptr);
+    write_frame_header : procedure(cinfo : j_compress_ptr);
+    write_scan_header : procedure(cinfo : j_compress_ptr);
+    write_file_trailer : procedure(cinfo : j_compress_ptr);
+    write_tables_only : procedure(cinfo : j_compress_ptr);
+   { These routines are exported to allow insertion of extra markers }
+   { Probably only COM and APPn markers should be written this way }
+    write_marker_header : procedure (cinfo : j_compress_ptr;
+                                     marker : int;
+             datalen : uint);
+    write_marker_byte : procedure (cinfo : j_compress_ptr; val : int);
+  end;
+
+{ Declarations for decompression modules }
+
+{ Master control module }
+  jpeg_decomp_master_ptr = ^jpeg_decomp_master;
+  jpeg_decomp_master = record
+    prepare_for_output_pass : procedure( cinfo : j_decompress_ptr);
+    finish_output_pass : procedure(cinfo : j_decompress_ptr);
+
+    { State variables made visible to other modules }
+    is_dummy_pass : Boolean;  { True during 1st pass for 2-pass quant }
+  end;
+
+{ Input control module }
+  jpeg_input_controller_ptr = ^jpeg_input_controller;
+  jpeg_input_controller = record
+    consume_input : function (cinfo : j_decompress_ptr) : int;
+    reset_input_controller : procedure(cinfo : j_decompress_ptr);
+    start_input_pass : procedure(cinfo : j_decompress_ptr);
+    finish_input_pass : procedure(cinfo : j_decompress_ptr);
+
+    { State variables made visible to other modules }
+    has_multiple_scans : Boolean;  { True if file has multiple scans }
+    eoi_reached : Boolean;         { True when EOI has been consumed }
+  end;
+
+{ Main buffer control (downsampled-data buffer) }
+
+  jpeg_d_main_controller_ptr = ^jpeg_d_main_controller;
+  jpeg_d_main_controller = record
+    start_pass : procedure(cinfo : j_decompress_ptr; pass_mode : J_BUF_MODE);
+    process_data : procedure(cinfo : j_decompress_ptr;
+                             output_buf : JSAMPARRAY;
+                             var out_row_ctr : JDIMENSION;
+                       out_rows_avail : JDIMENSION);
+  end;
+
+{ Coefficient buffer control }
+  jvirt_barray_tbl = array[0..MAX_COMPONENTS-1] of jvirt_barray_ptr;
+  jvirt_barray_tbl_ptr = ^jvirt_barray_tbl;
+  jpeg_d_coef_controller_ptr = ^jpeg_d_coef_controller;
+  jpeg_d_coef_controller = record
+    start_input_pass : procedure(cinfo : j_decompress_ptr);
+    consume_data : function (cinfo : j_decompress_ptr) : int;
+    start_output_pass : procedure(cinfo : j_decompress_ptr);
+    decompress_data : function (cinfo : j_decompress_ptr;
+                                output_buf : JSAMPIMAGE) : int;
+  { Pointer to array of coefficient virtual arrays, or NIL if none }
+    coef_arrays : jvirt_barray_tbl_ptr;
+  end;
+
+{ Decompression postprocessing (color quantization buffer control) }
+  jpeg_d_post_controller_ptr = ^jpeg_d_post_controller;
+  jpeg_d_post_controller = record
+    start_pass : procedure(cinfo : j_decompress_ptr;
+                           pass_mode : J_BUF_MODE);
+    post_process_data : procedure(cinfo : j_decompress_ptr;
+          input_buf : JSAMPIMAGE;
+          var in_row_group_ctr : JDIMENSION;
+          in_row_groups_avail : JDIMENSION;
+          output_buf : JSAMPARRAY;
+          var out_row_ctr : JDIMENSION;
+          out_rows_avail : JDIMENSION);
+  end;
+
+
+{ Routine signature for application-supplied marker processing methods.
+  Need not pass marker code since it is stored in cinfo^.unread_marker. }
+
+  jpeg_marker_parser_method = function(cinfo : j_decompress_ptr) : boolean;
+
+{ Marker reading & parsing }
+  jpeg_marker_reader_ptr = ^jpeg_marker_reader;
+  jpeg_marker_reader = record
+    reset_marker_reader : procedure(cinfo : j_decompress_ptr);
+    { Read markers until SOS or EOI.
+      Returns same codes as are defined for jpeg_consume_input:
+      JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. }
+
+    read_markers : function (cinfo : j_decompress_ptr) : int;
+    { Read a restart marker --- exported for use by entropy decoder only }
+    read_restart_marker : jpeg_marker_parser_method;
+
+    { State of marker reader --- nominally internal, but applications
+      supplying COM or APPn handlers might like to know the state. }
+
+    saw_SOI : boolean;            { found SOI? }
+    saw_SOF : boolean;            { found SOF? }
+    next_restart_num : int;       { next restart number expected (0-7) }
+    discarded_bytes : uint;       { # of bytes skipped looking for a marker }
+  end;
+
+{ Entropy decoding }
+  jpeg_entropy_decoder_ptr = ^jpeg_entropy_decoder;
+  jpeg_entropy_decoder = record
+    start_pass : procedure(cinfo : j_decompress_ptr);
+    decode_mcu : function(cinfo : j_decompress_ptr;
+                          var MCU_data : array of JBLOCKROW) : boolean;
+  { This is here to share code between baseline and progressive decoders; }
+  { other modules probably should not use it }
+    insufficient_data : BOOLEAN;  { set TRUE after emitting warning }
+  end;
+
+{ Inverse DCT (also performs dequantization) }
+  inverse_DCT_method_ptr = procedure(cinfo : j_decompress_ptr;
+                 compptr : jpeg_component_info_ptr;
+     coef_block : JCOEFPTR;
+     output_buf : JSAMPARRAY; output_col : JDIMENSION);
+
+  jpeg_inverse_dct_ptr = ^jpeg_inverse_dct;
+  jpeg_inverse_dct = record
+    start_pass : procedure(cinfo : j_decompress_ptr);
+    { It is useful to allow each component to have a separate IDCT method. }
+    inverse_DCT : Array[0..MAX_COMPONENTS-1] of inverse_DCT_method_ptr;
+  end;
+
+{ Upsampling (note that upsampler must also call color converter) }
+  jpeg_upsampler_ptr = ^jpeg_upsampler;
+  jpeg_upsampler = record
+    start_pass : procedure(cinfo : j_decompress_ptr);
+    upsample : procedure(cinfo : j_decompress_ptr;
+                   input_buf : JSAMPIMAGE;
+       var in_row_group_ctr : JDIMENSION;  { array of }
+       in_row_groups_avail : JDIMENSION;
+       output_buf : JSAMPARRAY;
+       var out_row_ctr : JDIMENSION;
+       out_rows_avail : JDIMENSION);
+
+    need_context_rows : boolean;  { TRUE if need rows above & below }
+  end;
+
+{ Colorspace conversion }
+  jpeg_color_deconverter_ptr = ^jpeg_color_deconverter;
+  jpeg_color_deconverter = record
+    start_pass : procedure(cinfo: j_decompress_ptr);
+    color_convert : procedure(cinfo : j_decompress_ptr;
+                              input_buf : JSAMPIMAGE;
+                              input_row : JDIMENSION;
+                              output_buf : JSAMPARRAY;
+                              num_rows : int);
+  end;
+
+{ Color quantization or color precision reduction }
+  jpeg_color_quantizer_ptr = ^jpeg_color_quantizer;
+  jpeg_color_quantizer = record
+    start_pass : procedure(cinfo : j_decompress_ptr; is_pre_scan : boolean);
+    color_quantize : procedure(cinfo : j_decompress_ptr;
+                               input_buf : JSAMPARRAY;
+                               output_buf : JSAMPARRAY;
+                               num_rows : int);
+
+    finish_pass : procedure(cinfo : j_decompress_ptr);
+    new_color_map : procedure(cinfo : j_decompress_ptr);
+  end;
+
+  {int8array = Array[0..8-1] of int;}
+  int8array = Array[0..8-1] of longint; { for TP FormatStr }
+
+  jpeg_error_mgr = record
+    { Error exit handler: does not return to caller }
+    error_exit : procedure  (cinfo : j_common_ptr);
+    { Conditionally emit a trace or warning message }
+    emit_message : procedure (cinfo : j_common_ptr; msg_level : int);
+    { Routine that actually outputs a trace or error message }
+    output_message : procedure (cinfo : j_common_ptr);
+    { Format a message string for the most recent JPEG error or message }
+    format_message : procedure  (cinfo : j_common_ptr; var buffer : AnsiString);
+
+    { Reset error state variables at start of a new image }
+    reset_error_mgr : procedure (cinfo : j_common_ptr);
+
+    { The message ID code and any parameters are saved here.
+      A message can have one string parameter or up to 8 int parameters. }
+
+    msg_code : int;
+
+    msg_parm : record
+      case byte of
+      0:(i : int8array);
+      1:(s : string[JMSG_STR_PARM_MAX]);
+    end;
+
+    { Standard state variables for error facility }
+
+    trace_level : int;         { max msg_level that will be displayed }
+
+    { For recoverable corrupt-data errors, we emit a warning message,
+      but keep going unless emit_message chooses to abort.  emit_message
+      should count warnings in num_warnings.  The surrounding application
+      can check for bad data by seeing if num_warnings is nonzero at the
+      end of processing. }
+
+    num_warnings : long;       { number of corrupt-data warnings }
+
+    { These fields point to the table(s) of error message strings.
+      An application can change the table pointer to switch to a different
+      message list (typically, to change the language in which errors are
+      reported).  Some applications may wish to add additional error codes
+      that will be handled by the JPEG library error mechanism; the second
+      table pointer is used for this purpose.
+
+      First table includes all errors generated by JPEG library itself.
+      Error code 0 is reserved for a "no such error string" message. }
+
+    {const char * const * jpeg_message_table; }
+    jpeg_message_table : ^msg_table; { Library errors }
+
+    last_jpeg_message : J_MESSAGE_CODE;
+      { Table contains strings 0..last_jpeg_message }
+    { Second table can be added by application (see cjpeg/djpeg for example).
+      It contains strings numbered first_addon_message..last_addon_message. }
+
+    {const char * const * addon_message_table; }
+    addon_message_table : ^msg_table; { Non-library errors }
+
+    first_addon_message : J_MESSAGE_CODE;  { code for first string in addon table }
+    last_addon_message : J_MESSAGE_CODE;   { code for last string in addon table }
+  end;
+
+
+{ Progress monitor object }
+
+  jpeg_progress_mgr = record
+    progress_monitor : procedure(cinfo : j_common_ptr);
+
+    pass_counter : long;        { work units completed in this pass }
+    pass_limit : long;          { total number of work units in this pass }
+    completed_passes : int; { passes completed so far }
+    total_passes : int;         { total number of passes expected }
+  end;
+
+
+{ Data destination object for compression }
+  jpeg_destination_mgr_ptr = ^jpeg_destination_mgr;
+  jpeg_destination_mgr = record
+    next_output_byte : JOCTETptr;  { => next byte to write in buffer }
+    free_in_buffer : size_t;    { # of byte spaces remaining in buffer }
+
+    init_destination : procedure (cinfo : j_compress_ptr);
+    empty_output_buffer : function (cinfo : j_compress_ptr) : boolean;
+    term_destination : procedure (cinfo : j_compress_ptr);
+  end;
+
+
+{ Data source object for decompression }
+
+  jpeg_source_mgr_ptr = ^jpeg_source_mgr;
+  jpeg_source_mgr = record
+    {const JOCTET * next_input_byte;}
+    next_input_byte : JOCTETptr;      { => next byte to read from buffer }
+    bytes_in_buffer : size_t;       { # of bytes remaining in buffer }
+
+    init_source : procedure  (cinfo : j_decompress_ptr);
+    fill_input_buffer : function (cinfo : j_decompress_ptr) : boolean;
+    skip_input_data : procedure (cinfo : j_decompress_ptr; num_bytes : long);
+    resync_to_restart : function (cinfo : j_decompress_ptr;
+                                  desired : int) : boolean;
+    term_source : procedure (cinfo : j_decompress_ptr);
+  end;
+
+
+{ Memory manager object.
+  Allocates "small" objects (a few K total), "large" objects (tens of K),
+  and "really big" objects (virtual arrays with backing store if needed).
+  The memory manager does not allow individual objects to be freed; rather,
+  each created object is assigned to a pool, and whole pools can be freed
+  at once.  This is faster and more convenient than remembering exactly what
+  to free, especially where malloc()/free() are not too speedy.
+  NB: alloc routines never return NIL.  They exit to error_exit if not
+  successful. }
+
+
+  jpeg_memory_mgr = record
+    { Method pointers }
+    alloc_small : function (cinfo : j_common_ptr; pool_id : int;
+          sizeofobject : size_t) : pointer;
+    alloc_large : function (cinfo : j_common_ptr; pool_id : int;
+          sizeofobject : size_t) : pointer; {far}
+    alloc_sarray : function (cinfo : j_common_ptr; pool_id : int;
+                             samplesperrow : JDIMENSION;
+                             numrows : JDIMENSION) : JSAMPARRAY;
+
+    alloc_barray : function (cinfo : j_common_ptr; pool_id : int;
+                             blocksperrow : JDIMENSION;
+                             numrows : JDIMENSION) : JBLOCKARRAY;
+
+    request_virt_sarray : function(cinfo : j_common_ptr;
+                                   pool_id : int;
+                                   pre_zero : boolean;
+                                   samplesperrow : JDIMENSION;
+                                   numrows : JDIMENSION;
+                                   maxaccess : JDIMENSION) : jvirt_sarray_ptr;
+
+    request_virt_barray : function(cinfo : j_common_ptr;
+                                   pool_id : int;
+                                   pre_zero : boolean;
+                                   blocksperrow : JDIMENSION;
+                                   numrows : JDIMENSION;
+                                   maxaccess : JDIMENSION) : jvirt_barray_ptr;
+
+    realize_virt_arrays : procedure (cinfo : j_common_ptr);
+
+    access_virt_sarray : function (cinfo : j_common_ptr;
+                                   ptr : jvirt_sarray_ptr;
+                                   start_row : JDIMENSION;
+                                   num_rows : JDIMENSION;
+           writable : boolean) : JSAMPARRAY;
+
+    access_virt_barray : function (cinfo : j_common_ptr;
+                                   ptr : jvirt_barray_ptr;
+                                   start_row : JDIMENSION;
+                                   num_rows : JDIMENSION;
+                                   writable : boolean) : JBLOCKARRAY;
+
+    free_pool : procedure  (cinfo : j_common_ptr; pool_id : int);
+    self_destruct : procedure (cinfo : j_common_ptr);
+
+    { Limit on memory allocation for this JPEG object.  (Note that this is
+      merely advisory, not a guaranteed maximum; it only affects the space
+      used for virtual-array buffers.)  May be changed by outer application
+      after creating the JPEG object. }
+    max_memory_to_use : long;
+
+    { Maximum allocation request accepted by alloc_large. }
+    max_alloc_chunk : long;
+  end;
+
+{ Routines that are to be used by both halves of the library are declared
+  to receive a pointer to this structure.  There are no actual instances of
+  jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.}
+  jpeg_common_struct = record
+  { Fields common to both master struct types }
+    err : jpeg_error_mgr_ptr;           { Error handler module }
+    mem : jpeg_memory_mgr_ptr;          { Memory manager module }
+    progress : jpeg_progress_mgr_ptr;   { Progress monitor, or NIL if none }
+    client_data : voidp;                { Available for use by application }
+    is_decompressor : boolean;     { so common code can tell which is which }
+    global_state : int;            { for checking call sequence validity }
+
+  { Additional fields follow in an actual jpeg_compress_struct or
+    jpeg_decompress_struct.  All three structs must agree on these
+    initial fields!  (This would be a lot cleaner in C++.) }
+  end;
+
+
+{ Master record for a compression instance }
+
+  jpeg_compress_struct = record
+    { Fields shared with jpeg_decompress_struct }
+    err : jpeg_error_mgr_ptr;          { Error handler module }
+    mem : jpeg_memory_mgr_ptr;         { Memory manager module }
+    progress : jpeg_progress_mgr_ptr;  { Progress monitor, or NIL if none }
+    client_data : voidp;               { Available for use by application }
+    is_decompressor : boolean;      { so common code can tell which is which }
+    global_state : int;             { for checking call sequence validity }
+
+  { Destination for compressed data }
+    dest : jpeg_destination_mgr_ptr;
+
+  { Description of source image --- these fields must be filled in by
+    outer application before starting compression.  in_color_space must
+    be correct before you can even call jpeg_set_defaults(). }
+
+
+    image_width : JDIMENSION;         { input image width }
+    image_height : JDIMENSION;        { input image height }
+    input_components : int;           { # of color components in input image }
+    in_color_space : J_COLOR_SPACE;   { colorspace of input image }
+
+    input_gamma : double;             { image gamma of input image }
+
+    { Compression parameters --- these fields must be set before calling
+      jpeg_start_compress().  We recommend calling jpeg_set_defaults() to
+      initialize everything to reasonable defaults, then changing anything
+      the application specifically wants to change.  That way you won't get
+      burnt when new parameters are added.  Also note that there are several
+      helper routines to simplify changing parameters. }
+
+    data_precision : int;             { bits of precision in image data }
+
+    num_components : int;             { # of color components in JPEG image }
+    jpeg_color_space : J_COLOR_SPACE; { colorspace of JPEG image }
+
+    comp_info : jpeg_component_info_list_ptr;
+    { comp_info^[i] describes component that appears i'th in SOF }
+
+    quant_tbl_ptrs: Array[0..NUM_QUANT_TBLS-1] of JQUANT_TBL_PTR;
+    { ptrs to coefficient quantization tables, or NIL if not defined }
+
+    dc_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR;
+    ac_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR;
+    { ptrs to Huffman coding tables, or NIL if not defined }
+
+    arith_dc_L : Array[0..NUM_ARITH_TBLS-1] of UINT8; { L values for DC arith-coding tables }
+    arith_dc_U : Array[0..NUM_ARITH_TBLS-1] of UINT8; { U values for DC arith-coding tables }
+    arith_ac_K : Array[0..NUM_ARITH_TBLS-1] of UINT8; { Kx values for AC arith-coding tables }
+
+    num_scans : int;     { # of entries in scan_info array }
+    scan_info : jpeg_scan_info_ptr; { script for multi-scan file, or NIL }
+    { The default value of scan_info is NIL, which causes a single-scan
+      sequential JPEG file to be emitted.  To create a multi-scan file,
+      set num_scans and scan_info to point to an array of scan definitions. }
+
+    raw_data_in : boolean;        { TRUE=caller supplies downsampled data }
+    arith_code : boolean;         { TRUE=arithmetic coding, FALSE=Huffman }
+    optimize_coding : boolean;    { TRUE=optimize entropy encoding parms }
+    CCIR601_sampling : boolean;   { TRUE=first samples are cosited }
+    smoothing_factor : int;       { 1..100, or 0 for no input smoothing }
+    dct_method : J_DCT_METHOD;    { DCT algorithm selector }
+
+    { The restart interval can be specified in absolute MCUs by setting
+      restart_interval, or in MCU rows by setting restart_in_rows
+      (in which case the correct restart_interval will be figured
+      for each scan). }
+
+    restart_interval : uint;      { MCUs per restart, or 0 for no restart }
+    restart_in_rows : int;        { if > 0, MCU rows per restart interval }
+
+    { Parameters controlling emission of special markers. }
+
+    write_JFIF_header : boolean; { should a JFIF marker be written? }
+    JFIF_major_version : UINT8;  { What to write for the JFIF version number }
+    JFIF_minor_version : UINT8;
+    { These three values are not used by the JPEG code, merely copied }
+    { into the JFIF APP0 marker.  density_unit can be 0 for unknown, }
+    { 1 for dots/inch, or 2 for dots/cm.  Note that the pixel aspect }
+    { ratio is defined by X_density/Y_density even when density_unit=0. }
+    density_unit : UINT8;         { JFIF code for pixel size units }
+    X_density : UINT16;           { Horizontal pixel density }
+    Y_density : UINT16;           { Vertical pixel density }
+    write_Adobe_marker : boolean; { should an Adobe marker be written? }
+
+    { State variable: index of next scanline to be written to
+      jpeg_write_scanlines().  Application may use this to control its
+      processing loop, e.g., "while (next_scanline < image_height)". }
+
+    next_scanline : JDIMENSION;   { 0 .. image_height-1  }
+
+    { Remaining fields are known throughout compressor, but generally
+      should not be touched by a surrounding application. }
+
+    { These fields are computed during compression startup }
+    progressive_mode : boolean;   { TRUE if scan script uses progressive mode }
+    max_h_samp_factor : int;      { largest h_samp_factor }
+    max_v_samp_factor : int;      { largest v_samp_factor }
+
+    total_iMCU_rows : JDIMENSION; { # of iMCU rows to be input to coef ctlr }
+    { The coefficient controller receives data in units of MCU rows as defined
+      for fully interleaved scans (whether the JPEG file is interleaved or not).
+      There are v_samp_factor * DCTSIZE sample rows of each component in an
+      "iMCU" (interleaved MCU) row. }
+
+    { These fields are valid during any one scan.
+      They describe the components and MCUs actually appearing in the scan. }
+
+    comps_in_scan : int;          { # of JPEG components in this scan }
+    cur_comp_info : Array[0..MAX_COMPS_IN_SCAN-1] of jpeg_component_info_ptr;
+    { cur_comp_info[i]^ describes component that appears i'th in SOS }
+
+    MCUs_per_row : JDIMENSION;    { # of MCUs across the image }
+    MCU_rows_in_scan : JDIMENSION;{ # of MCU rows in the image }
+
+    blocks_in_MCU : int;          { # of DCT blocks per MCU }
+    MCU_membership : Array[0..C_MAX_BLOCKS_IN_MCU-1] of int;
+    { MCU_membership[i] is index in cur_comp_info of component owning }
+    { i'th block in an MCU }
+
+    Ss, Se, Ah, Al : int;         { progressive JPEG parameters for scan }
+
+    { Links to compression subobjects (methods and private variables of modules) }
+    master : jpeg_comp_master_ptr;
+    main : jpeg_c_main_controller_ptr;
+    prep : jpeg_c_prep_controller_ptr;
+    coef : jpeg_c_coef_controller_ptr;
+    marker : jpeg_marker_writer_ptr;
+    cconvert : jpeg_color_converter_ptr;
+    downsample : jpeg_downsampler_ptr;
+    fdct : jpeg_forward_dct_ptr;
+    entropy : jpeg_entropy_encoder_ptr;
+    script_space : jpeg_scan_info_ptr; { workspace for jpeg_simple_progression }
+    script_space_size : int;
+  end;
+
+
+{ Master record for a decompression instance }
+
+  coef_bits_field = Array[0..DCTSIZE2-1] of int;
+  coef_bits_ptr = ^coef_bits_field;
+  coef_bits_ptrfield =  Array[0..MAX_COMPS_IN_SCAN-1] of coef_bits_field;
+  coef_bits_ptrrow = ^coef_bits_ptrfield;
+
+  range_limit_table = array[-(MAXJSAMPLE+1)..4*(MAXJSAMPLE+1)
+                            + CENTERJSAMPLE -1] of JSAMPLE;
+  range_limit_table_ptr = ^range_limit_table;
+
+  jpeg_decompress_struct = record
+  { Fields shared with jpeg_compress_struct }
+    err : jpeg_error_mgr_ptr;    { Error handler module }
+    mem : jpeg_memory_mgr_ptr;        { Memory manager module }
+    progress : jpeg_progress_mgr_ptr; { Progress monitor, or NIL if none }
+    client_data : voidp;              { Available for use by application }
+    is_decompressor : boolean;     { so common code can tell which is which }
+    global_state : int;            { for checking call sequence validity }
+
+    { Source of compressed data }
+    src : jpeg_source_mgr_ptr;
+
+    { Basic description of image --- filled in by jpeg_read_header(). }
+    { Application may inspect these values to decide how to process image. }
+
+    image_width : JDIMENSION;      { nominal image width (from SOF marker) }
+    image_height : JDIMENSION;     { nominal image height }
+    num_components : int;          { # of color components in JPEG image }
+    jpeg_color_space : J_COLOR_SPACE; { colorspace of JPEG image }
+
+    { Decompression processing parameters --- these fields must be set before
+      calling jpeg_start_decompress().  Note that jpeg_read_header()
+      initializes them to default values. }
+
+    out_color_space : J_COLOR_SPACE; { colorspace for output }
+
+    scale_num, scale_denom : uint ;  { fraction by which to scale image }
+
+    output_gamma : double;           { image gamma wanted in output }
+
+    buffered_image : boolean;        { TRUE=multiple output passes }
+    raw_data_out : boolean;          { TRUE=downsampled data wanted }
+
+    dct_method : J_DCT_METHOD;       { IDCT algorithm selector }
+    do_fancy_upsampling : boolean;   { TRUE=apply fancy upsampling }
+    do_block_smoothing : boolean;    { TRUE=apply interblock smoothing }
+
+    quantize_colors : boolean;       { TRUE=colormapped output wanted }
+    { the following are ignored if not quantize_colors: }
+    dither_mode : J_DITHER_MODE;     { type of color dithering to use }
+    two_pass_quantize : boolean;     { TRUE=use two-pass color quantization }
+    desired_number_of_colors : int;  { max # colors to use in created colormap }
+    { these are significant only in buffered-image mode: }
+    enable_1pass_quant : boolean;    { enable future use of 1-pass quantizer }
+    enable_external_quant : boolean; { enable future use of external colormap }
+    enable_2pass_quant : boolean;    { enable future use of 2-pass quantizer }
+
+    { Description of actual output image that will be returned to application.
+      These fields are computed by jpeg_start_decompress().
+      You can also use jpeg_calc_output_dimensions() to determine these values
+      in advance of calling jpeg_start_decompress(). }
+
+    output_width : JDIMENSION;       { scaled image width }
+    output_height: JDIMENSION;       { scaled image height }
+    out_color_components : int;  { # of color components in out_color_space }
+    output_components : int;     { # of color components returned }
+    { output_components is 1 (a colormap index) when quantizing colors;
+      otherwise it equals out_color_components. }
+
+    rec_outbuf_height : int;     { min recommended height of scanline buffer }
+    { If the buffer passed to jpeg_read_scanlines() is less than this many
+      rows high, space and time will be wasted due to unnecessary data
+      copying. Usually rec_outbuf_height will be 1 or 2, at most 4. }
+
+    { When quantizing colors, the output colormap is described by these
+      fields. The application can supply a colormap by setting colormap
+      non-NIL before calling jpeg_start_decompress; otherwise a colormap
+      is created during jpeg_start_decompress or jpeg_start_output. The map
+      has out_color_components rows and actual_number_of_colors columns. }
+
+    actual_number_of_colors : int;      { number of entries in use }
+    colormap : JSAMPARRAY;              { The color map as a 2-D pixel array }
+
+    { State variables: these variables indicate the progress of decompression.
+      The application may examine these but must not modify them. }
+
+    { Row index of next scanline to be read from jpeg_read_scanlines().
+      Application may use this to control its processing loop, e.g.,
+      "while (output_scanline < output_height)". }
+
+    output_scanline : JDIMENSION; { 0 .. output_height-1  }
+
+    { Current input scan number and number of iMCU rows completed in scan.
+      These indicate the progress of the decompressor input side. }
+
+    input_scan_number : int;      { Number of SOS markers seen so far }
+    input_iMCU_row : JDIMENSION;  { Number of iMCU rows completed }
+
+    { The "output scan number" is the notional scan being displayed by the
+      output side.  The decompressor will not allow output scan/row number
+      to get ahead of input scan/row, but it can fall arbitrarily far behind.}
+
+    output_scan_number : int;     { Nominal scan number being displayed }
+    output_iMCU_row : int;        { Number of iMCU rows read }
+
+    { Current progression status.  coef_bits[c][i] indicates the precision
+      with which component c's DCT coefficient i (in zigzag order) is known.
+      It is -1 when no data has yet been received, otherwise it is the point
+      transform (shift) value for the most recent scan of the coefficient
+      (thus, 0 at completion of the progression).
+      This pointer is NIL when reading a non-progressive file. }
+
+    coef_bits : coef_bits_ptrrow;
+                 { -1 or current Al value for each coef }
+
+    { Internal JPEG parameters --- the application usually need not look at
+      these fields.  Note that the decompressor output side may not use
+      any parameters that can change between scans. }
+
+    { Quantization and Huffman tables are carried forward across input
+      datastreams when processing abbreviated JPEG datastreams. }
+
+    quant_tbl_ptrs : Array[0..NUM_QUANT_TBLS-1] of JQUANT_TBL_PTR;
+    { ptrs to coefficient quantization tables, or NIL if not defined }
+
+    dc_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR;
+    ac_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR;
+    { ptrs to Huffman coding tables, or NIL if not defined }
+
+    { These parameters are never carried across datastreams, since they
+      are given in SOF/SOS markers or defined to be reset by SOI. }
+
+    data_precision : int;          { bits of precision in image data }
+
+    comp_info : jpeg_component_info_list_ptr;
+    { comp_info^[i] describes component that appears i'th in SOF }
+
+    progressive_mode : boolean;    { TRUE if SOFn specifies progressive mode }
+    arith_code : boolean;          { TRUE=arithmetic coding, FALSE=Huffman }
+
+    arith_dc_L : Array[0..NUM_ARITH_TBLS-1] of UINT8; { L values for DC arith-coding tables }
+    arith_dc_U : Array[0..NUM_ARITH_TBLS-1] of UINT8; { U values for DC arith-coding tables }
+    arith_ac_K : Array[0..NUM_ARITH_TBLS-1] of UINT8; { Kx values for AC arith-coding tables }
+
+    restart_interval : uint; { MCUs per restart interval, or 0 for no restart }
+
+    { These fields record data obtained from optional markers recognized by
+      the JPEG library. }
+
+    saw_JFIF_marker : boolean;  { TRUE iff a JFIF APP0 marker was found }
+    { Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: }
+    JFIF_major_version : UINT8; { JFIF version number }
+    JFIF_minor_version : UINT8;
+    density_unit : UINT8;       { JFIF code for pixel size units }
+    X_density : UINT16;         { Horizontal pixel density }
+    Y_density : UINT16;         { Vertical pixel density }
+    saw_Adobe_marker : boolean; { TRUE iff an Adobe APP14 marker was found }
+    Adobe_transform : UINT8;    { Color transform code from Adobe marker }
+
+    CCIR601_sampling : boolean; { TRUE=first samples are cosited }
+
+    { Aside from the specific data retained from APPn markers known to the
+      library, the uninterpreted contents of any or all APPn and COM markers
+      can be saved in a list for examination by the application. }
+
+    marker_list : jpeg_saved_marker_ptr; { Head of list of saved markers }
+
+    { Remaining fields are known throughout decompressor, but generally
+      should not be touched by a surrounding application. }
+
+
+    { These fields are computed during decompression startup }
+
+    max_h_samp_factor : int;    { largest h_samp_factor }
+    max_v_samp_factor : int;    { largest v_samp_factor }
+
+    min_DCT_scaled_size : int;  { smallest DCT_scaled_size of any component }
+
+    total_iMCU_rows : JDIMENSION; { # of iMCU rows in image }
+    { The coefficient controller's input and output progress is measured in
+      units of "iMCU" (interleaved MCU) rows.  These are the same as MCU rows
+      in fully interleaved JPEG scans, but are used whether the scan is
+      interleaved or not.  We define an iMCU row as v_samp_factor DCT block
+      rows of each component.  Therefore, the IDCT output contains
+      v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row.}
+
+    sample_range_limit : range_limit_table_ptr; { table for fast range-limiting }
+
+
+    { These fields are valid during any one scan.
+      They describe the components and MCUs actually appearing in the scan.
+      Note that the decompressor output side must not use these fields. }
+
+    comps_in_scan : int;           { # of JPEG components in this scan }
+    cur_comp_info : Array[0..MAX_COMPS_IN_SCAN-1] of jpeg_component_info_ptr;
+    { cur_comp_info[i]^ describes component that appears i'th in SOS }
+
+    MCUs_per_row : JDIMENSION;     { # of MCUs across the image }
+    MCU_rows_in_scan : JDIMENSION; { # of MCU rows in the image }
+
+    blocks_in_MCU : JDIMENSION;    { # of DCT blocks per MCU }
+    MCU_membership : Array[0..D_MAX_BLOCKS_IN_MCU-1] of int;
+    { MCU_membership[i] is index in cur_comp_info of component owning }
+    { i'th block in an MCU }
+
+    Ss, Se, Ah, Al : int;          { progressive JPEG parameters for scan }
+
+    { This field is shared between entropy decoder and marker parser.
+      It is either zero or the code of a JPEG marker that has been
+      read from the data source, but has not yet been processed. }
+
+    unread_marker : int;
+
+    { Links to decompression subobjects
+      (methods, private variables of modules) }
+
+    master : jpeg_decomp_master_ptr;
+    main : jpeg_d_main_controller_ptr;
+    coef : jpeg_d_coef_controller_ptr;
+    post : jpeg_d_post_controller_ptr;
+    inputctl : jpeg_input_controller_ptr;
+    marker : jpeg_marker_reader_ptr;
+    entropy : jpeg_entropy_decoder_ptr;
+    idct : jpeg_inverse_dct_ptr;
+    upsample : jpeg_upsampler_ptr;
+    cconvert : jpeg_color_deconverter_ptr;
+    cquantize : jpeg_color_quantizer_ptr;
+  end;
+
+{ Decompression startup: read start of JPEG datastream to see what's there
+   function jpeg_read_header (cinfo : j_decompress_ptr;
+                              require_image : boolean) : int;
+  Return value is one of: }
+const
+  JPEG_SUSPENDED              = 0; { Suspended due to lack of input data }
+  JPEG_HEADER_OK              = 1; { Found valid image datastream }
+  JPEG_HEADER_TABLES_ONLY     = 2; { Found valid table-specs-only datastream }
+{ If you pass require_image = TRUE (normal case), you need not check for
+  a TABLES_ONLY return code; an abbreviated file will cause an error exit.
+  JPEG_SUSPENDED is only possible if you use a data source module that can
+  give a suspension return (the stdio source module doesn't). }
+
+
+{ function jpeg_consume_input (cinfo : j_decompress_ptr) : int;
+  Return value is one of: }
+
+  JPEG_REACHED_SOS            = 1; { Reached start of new scan }
+  JPEG_REACHED_EOI            = 2; { Reached end of image }
+  JPEG_ROW_COMPLETED          = 3; { Completed one iMCU row }
+  JPEG_SCAN_COMPLETED         = 4; { Completed last iMCU row of a scan }
+
+
+
+
+implementation
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjquant1.pas b/src/lib/vampimg/JpegLib/imjquant1.pas
new file mode 100644 (file)
index 0000000..c5df360
--- /dev/null
@@ -0,0 +1,1009 @@
+unit imjquant1;
+
+{ This file contains 1-pass color quantization (color mapping) routines.
+  These routines provide mapping to a fixed color map using equally spaced
+  color values.  Optional Floyd-Steinberg or ordered dithering is available. }
+
+{ Original: jquant1.c; Copyright (C) 1991-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjpeglib;
+
+{GLOBAL}
+procedure jinit_1pass_quantizer (cinfo : j_decompress_ptr);
+
+implementation
+
+uses
+  imjmorecfg,
+  imjdeferr,
+  imjerror,
+  imjutils;
+
+{ The main purpose of 1-pass quantization is to provide a fast, if not very
+  high quality, colormapped output capability.  A 2-pass quantizer usually
+  gives better visual quality; however, for quantized grayscale output this
+  quantizer is perfectly adequate.  Dithering is highly recommended with this
+  quantizer, though you can turn it off if you really want to.
+
+  In 1-pass quantization the colormap must be chosen in advance of seeing the
+  image.  We use a map consisting of all combinations of Ncolors[i] color
+  values for the i'th component.  The Ncolors[] values are chosen so that
+  their product, the total number of colors, is no more than that requested.
+  (In most cases, the product will be somewhat less.)
+
+  Since the colormap is orthogonal, the representative value for each color
+  component can be determined without considering the other components;
+  then these indexes can be combined into a colormap index by a standard
+  N-dimensional-array-subscript calculation.  Most of the arithmetic involved
+  can be precalculated and stored in the lookup table colorindex[].
+  colorindex[i][j] maps pixel value j in component i to the nearest
+  representative value (grid plane) for that component; this index is
+  multiplied by the array stride for component i, so that the
+  index of the colormap entry closest to a given pixel value is just
+     sum( colorindex[component-number][pixel-component-value] )
+  Aside from being fast, this scheme allows for variable spacing between
+  representative values with no additional lookup cost.
+
+  If gamma correction has been applied in color conversion, it might be wise
+  to adjust the color grid spacing so that the representative colors are
+  equidistant in linear space.  At this writing, gamma correction is not
+  implemented by jdcolor, so nothing is done here. }
+
+
+{ Declarations for ordered dithering.
+
+  We use a standard 16x16 ordered dither array.  The basic concept of ordered
+  dithering is described in many references, for instance Dale Schumacher's
+  chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
+  In place of Schumacher's comparisons against a "threshold" value, we add a
+  "dither" value to the input pixel and then round the result to the nearest
+  output value.  The dither value is equivalent to (0.5 - threshold) times
+  the distance between output values.  For ordered dithering, we assume that
+  the output colors are equally spaced; if not, results will probably be
+  worse, since the dither may be too much or too little at a given point.
+
+  The normal calculation would be to form pixel value + dither, range-limit
+  this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
+  We can skip the separate range-limiting step by extending the colorindex
+  table in both directions. }
+
+
+const
+  ODITHER_SIZE  = 16;   { dimension of dither matrix }
+{ NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break }
+  ODITHER_CELLS = (ODITHER_SIZE*ODITHER_SIZE);  { # cells in matrix }
+  ODITHER_MASK = (ODITHER_SIZE-1); { mask for wrapping around counters }
+
+type
+  ODITHER_vector = Array[0..ODITHER_SIZE-1] of int;
+  ODITHER_MATRIX = Array[0..ODITHER_SIZE-1] of ODITHER_vector;
+  {ODITHER_MATRIX_PTR = ^array[0..ODITHER_SIZE-1] of int;}
+  ODITHER_MATRIX_PTR = ^ODITHER_MATRIX;
+
+const
+  base_dither_matrix : Array[0..ODITHER_SIZE-1,0..ODITHER_SIZE-1] of UINT8
+  = (
+  { Bayer's order-4 dither array.  Generated by the code given in
+    Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
+    The values in this array must range from 0 to ODITHER_CELLS-1. }
+
+  (   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 ),
+  ( 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 ),
+  (  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 ),
+  ( 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 ),
+  (   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 ),
+  ( 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 ),
+  (  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 ),
+  ( 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 ),
+  (   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 ),
+  ( 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 ),
+  (  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 ),
+  ( 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 ),
+  (  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 ),
+  ( 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 ),
+  (  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 ),
+  ( 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 )
+  );
+
+
+{ Declarations for Floyd-Steinberg dithering.
+
+  Errors are accumulated into the array fserrors[], at a resolution of
+  1/16th of a pixel count.  The error at a given pixel is propagated
+  to its not-yet-processed neighbors using the standard F-S fractions,
+    ... (here)  7/16
+    3/16  5/16  1/16
+  We work left-to-right on even rows, right-to-left on odd rows.
+
+  We can get away with a single array (holding one row's worth of errors)
+  by using it to store the current row's errors at pixel columns not yet
+  processed, but the next row's errors at columns already processed.  We
+  need only a few extra variables to hold the errors immediately around the
+  current column.  (If we are lucky, those variables are in registers, but
+  even if not, they're probably cheaper to access than array elements are.)
+
+  The fserrors[] array is indexed [component#][position].
+  We provide (#columns + 2) entries per component; the extra entry at each
+  end saves us from special-casing the first and last pixels.
+
+  Note: on a wide image, we might not have enough room in a PC's near data
+  segment to hold the error array; so it is allocated with alloc_large. }
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+type
+  FSERROR = INT16;              { 16 bits should be enough }
+  LOCFSERROR = int;             { use 'int' for calculation temps }
+{$else}
+type
+  FSERROR = INT32;              { may need more than 16 bits }
+  LOCFSERROR = INT32;           { be sure calculation temps are big enough }
+{$endif}
+
+type
+  jFSError = 0..(MaxInt div SIZEOF(FSERROR))-1;
+  FS_ERROR_FIELD = array[jFSError] of FSERROR;
+  FS_ERROR_FIELD_PTR = ^FS_ERROR_FIELD;{far}
+                                { pointer to error array (in FAR storage!) }
+  FSERRORPTR = ^FSERROR;
+
+
+{ Private subobject }
+
+const
+  MAX_Q_COMPS = 4;              { max components I can handle }
+
+type
+  my_cquantize_ptr = ^my_cquantizer;
+  my_cquantizer = record
+    pub : jpeg_color_quantizer; { public fields }
+
+    { Initially allocated colormap is saved here }
+    sv_colormap : JSAMPARRAY;   { The color map as a 2-D pixel array }
+    sv_actual : int;            { number of entries in use }
+
+    colorindex : JSAMPARRAY;    { Precomputed mapping for speed }
+    { colorindex[i][j] = index of color closest to pixel value j in component i,
+      premultiplied as described above.  Since colormap indexes must fit into
+      JSAMPLEs, the entries of this array will too. }
+
+    is_padded : boolean;        { is the colorindex padded for odither? }
+
+    Ncolors : array[0..MAX_Q_COMPS-1] of int;
+                                { # of values alloced to each component }
+
+    { Variables for ordered dithering }
+    row_index : int;            { cur row's vertical index in dither matrix }
+    odither : array[0..MAX_Q_COMPS-1] of ODITHER_MATRIX_PTR;
+                                { one dither array per component }
+    { Variables for Floyd-Steinberg dithering }
+    fserrors : array[0..MAX_Q_COMPS-1] of FS_ERROR_FIELD_PTR;
+                                { accumulated errors }
+    on_odd_row : boolean;       { flag to remember which row we are on }
+  end;
+
+
+{ Policy-making subroutines for create_colormap and create_colorindex.
+  These routines determine the colormap to be used.  The rest of the module
+  only assumes that the colormap is orthogonal.
+
+   * select_ncolors decides how to divvy up the available colors
+     among the components.
+   * output_value defines the set of representative values for a component.
+   * largest_input_value defines the mapping from input values to
+     representative values for a component.
+  Note that the latter two routines may impose different policies for
+  different components, though this is not currently done. }
+
+
+
+{LOCAL}
+function select_ncolors (cinfo : j_decompress_ptr;
+                         var Ncolors : array of int) : int;
+{ Determine allocation of desired colors to components, }
+{ and fill in Ncolors[] array to indicate choice. }
+{ Return value is total number of colors (product of Ncolors[] values). }
+var
+  nc : int;
+  max_colors : int;
+  total_colors, iroot, i, j : int;
+  changed : boolean;
+  temp : long;
+const
+  RGB_order:array[0..2] of int = (RGB_GREEN, RGB_RED, RGB_BLUE);
+begin
+  nc := cinfo^.out_color_components; { number of color components }
+  max_colors := cinfo^.desired_number_of_colors;
+
+  { We can allocate at least the nc'th root of max_colors per component. }
+  { Compute floor(nc'th root of max_colors). }
+  iroot := 1;
+  repeat
+    Inc(iroot);
+    temp := iroot;    { set temp = iroot ** nc }
+    for i := 1 to pred(nc) do
+      temp := temp * iroot;
+  until (temp > long(max_colors)); { repeat till iroot exceeds root }
+  Dec(iroot);                   { now iroot = floor(root) }
+
+  { Must have at least 2 color values per component }
+  if (iroot < 2) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_FEW_COLORS, int(temp));
+
+  { Initialize to iroot color values for each component }
+  total_colors := 1;
+  for i := 0 to pred(nc) do
+  begin
+    Ncolors[i] := iroot;
+    total_colors := total_colors * iroot;
+  end;
+
+  { We may be able to increment the count for one or more components without
+    exceeding max_colors, though we know not all can be incremented.
+    Sometimes, the first component can be incremented more than once!
+    (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
+    In RGB colorspace, try to increment G first, then R, then B. }
+
+  repeat
+    changed := FALSE;
+    for i := 0 to pred(nc) do
+    begin
+      if cinfo^.out_color_space = JCS_RGB then
+        j := RGB_order[i]
+      else
+        j := i;
+      { calculate new total_colors if Ncolors[j] is incremented }
+      temp := total_colors div Ncolors[j];
+      temp := temp * (Ncolors[j]+1);   { done in long arith to avoid oflo }
+      if (temp > long(max_colors)) then
+  break;                  { won't fit, done with this pass }
+      Inc(Ncolors[j]);    { OK, apply the increment }
+      total_colors := int(temp);
+      changed := TRUE;
+    end;
+  until not changed;
+
+  select_ncolors := total_colors;
+end;
+
+
+{LOCAL}
+function output_value (cinfo : j_decompress_ptr;
+                       ci : int; j : int; maxj : int) : int;
+{ Return j'th output value, where j will range from 0 to maxj }
+{ The output values must fall in 0..MAXJSAMPLE in increasing order }
+begin
+  { We always provide values 0 and MAXJSAMPLE for each component;
+    any additional values are equally spaced between these limits.
+    (Forcing the upper and lower values to the limits ensures that
+    dithering can't produce a color outside the selected gamut.) }
+
+  output_value := int (( INT32(j) * MAXJSAMPLE + maxj div 2) div maxj);
+end;
+
+
+{LOCAL}
+function largest_input_value (cinfo : j_decompress_ptr;
+                              ci : int; j : int; maxj : int) : int;
+{ Return largest input value that should map to j'th output value }
+{ Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE }
+begin
+  { Breakpoints are halfway between values returned by output_value }
+  largest_input_value := int (( INT32(2*j + 1) * MAXJSAMPLE +
+                                 maxj) div (2*maxj));
+end;
+
+
+{ Create the colormap. }
+
+{LOCAL}
+procedure create_colormap (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+  colormap : JSAMPARRAY;        { Created colormap }
+
+  total_colors : int;           { Number of distinct output colors }
+  i,j,k, nci, blksize, blkdist, ptr, val : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+
+  { Select number of colors for each component }
+  total_colors := select_ncolors(cinfo, cquantize^.Ncolors);
+
+  { Report selected color counts }
+  {$IFDEF DEBUG}
+  if (cinfo^.out_color_components = 3) then
+    TRACEMS4(j_common_ptr(cinfo), 1, JTRC_QUANT_3_NCOLORS,
+       total_colors, cquantize^.Ncolors[0],
+       cquantize^.Ncolors[1], cquantize^.Ncolors[2])
+  else
+    TRACEMS1(j_common_ptr(cinfo), 1, JTRC_QUANT_NCOLORS, total_colors);
+  {$ENDIF}
+
+  { Allocate and fill in the colormap. }
+  { The colors are ordered in the map in standard row-major order, }
+  { i.e. rightmost (highest-indexed) color changes most rapidly. }
+
+  colormap := cinfo^.mem^.alloc_sarray(
+     j_common_ptr(cinfo), JPOOL_IMAGE,
+     JDIMENSION(total_colors), JDIMENSION(cinfo^.out_color_components));
+
+  { blksize is number of adjacent repeated entries for a component }
+  { blkdist is distance between groups of identical entries for a component }
+  blkdist := total_colors;
+
+  for i := 0 to pred(cinfo^.out_color_components) do
+  begin
+    { fill in colormap entries for i'th color component }
+    nci := cquantize^.Ncolors[i]; { # of distinct values for this color }
+    blksize := blkdist div nci;
+    for j := 0 to pred(nci) do
+    begin
+      { Compute j'th output value (out of nci) for component }
+      val := output_value(cinfo, i, j, nci-1);
+      { Fill in all colormap entries that have this value of this component }
+      ptr := j * blksize;
+      while (ptr < total_colors) do
+      begin
+  { fill in blksize entries beginning at ptr }
+  for k := 0 to pred(blksize) do
+          colormap^[i]^[ptr+k] := JSAMPLE(val);
+
+        Inc(ptr, blkdist);
+      end;
+    end;
+    blkdist := blksize;   { blksize of this color is blkdist of next }
+  end;
+
+  { Save the colormap in private storage,
+    where it will survive color quantization mode changes. }
+
+  cquantize^.sv_colormap := colormap;
+  cquantize^.sv_actual := total_colors;
+end;
+
+{ Create the color index table. }
+
+{LOCAL}
+procedure create_colorindex (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+  indexptr,
+  help_indexptr : JSAMPROW;  { for negative offsets }
+  i,j,k, nci, blksize, val, pad : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  { For ordered dither, we pad the color index tables by MAXJSAMPLE in
+    each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
+    This is not necessary in the other dithering modes.  However, we
+    flag whether it was done in case user changes dithering mode. }
+
+  if (cinfo^.dither_mode = JDITHER_ORDERED) then
+  begin
+    pad := MAXJSAMPLE*2;
+    cquantize^.is_padded := TRUE;
+  end
+  else
+  begin
+    pad := 0;
+    cquantize^.is_padded := FALSE;
+  end;
+
+  cquantize^.colorindex := cinfo^.mem^.alloc_sarray
+    (j_common_ptr(cinfo), JPOOL_IMAGE,
+     JDIMENSION(MAXJSAMPLE+1 + pad),
+     JDIMENSION(cinfo^.out_color_components));
+
+  { blksize is number of adjacent repeated entries for a component }
+  blksize := cquantize^.sv_actual;
+
+  for i := 0 to pred(cinfo^.out_color_components) do
+  begin
+    { fill in colorindex entries for i'th color component }
+    nci := cquantize^.Ncolors[i]; { # of distinct values for this color }
+    blksize := blksize div nci;
+
+    { adjust colorindex pointers to provide padding at negative indexes. }
+    if (pad <> 0) then
+      Inc(JSAMPLE_PTR(cquantize^.colorindex^[i]), MAXJSAMPLE);
+
+    { in loop, val = index of current output value, }
+    { and k = largest j that maps to current val }
+    indexptr := cquantize^.colorindex^[i];
+    val := 0;
+    k := largest_input_value(cinfo, i, 0, nci-1);
+    for j := 0 to MAXJSAMPLE do
+    begin
+      while (j > k) do          { advance val if past boundary }
+      begin
+        Inc(val);
+  k := largest_input_value(cinfo, i, val, nci-1);
+      end;
+      { premultiply so that no multiplication needed in main processing }
+      indexptr^[j] := JSAMPLE (val * blksize);
+    end;
+    { Pad at both ends if necessary }
+    if (pad <> 0) then
+    begin
+      help_indexptr := indexptr;
+      { adjust the help pointer to avoid negative offsets }
+      Dec(JSAMPLE_PTR(help_indexptr), MAXJSAMPLE);
+
+      for j := 1 to MAXJSAMPLE do
+      begin
+        {indexptr^[-j] := indexptr^[0];}
+        help_indexptr^[MAXJSAMPLE-j] := indexptr^[0];
+        indexptr^[MAXJSAMPLE+j] := indexptr^[MAXJSAMPLE];
+      end;
+    end;
+  end;
+end;
+
+
+{ Create an ordered-dither array for a component having ncolors
+  distinct output values. }
+
+{LOCAL}
+function make_odither_array (cinfo : j_decompress_ptr;
+                             ncolors : int) : ODITHER_MATRIX_PTR;
+var
+  odither : ODITHER_MATRIX_PTR;
+  j, k : int;
+  num, den : INT32;
+begin
+  odither := ODITHER_MATRIX_PTR (
+        cinfo^.mem^.alloc_small(j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(ODITHER_MATRIX)));
+  { The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
+    Hence the dither value for the matrix cell with fill order f
+    (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
+    On 16-bit-int machine, be careful to avoid overflow. }
+
+  den := 2 * ODITHER_CELLS * ( INT32(ncolors - 1));
+  for j := 0 to pred(ODITHER_SIZE) do
+  begin
+    for k := 0 to pred(ODITHER_SIZE) do
+    begin
+      num := ( INT32(ODITHER_CELLS-1 - 2*( int(base_dither_matrix[j][k]))))
+      * MAXJSAMPLE;
+      { Ensure round towards zero despite C's lack of consistency
+        about rounding negative values in integer division... }
+
+      if num<0 then
+        odither^[j][k] := int (-((-num) div den))
+      else
+        odither^[j][k] := int (num div den);
+    end;
+  end;
+  make_odither_array := odither;
+end;
+
+
+{ Create the ordered-dither tables.
+  Components having the same number of representative colors may
+  share a dither table. }
+
+{LOCAL}
+procedure create_odither_tables (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+  odither : ODITHER_MATRIX_PTR;
+  i, j, nci : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+
+  for i := 0 to pred(cinfo^.out_color_components) do
+  begin
+    nci := cquantize^.Ncolors[i]; { # of distinct values for this color }
+    odither := NIL;     { search for matching prior component }
+    for j := 0 to pred(i) do
+    begin
+      if (nci = cquantize^.Ncolors[j]) then
+      begin
+  odither := cquantize^.odither[j];
+  break;
+      end;
+    end;
+    if (odither = NIL)  then { need a new table? }
+      odither := make_odither_array(cinfo, nci);
+    cquantize^.odither[i] := odither;
+  end;
+end;
+
+
+{ Map some rows of pixels to the output colormapped representation. }
+
+{METHODDEF}
+procedure color_quantize (cinfo : j_decompress_ptr;
+                          input_buf : JSAMPARRAY;
+              output_buf : JSAMPARRAY;
+                          num_rows : int);
+{ General case, no dithering }
+var
+  cquantize : my_cquantize_ptr;
+  colorindex : JSAMPARRAY;
+  pixcode, ci : int; {register}
+  ptrin, ptrout : JSAMPLE_PTR; {register}
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+  nc : int; {register}
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  colorindex := cquantize^.colorindex;
+  width := cinfo^.output_width;
+  nc := cinfo^.out_color_components;
+
+  for row := 0 to pred(num_rows) do
+  begin
+    ptrin := JSAMPLE_PTR(input_buf^[row]);
+    ptrout := JSAMPLE_PTR(output_buf^[row]);
+    for col := pred(width) downto 0 do
+    begin
+      pixcode := 0;
+      for ci := 0 to pred(nc) do
+      begin
+  Inc(pixcode, GETJSAMPLE(colorindex^[ci]^[GETJSAMPLE(ptrin^)]) );
+        Inc(ptrin);
+      end;
+      ptrout^ := JSAMPLE (pixcode);
+      Inc(ptrout);
+    end;
+  end;
+end;
+
+
+{METHODDEF}
+procedure color_quantize3 (cinfo : j_decompress_ptr;
+                           input_buf : JSAMPARRAY;
+               output_buf : JSAMPARRAY;
+                           num_rows : int);
+{ Fast path for out_color_components=3, no dithering }
+var
+  cquantize : my_cquantize_ptr;
+  pixcode : int; {register}
+  ptrin, ptrout : JSAMPLE_PTR; {register}
+  colorindex0 : JSAMPROW;
+  colorindex1 : JSAMPROW;
+  colorindex2 : JSAMPROW;
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  colorindex0 := (cquantize^.colorindex)^[0];
+  colorindex1 := (cquantize^.colorindex)^[1];
+  colorindex2 := (cquantize^.colorindex)^[2];
+  width := cinfo^.output_width;
+
+  for row := 0 to pred(num_rows) do
+  begin
+    ptrin := JSAMPLE_PTR(input_buf^[row]);
+    ptrout := JSAMPLE_PTR(output_buf^[row]);
+    for col := pred(width) downto 0 do
+    begin
+      pixcode  := GETJSAMPLE((colorindex0)^[GETJSAMPLE(ptrin^)]);
+      Inc(ptrin);
+      Inc( pixcode, GETJSAMPLE((colorindex1)^[GETJSAMPLE(ptrin^)]) );
+      Inc(ptrin);
+      Inc( pixcode, GETJSAMPLE((colorindex2)^[GETJSAMPLE(ptrin^)]) );
+      Inc(ptrin);
+      ptrout^ := JSAMPLE (pixcode);
+      Inc(ptrout);
+    end;
+  end;
+end;
+
+
+{METHODDEF}
+procedure quantize_ord_dither (cinfo : j_decompress_ptr;
+                               input_buf :  JSAMPARRAY;
+                   output_buf : JSAMPARRAY;
+                               num_rows : int);
+{ General case, with ordered dithering }
+var
+  cquantize : my_cquantize_ptr;
+  input_ptr,                {register}
+  output_ptr : JSAMPLE_PTR; {register}
+  colorindex_ci : JSAMPROW;
+  dither : ^ODITHER_vector;     { points to active row of dither matrix }
+  row_index, col_index : int;   { current indexes into dither matrix }
+  nc : int;
+  ci : int;
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+var
+  pad_offset : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  nc := cinfo^.out_color_components;
+  width := cinfo^.output_width;
+
+  { Nomssi: work around negative offset }
+  if my_cquantize_ptr (cinfo^.cquantize)^.is_padded then
+    pad_offset := MAXJSAMPLE
+  else
+    pad_offset := 0;
+
+  for row := 0 to pred(num_rows) do
+  begin
+    { Initialize output values to 0 so can process components separately }
+    jzero_far( {far} pointer(output_buf^[row]),
+        size_t(width * SIZEOF(JSAMPLE)));
+    row_index := cquantize^.row_index;
+    for ci := 0 to pred(nc) do
+    begin
+      input_ptr := JSAMPLE_PTR(@ input_buf^[row]^[ci]);
+      output_ptr := JSAMPLE_PTR(output_buf^[row]);
+      colorindex_ci := cquantize^.colorindex^[ci];
+      { Nomssi }
+      Dec(JSAMPLE_PTR(colorindex_ci), pad_offset);
+
+      dither := @(cquantize^.odither[ci]^[row_index]);
+      col_index := 0;
+
+      for col := pred(width) downto 0 do
+      begin
+  { Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
+    select output value, accumulate into output code for this pixel.
+    Range-limiting need not be done explicitly, as we have extended
+    the colorindex table to produce the right answers for out-of-range
+    inputs.  The maximum dither is +- MAXJSAMPLE; this sets the
+    required amount of padding. }
+
+  Inc(output_ptr^,
+            colorindex_ci^[GETJSAMPLE(input_ptr^)+ pad_offset +
+                                         dither^[col_index]]);
+        Inc(output_ptr);
+  Inc(input_ptr, nc);
+  col_index := (col_index + 1) and ODITHER_MASK;
+      end;
+    end;
+    { Advance row index for next row }
+    row_index := (row_index + 1) and ODITHER_MASK;
+    cquantize^.row_index := row_index;
+  end;
+end;
+
+{METHODDEF}
+procedure quantize3_ord_dither (cinfo : j_decompress_ptr;
+                                input_buf : JSAMPARRAY;
+                    output_buf : JSAMPARRAY;
+                                num_rows : int);
+{ Fast path for out_color_components=3, with ordered dithering }
+var
+  cquantize : my_cquantize_ptr;
+  pixcode : int; {register}
+  input_ptr : JSAMPLE_PTR; {register}
+  output_ptr : JSAMPLE_PTR; {register}
+  colorindex0 : JSAMPROW;
+  colorindex1 : JSAMPROW;
+  colorindex2 : JSAMPROW;
+  dither0 : ^ODITHER_vector;    { points to active row of dither matrix }
+  dither1 : ^ODITHER_vector;
+  dither2 : ^ODITHER_vector;
+  row_index, col_index : int;   { current indexes into dither matrix }
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+var
+  pad_offset : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  colorindex0 := (cquantize^.colorindex)^[0];
+  colorindex1 := (cquantize^.colorindex)^[1];
+  colorindex2 := (cquantize^.colorindex)^[2];
+  width := cinfo^.output_width;
+
+  { Nomssi: work around negative offset }
+  if my_cquantize_ptr (cinfo^.cquantize)^.is_padded then
+    pad_offset := MAXJSAMPLE
+  else
+    pad_offset := 0;
+
+  Dec(JSAMPLE_PTR(colorindex0), pad_offset);
+  Dec(JSAMPLE_PTR(colorindex1), pad_offset);
+  Dec(JSAMPLE_PTR(colorindex2), pad_offset);
+
+  for row := 0 to pred(num_rows) do
+  begin
+    row_index := cquantize^.row_index;
+    input_ptr := JSAMPLE_PTR(input_buf^[row]);
+    output_ptr := JSAMPLE_PTR(output_buf^[row]);
+    dither0 := @(cquantize^.odither[0]^[row_index]);
+    dither1 := @(cquantize^.odither[1]^[row_index]);
+    dither2 := @(cquantize^.odither[2]^[row_index]);
+    col_index := 0;
+
+
+    for col := pred(width) downto 0 do
+    begin
+      pixcode := GETJSAMPLE(colorindex0^[GETJSAMPLE(input_ptr^) + pad_offset
+                                         + dither0^[col_index]]);
+      Inc(input_ptr);
+      Inc(pixcode, GETJSAMPLE(colorindex1^[GETJSAMPLE(input_ptr^) + pad_offset
+                                           + dither1^[col_index]]));
+      Inc(input_ptr);
+      Inc(pixcode, GETJSAMPLE(colorindex2^[GETJSAMPLE(input_ptr^) + pad_offset
+                                           + dither2^[col_index]]));
+      Inc(input_ptr);
+      output_ptr^ := JSAMPLE (pixcode);
+      Inc(output_ptr);
+      col_index := (col_index + 1) and ODITHER_MASK;
+    end;
+    row_index := (row_index + 1) and ODITHER_MASK;
+    cquantize^.row_index := row_index;
+  end;
+end;
+
+
+{METHODDEF}
+procedure quantize_fs_dither (cinfo : j_decompress_ptr;
+                              input_buf : JSAMPARRAY;
+                  output_buf : JSAMPARRAY;
+                              num_rows : int);
+{ General case, with Floyd-Steinberg dithering }
+var
+  cquantize : my_cquantize_ptr;
+  cur : LOCFSERROR; {register}  { current error or pixel value }
+  belowerr : LOCFSERROR;        { error for pixel below cur }
+  bpreverr : LOCFSERROR;        { error for below/prev col }
+  bnexterr : LOCFSERROR;        { error for below/next col }
+  delta : LOCFSERROR;
+  prev_errorptr,
+  errorptr : FSERRORPTR; {register} { => fserrors[] at column before current }
+  input_ptr,                {register}
+  output_ptr : JSAMPLE_PTR; {register}
+  colorindex_ci : JSAMPROW;
+  colormap_ci : JSAMPROW;
+  pixcode : int;
+  nc : int;
+  dir : int;      { 1 for left-to-right, -1 for right-to-left }
+  dirnc : int;      { dir * nc }
+  ci : int;
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+  range_limit : range_limit_table_ptr;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  nc := cinfo^.out_color_components;
+  width := cinfo^.output_width;
+  range_limit := cinfo^.sample_range_limit;
+
+  for row := 0 to pred(num_rows) do
+  begin
+    { Initialize output values to 0 so can process components separately }
+    jzero_far( (output_buf)^[row],
+               size_t(width * SIZEOF(JSAMPLE)));
+    for ci := 0 to pred(nc) do
+    begin
+      input_ptr := JSAMPLE_PTR(@ input_buf^[row]^[ci]);
+      output_ptr := JSAMPLE_PTR(output_buf^[row]);
+      errorptr := FSERRORPTR(cquantize^.fserrors[ci]); { => entry before first column }
+      if (cquantize^.on_odd_row) then
+      begin
+  { work right to left in this row }
+  Inc(input_ptr, (width-1) * JDIMENSION(nc)); { so point to rightmost pixel }
+  Inc(output_ptr, width-1);
+  dir := -1;
+  dirnc := -nc;
+  Inc(errorptr, (width+1)); { => entry after last column }
+      end
+      else
+      begin
+  { work left to right in this row }
+  dir := 1;
+  dirnc := nc;
+        {errorptr := cquantize^.fserrors[ci];}
+      end;
+
+      colorindex_ci := cquantize^.colorindex^[ci];
+
+      colormap_ci := (cquantize^.sv_colormap)^[ci];
+      { Preset error values: no error propagated to first pixel from left }
+      cur := 0;
+      { and no error propagated to row below yet }
+      belowerr := 0;
+      bpreverr := 0;
+
+      for col := pred(width) downto 0 do
+      begin
+        prev_errorptr := errorptr;
+  Inc(errorptr, dir);  { advance errorptr to current column }
+
+  { cur holds the error propagated from the previous pixel on the
+    current line.  Add the error propagated from the previous line
+    to form the complete error correction term for this pixel, and
+    round the error term (which is expressed * 16) to an integer.
+    RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+    for either sign of the error value.
+    Note: errorptr points to *previous* column's array entry. }
+
+        cur := (cur + errorptr^ + 8) div 16;
+
+  { Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+    The maximum error is +- MAXJSAMPLE; this sets the required size
+    of the range_limit array. }
+
+  Inc( cur, GETJSAMPLE(input_ptr^));
+  cur := GETJSAMPLE(range_limit^[cur]);
+  { Select output value, accumulate into output code for this pixel }
+  pixcode := GETJSAMPLE(colorindex_ci^[cur]);
+  Inc(output_ptr^, JSAMPLE (pixcode));
+  { Compute actual representation error at this pixel }
+  { Note: we can do this even though we don't have the final }
+  { pixel code, because the colormap is orthogonal. }
+  Dec(cur, GETJSAMPLE(colormap_ci^[pixcode]));
+  { Compute error fractions to be propagated to adjacent pixels.
+    Add these into the running sums, and simultaneously shift the
+    next-line error sums left by 1 column. }
+
+  bnexterr := cur;
+  delta := cur * 2;
+  Inc(cur, delta);        { form error * 3 }
+  prev_errorptr^ := FSERROR (bpreverr + cur);
+  Inc(cur, delta);        { form error * 5 }
+  bpreverr := belowerr + cur;
+  belowerr := bnexterr;
+  Inc(cur, delta);        { form error * 7 }
+  { At this point cur contains the 7/16 error value to be propagated
+    to the next pixel on the current line, and all the errors for the
+    next line have been shifted over. We are therefore ready to move on. }
+
+  Inc(input_ptr, dirnc);  { advance input ptr to next column }
+  Inc(output_ptr, dir);   { advance output ptr to next column }
+
+      end;
+      { Post-loop cleanup: we must unload the final error value into the
+        final fserrors[] entry.  Note we need not unload belowerr because
+        it is for the dummy column before or after the actual array. }
+
+      errorptr^ := FSERROR (bpreverr); { unload prev err into array }
+      { Nomssi : ?? }
+    end;
+    cquantize^.on_odd_row := not cquantize^.on_odd_row;
+  end;
+end;
+
+
+{ Allocate workspace for Floyd-Steinberg errors. }
+
+{LOCAL}
+procedure alloc_fs_workspace (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+  arraysize : size_t;
+  i : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  arraysize := size_t ((cinfo^.output_width + 2) * SIZEOF(FSERROR));
+  for i := 0 to pred(cinfo^.out_color_components) do
+  begin
+    cquantize^.fserrors[i] := FS_ERROR_FIELD_PTR(
+      cinfo^.mem^.alloc_large(j_common_ptr(cinfo), JPOOL_IMAGE, arraysize));
+  end;
+end;
+
+
+{ Initialize for one-pass color quantization. }
+
+{METHODDEF}
+procedure start_pass_1_quant (cinfo : j_decompress_ptr;
+                              is_pre_scan : boolean);
+var
+  cquantize : my_cquantize_ptr;
+  arraysize : size_t;
+  i : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  { Install my colormap. }
+  cinfo^.colormap := cquantize^.sv_colormap;
+  cinfo^.actual_number_of_colors := cquantize^.sv_actual;
+
+  { Initialize for desired dithering mode. }
+  case (cinfo^.dither_mode) of
+  JDITHER_NONE:
+    if (cinfo^.out_color_components = 3) then
+      cquantize^.pub.color_quantize := color_quantize3
+    else
+      cquantize^.pub.color_quantize := color_quantize;
+  JDITHER_ORDERED:
+    begin
+      if (cinfo^.out_color_components = 3) then
+        cquantize^.pub.color_quantize := quantize3_ord_dither
+      else
+        cquantize^.pub.color_quantize := quantize_ord_dither;
+      cquantize^.row_index := 0;    { initialize state for ordered dither }
+      { If user changed to ordered dither from another mode,
+        we must recreate the color index table with padding.
+        This will cost extra space, but probably isn't very likely. }
+
+      if (not cquantize^.is_padded) then
+        create_colorindex(cinfo);
+      { Create ordered-dither tables if we didn't already. }
+      if (cquantize^.odither[0] = NIL) then
+        create_odither_tables(cinfo);
+    end;
+  JDITHER_FS:
+    begin
+      cquantize^.pub.color_quantize := quantize_fs_dither;
+      cquantize^.on_odd_row := FALSE; { initialize state for F-S dither }
+      { Allocate Floyd-Steinberg workspace if didn't already. }
+      if (cquantize^.fserrors[0] = NIL) then
+        alloc_fs_workspace(cinfo);
+      { Initialize the propagated errors to zero. }
+      arraysize := size_t ((cinfo^.output_width + 2) * SIZEOF(FSERROR));
+      for i := 0 to pred(cinfo^.out_color_components) do
+        jzero_far({far} pointer( cquantize^.fserrors[i] ), arraysize);
+    end;
+  else
+    ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED);
+  end;
+end;
+
+
+{ Finish up at the end of the pass. }
+
+{METHODDEF}
+procedure finish_pass_1_quant (cinfo : j_decompress_ptr);
+begin
+  { no work in 1-pass case }
+end;
+
+
+{ Switch to a new external colormap between output passes.
+  Shouldn't get to this module! }
+
+{METHODDEF}
+procedure new_color_map_1_quant (cinfo : j_decompress_ptr);
+begin
+  ERREXIT(j_common_ptr(cinfo), JERR_MODE_CHANGE);
+end;
+
+
+{ Module initialization routine for 1-pass color quantization. }
+
+{GLOBAL}
+procedure jinit_1pass_quantizer (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+begin
+  cquantize := my_cquantize_ptr(
+     cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_cquantizer)));
+  cinfo^.cquantize := jpeg_color_quantizer_ptr(cquantize);
+  cquantize^.pub.start_pass := start_pass_1_quant;
+  cquantize^.pub.finish_pass := finish_pass_1_quant;
+  cquantize^.pub.new_color_map := new_color_map_1_quant;
+  cquantize^.fserrors[0] := NIL; { Flag FS workspace not allocated }
+  cquantize^.odither[0] := NIL; { Also flag odither arrays not allocated }
+
+  { Make sure my internal arrays won't overflow }
+  if (cinfo^.out_color_components > MAX_Q_COMPS) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
+  { Make sure colormap indexes can be represented by JSAMPLEs }
+  if (cinfo^.desired_number_of_colors > (MAXJSAMPLE+1)) then
+    ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);
+
+  { Create the colormap and color index table. }
+  create_colormap(cinfo);
+  create_colorindex(cinfo);
+
+  { Allocate Floyd-Steinberg workspace now if requested.
+    We do this now since it is FAR storage and may affect the memory
+    manager's space calculations.  If the user changes to FS dither
+    mode in a later pass, we will allocate the space then, and will
+    possibly overrun the max_memory_to_use setting. }
+
+  if (cinfo^.dither_mode = JDITHER_FS) then
+    alloc_fs_workspace(cinfo);
+end;
+
+
+end.
diff --git a/src/lib/vampimg/JpegLib/imjquant2.pas b/src/lib/vampimg/JpegLib/imjquant2.pas
new file mode 100644 (file)
index 0000000..5d4e4dc
--- /dev/null
@@ -0,0 +1,1551 @@
+unit imjquant2;
+
+
+{ This file contains 2-pass color quantization (color mapping) routines.
+  These routines provide selection of a custom color map for an image,
+  followed by mapping of the image to that color map, with optional
+  Floyd-Steinberg dithering.
+  It is also possible to use just the second pass to map to an arbitrary
+  externally-given color map.
+
+  Note: ordered dithering is not supported, since there isn't any fast
+  way to compute intercolor distances; it's unclear that ordered dither's
+  fundamental assumptions even hold with an irregularly spaced color map. }
+
+{ Original: jquant2.c; Copyright (C) 1991-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjdeferr,
+  imjerror,
+  imjutils,
+  imjpeglib;
+
+{ Module initialization routine for 2-pass color quantization. }
+
+
+{GLOBAL}
+procedure jinit_2pass_quantizer (cinfo : j_decompress_ptr);
+
+implementation
+
+{ This module implements the well-known Heckbert paradigm for color
+  quantization.  Most of the ideas used here can be traced back to
+  Heckbert's seminal paper
+    Heckbert, Paul.  "Color Image Quantization for Frame Buffer Display",
+    Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304.
+
+  In the first pass over the image, we accumulate a histogram showing the
+  usage count of each possible color.  To keep the histogram to a reasonable
+  size, we reduce the precision of the input; typical practice is to retain
+  5 or 6 bits per color, so that 8 or 4 different input values are counted
+  in the same histogram cell.
+
+  Next, the color-selection step begins with a box representing the whole
+  color space, and repeatedly splits the "largest" remaining box until we
+  have as many boxes as desired colors.  Then the mean color in each
+  remaining box becomes one of the possible output colors.
+
+  The second pass over the image maps each input pixel to the closest output
+  color (optionally after applying a Floyd-Steinberg dithering correction).
+  This mapping is logically trivial, but making it go fast enough requires
+  considerable care.
+
+  Heckbert-style quantizers vary a good deal in their policies for choosing
+  the "largest" box and deciding where to cut it.  The particular policies
+  used here have proved out well in experimental comparisons, but better ones
+  may yet be found.
+
+  In earlier versions of the IJG code, this module quantized in YCbCr color
+  space, processing the raw upsampled data without a color conversion step.
+  This allowed the color conversion math to be done only once per colormap
+  entry, not once per pixel.  However, that optimization precluded other
+  useful optimizations (such as merging color conversion with upsampling)
+  and it also interfered with desired capabilities such as quantizing to an
+  externally-supplied colormap.  We have therefore abandoned that approach.
+  The present code works in the post-conversion color space, typically RGB.
+
+  To improve the visual quality of the results, we actually work in scaled
+  RGB space, giving G distances more weight than R, and R in turn more than
+  B.  To do everything in integer math, we must use integer scale factors.
+  The 2/3/1 scale factors used here correspond loosely to the relative
+  weights of the colors in the NTSC grayscale equation.
+  If you want to use this code to quantize a non-RGB color space, you'll
+  probably need to change these scale factors. }
+
+const
+  R_SCALE = 2;          { scale R distances by this much }
+  G_SCALE = 3;          { scale G distances by this much }
+  B_SCALE = 1;          { and B by this much }
+
+{ Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined
+  in jmorecfg.h.  As the code stands, it will do the right thing for R,G,B
+  and B,G,R orders.  If you define some other weird order in jmorecfg.h,
+  you'll get compile errors until you extend this logic.  In that case
+  you'll probably want to tweak the histogram sizes too. }
+
+{$ifdef RGB_RED_IS_0}
+const
+  C0_SCALE = R_SCALE;
+  C1_SCALE = G_SCALE;
+  C2_SCALE = B_SCALE;
+{$else}
+const
+  C0_SCALE = B_SCALE;
+  C1_SCALE = G_SCALE;
+  C2_SCALE = R_SCALE;
+{$endif}
+
+
+{ First we have the histogram data structure and routines for creating it.
+
+  The number of bits of precision can be adjusted by changing these symbols.
+  We recommend keeping 6 bits for G and 5 each for R and B.
+  If you have plenty of memory and cycles, 6 bits all around gives marginally
+  better results; if you are short of memory, 5 bits all around will save
+  some space but degrade the results.
+  To maintain a fully accurate histogram, we'd need to allocate a "long"
+  (preferably unsigned long) for each cell.  In practice this is overkill;
+  we can get by with 16 bits per cell.  Few of the cell counts will overflow,
+  and clamping those that do overflow to the maximum value will give close-
+  enough results.  This reduces the recommended histogram size from 256Kb
+  to 128Kb, which is a useful savings on PC-class machines.
+  (In the second pass the histogram space is re-used for pixel mapping data;
+  in that capacity, each cell must be able to store zero to the number of
+  desired colors.  16 bits/cell is plenty for that too.)
+  Since the JPEG code is intended to run in small memory model on 80x86
+  machines, we can't just allocate the histogram in one chunk.  Instead
+  of a true 3-D array, we use a row of pointers to 2-D arrays.  Each
+  pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and
+  each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries.  Note that
+  on 80x86 machines, the pointer row is in near memory but the actual
+  arrays are in far memory (same arrangement as we use for image arrays). }
+
+
+const
+  MAXNUMCOLORS = (MAXJSAMPLE+1);        { maximum size of colormap }
+
+{ These will do the right thing for either R,G,B or B,G,R color order,
+  but you may not like the results for other color orders. }
+
+const
+  HIST_C0_BITS = 5;             { bits of precision in R/B histogram }
+  HIST_C1_BITS = 6;             { bits of precision in G histogram }
+  HIST_C2_BITS = 5;             { bits of precision in B/R histogram }
+
+{ Number of elements along histogram axes. }
+const
+  HIST_C0_ELEMS = (1 shl HIST_C0_BITS);
+  HIST_C1_ELEMS = (1 shl HIST_C1_BITS);
+  HIST_C2_ELEMS = (1 shl HIST_C2_BITS);
+
+{ These are the amounts to shift an input value to get a histogram index. }
+const
+  C0_SHIFT = (BITS_IN_JSAMPLE-HIST_C0_BITS);
+  C1_SHIFT = (BITS_IN_JSAMPLE-HIST_C1_BITS);
+  C2_SHIFT = (BITS_IN_JSAMPLE-HIST_C2_BITS);
+
+
+type                            { Nomssi }
+  RGBptr = ^RGBtype;
+  RGBtype = packed record
+    r,g,b : JSAMPLE;
+  end;
+type
+  histcell = UINT16;            { histogram cell; prefer an unsigned type }
+
+type
+  histptr = ^histcell {FAR};       { for pointers to histogram cells }
+
+type
+  hist1d = array[0..HIST_C2_ELEMS-1] of histcell; { typedefs for the array }
+  {hist1d_ptr = ^hist1d;}
+  hist1d_field = array[0..HIST_C1_ELEMS-1] of hist1d;
+                                  { type for the 2nd-level pointers }
+  hist2d = ^hist1d_field;
+  hist2d_field = array[0..HIST_C0_ELEMS-1] of hist2d;
+  hist3d = ^hist2d_field;   { type for top-level pointer }
+
+
+{ Declarations for Floyd-Steinberg dithering.
+
+  Errors are accumulated into the array fserrors[], at a resolution of
+  1/16th of a pixel count.  The error at a given pixel is propagated
+  to its not-yet-processed neighbors using the standard F-S fractions,
+    ... (here)  7/16
+    3/16  5/16  1/16
+  We work left-to-right on even rows, right-to-left on odd rows.
+
+  We can get away with a single array (holding one row's worth of errors)
+  by using it to store the current row's errors at pixel columns not yet
+  processed, but the next row's errors at columns already processed.  We
+  need only a few extra variables to hold the errors immediately around the
+  current column.  (If we are lucky, those variables are in registers, but
+  even if not, they're probably cheaper to access than array elements are.)
+
+  The fserrors[] array has (#columns + 2) entries; the extra entry at
+  each end saves us from special-casing the first and last pixels.
+  Each entry is three values long, one value for each color component.
+
+  Note: on a wide image, we might not have enough room in a PC's near data
+  segment to hold the error array; so it is allocated with alloc_large. }
+
+
+{$ifdef BITS_IN_JSAMPLE_IS_8}
+type
+  FSERROR = INT16;              { 16 bits should be enough }
+  LOCFSERROR = int;             { use 'int' for calculation temps }
+{$else}
+type
+  FSERROR = INT32;              { may need more than 16 bits }
+  LOCFSERROR = INT32;           { be sure calculation temps are big enough }
+{$endif}
+type                            { Nomssi }
+  RGB_FSERROR_PTR = ^RGB_FSERROR;
+  RGB_FSERROR = packed record
+    r,g,b : FSERROR;
+  end;
+  LOCRGB_FSERROR = packed record
+    r,g,b : LOCFSERROR;
+  end;
+
+type
+  FSERROR_PTR = ^FSERROR;
+  jFSError = 0..(MaxInt div SIZEOF(RGB_FSERROR))-1;
+  FS_ERROR_FIELD = array[jFSError] of RGB_FSERROR;
+  FS_ERROR_FIELD_PTR = ^FS_ERROR_FIELD;{far}
+                                { pointer to error array (in FAR storage!) }
+
+type
+  error_limit_array = array[-MAXJSAMPLE..MAXJSAMPLE] of int;
+  { table for clamping the applied error }
+  error_limit_ptr = ^error_limit_array;
+
+{ Private subobject }
+type
+  my_cquantize_ptr = ^my_cquantizer;
+  my_cquantizer = record
+    pub : jpeg_color_quantizer; { public fields }
+
+    { Space for the eventually created colormap is stashed here }
+    sv_colormap : JSAMPARRAY; { colormap allocated at init time }
+    desired : int;              { desired # of colors = size of colormap }
+
+    { Variables for accumulating image statistics }
+    histogram : hist3d;         { pointer to the histogram }
+
+    needs_zeroed : boolean;     { TRUE if next pass must zero histogram }
+
+    { Variables for Floyd-Steinberg dithering }
+    fserrors : FS_ERROR_FIELD_PTR;        { accumulated errors }
+    on_odd_row : boolean;       { flag to remember which row we are on }
+    error_limiter : error_limit_ptr; { table for clamping the applied error }
+  end;
+
+
+
+{ Prescan some rows of pixels.
+  In this module the prescan simply updates the histogram, which has been
+  initialized to zeroes by start_pass.
+  An output_buf parameter is required by the method signature, but no data
+  is actually output (in fact the buffer controller is probably passing a
+  NIL pointer). }
+
+{METHODDEF}
+procedure prescan_quantize (cinfo : j_decompress_ptr;
+                            input_buf : JSAMPARRAY;
+                            output_buf : JSAMPARRAY;
+                            num_rows : int);
+var
+  cquantize : my_cquantize_ptr;
+  {register} ptr : RGBptr;
+  {register} histp : histptr;
+  {register} histogram : hist3d;
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+begin
+  cquantize := my_cquantize_ptr(cinfo^.cquantize);
+  histogram := cquantize^.histogram;
+  width := cinfo^.output_width;
+
+  for row := 0 to pred(num_rows) do
+  begin
+    ptr := RGBptr(input_buf^[row]);
+    for col := pred(width) downto 0 do
+    begin
+      { get pixel value and index into the histogram }
+      histp := @(histogram^[GETJSAMPLE(ptr^.r) shr C0_SHIFT]^
+                           [GETJSAMPLE(ptr^.g) shr C1_SHIFT]
+         [GETJSAMPLE(ptr^.b) shr C2_SHIFT]);
+      { increment, check for overflow and undo increment if so. }
+      Inc(histp^);
+      if (histp^ <= 0) then
+  Dec(histp^);
+      Inc(ptr);
+    end;
+  end;
+end;
+
+{ Next we have the really interesting routines: selection of a colormap
+  given the completed histogram.
+  These routines work with a list of "boxes", each representing a rectangular
+  subset of the input color space (to histogram precision). }
+
+type
+  box = record
+  { The bounds of the box (inclusive); expressed as histogram indexes }
+    c0min, c0max : int;
+    c1min, c1max : int;
+    c2min, c2max : int;
+    { The volume (actually 2-norm) of the box }
+    volume : INT32;
+    { The number of nonzero histogram cells within this box }
+    colorcount : long;
+  end;
+
+type
+  jBoxList = 0..(MaxInt div SizeOf(box))-1;
+  box_field = array[jBoxlist] of box;
+  boxlistptr = ^box_field;
+  boxptr = ^box;
+
+{LOCAL}
+function find_biggest_color_pop (boxlist : boxlistptr; numboxes : int) : boxptr;
+{ Find the splittable box with the largest color population }
+{ Returns NIL if no splittable boxes remain }
+var
+  boxp : boxptr ; {register}
+  i : int;        {register}
+  maxc : long;    {register}
+  which : boxptr;
+begin
+  which := NIL;
+  boxp := @(boxlist^[0]);
+  maxc := 0;
+  for i := 0 to pred(numboxes) do
+  begin
+    if (boxp^.colorcount > maxc) and (boxp^.volume > 0) then
+    begin
+      which := boxp;
+      maxc := boxp^.colorcount;
+    end;
+    Inc(boxp);
+  end;
+  find_biggest_color_pop := which;
+end;
+
+
+{LOCAL}
+function find_biggest_volume (boxlist : boxlistptr; numboxes : int) : boxptr;
+{ Find the splittable box with the largest (scaled) volume }
+{ Returns NULL if no splittable boxes remain }
+var
+  {register} boxp : boxptr;
+  {register} i : int;
+  {register} maxv : INT32;
+  which : boxptr;
+begin
+  maxv := 0;
+  which := NIL;
+  boxp := @(boxlist^[0]);
+  for i := 0 to pred(numboxes) do
+  begin
+    if (boxp^.volume > maxv) then
+    begin
+      which := boxp;
+      maxv := boxp^.volume;
+    end;
+    Inc(boxp);
+  end;
+  find_biggest_volume := which;
+end;
+
+
+{LOCAL}
+procedure update_box (cinfo : j_decompress_ptr; var boxp : box);
+label
+  have_c0min, have_c0max,
+  have_c1min, have_c1max,
+  have_c2min, have_c2max;
+{ Shrink the min/max bounds of a box to enclose only nonzero elements, }
+{ and recompute its volume and population }
+var
+  cquantize : my_cquantize_ptr;
+  histogram : hist3d;
+  histp : histptr;
+  c0,c1,c2 : int;
+  c0min,c0max,c1min,c1max,c2min,c2max : int;
+  dist0,dist1,dist2 : INT32;
+  ccount : long;
+begin
+  cquantize := my_cquantize_ptr(cinfo^.cquantize);
+  histogram := cquantize^.histogram;
+
+  c0min := boxp.c0min;  c0max := boxp.c0max;
+  c1min := boxp.c1min;  c1max := boxp.c1max;
+  c2min := boxp.c2min;  c2max := boxp.c2max;
+
+  if (c0max > c0min) then
+    for c0 := c0min to c0max do
+      for c1 := c1min to c1max do
+      begin
+  histp := @(histogram^[c0]^[c1][c2min]);
+  for c2 := c2min to c2max do
+        begin
+    if (histp^ <> 0) then
+          begin
+            c0min := c0;
+      boxp.c0min := c0min;
+      goto have_c0min;
+    end;
+          Inc(histp);
+        end;
+      end;
+ have_c0min:
+  if (c0max > c0min) then
+    for c0 := c0max downto c0min do
+      for c1 := c1min to c1max do
+      begin
+  histp := @(histogram^[c0]^[c1][c2min]);
+  for c2 := c2min to c2max do
+        begin
+    if ( histp^ <> 0) then
+          begin
+            c0max := c0;
+      boxp.c0max := c0;
+      goto have_c0max;
+    end;
+          Inc(histp);
+        end;
+      end;
+ have_c0max:
+  if (c1max > c1min) then
+    for c1 := c1min to c1max do
+      for c0 := c0min to c0max do
+      begin
+  histp := @(histogram^[c0]^[c1][c2min]);
+  for c2 := c2min to c2max do
+        begin
+    if (histp^ <> 0) then
+          begin
+            c1min := c1;
+      boxp.c1min := c1;
+      goto have_c1min;
+    end;
+          Inc(histp);
+        end;
+      end;
+ have_c1min:
+  if (c1max > c1min) then
+    for c1 := c1max downto c1min do
+      for c0 := c0min to c0max do
+      begin
+  histp := @(histogram^[c0]^[c1][c2min]);
+  for c2 := c2min to c2max do
+        begin
+    if (histp^ <> 0) then
+          begin
+            c1max := c1;
+      boxp.c1max := c1;
+      goto have_c1max;
+    end;
+          Inc(histp);
+        end;
+      end;
+ have_c1max:
+  if (c2max > c2min) then
+    for c2 := c2min to c2max do
+      for c0 := c0min to c0max do
+      begin
+  histp := @(histogram^[c0]^[c1min][c2]);
+  for c1 := c1min to c1max do
+        begin
+    if (histp^ <> 0) then
+          begin
+      c2min := c2;
+      boxp.c2min := c2min;
+      goto have_c2min;
+    end;
+          Inc(histp, HIST_C2_ELEMS);
+        end;
+      end;
+ have_c2min:
+  if (c2max > c2min) then
+    for c2 := c2max downto c2min do
+      for c0 := c0min to c0max do
+      begin
+  histp := @(histogram^[c0]^[c1min][c2]);
+  for c1 := c1min to c1max do
+        begin
+    if (histp^ <> 0) then
+          begin
+      c2max := c2;
+      boxp.c2max := c2max;
+      goto have_c2max;
+    end;
+          Inc(histp, HIST_C2_ELEMS);
+        end;
+      end;
+ have_c2max:
+
+  { Update box volume.
+    We use 2-norm rather than real volume here; this biases the method
+    against making long narrow boxes, and it has the side benefit that
+    a box is splittable iff norm > 0.
+    Since the differences are expressed in histogram-cell units,
+    we have to shift back to JSAMPLE units to get consistent distances;
+    after which, we scale according to the selected distance scale factors.}
+
+  dist0 := ((c0max - c0min) shl C0_SHIFT) * C0_SCALE;
+  dist1 := ((c1max - c1min) shl C1_SHIFT) * C1_SCALE;
+  dist2 := ((c2max - c2min) shl C2_SHIFT) * C2_SCALE;
+  boxp.volume := dist0*dist0 + dist1*dist1 + dist2*dist2;
+
+  { Now scan remaining volume of box and compute population }
+  ccount := 0;
+  for c0 := c0min to c0max do
+    for c1 := c1min to c1max do
+    begin
+      histp := @(histogram^[c0]^[c1][c2min]);
+      for c2 := c2min to c2max do
+      begin
+  if (histp^ <> 0) then
+    Inc(ccount);
+        Inc(histp);
+      end;
+    end;
+  boxp.colorcount := ccount;
+end;
+
+
+{LOCAL}
+function median_cut (cinfo : j_decompress_ptr; boxlist : boxlistptr;
+                     numboxes : int; desired_colors : int) : int;
+{ Repeatedly select and split the largest box until we have enough boxes }
+var
+  n,lb : int;
+  c0,c1,c2,cmax : int;
+  {register} b1,b2 : boxptr;
+begin
+  while (numboxes < desired_colors) do
+  begin
+    { Select box to split.
+      Current algorithm: by population for first half, then by volume. }
+
+    if (numboxes*2 <= desired_colors) then
+      b1 := find_biggest_color_pop(boxlist, numboxes)
+    else
+      b1 := find_biggest_volume(boxlist, numboxes);
+
+    if (b1 = NIL) then          { no splittable boxes left! }
+      break;
+    b2 := @(boxlist^[numboxes]);  { where new box will go }
+    { Copy the color bounds to the new box. }
+    b2^.c0max := b1^.c0max; b2^.c1max := b1^.c1max; b2^.c2max := b1^.c2max;
+    b2^.c0min := b1^.c0min; b2^.c1min := b1^.c1min; b2^.c2min := b1^.c2min;
+    { Choose which axis to split the box on.
+      Current algorithm: longest scaled axis.
+      See notes in update_box about scaling distances. }
+
+    c0 := ((b1^.c0max - b1^.c0min) shl C0_SHIFT) * C0_SCALE;
+    c1 := ((b1^.c1max - b1^.c1min) shl C1_SHIFT) * C1_SCALE;
+    c2 := ((b1^.c2max - b1^.c2min) shl C2_SHIFT) * C2_SCALE;
+    { We want to break any ties in favor of green, then red, blue last.
+      This code does the right thing for R,G,B or B,G,R color orders only. }
+
+{$ifdef RGB_RED_IS_0}
+    cmax := c1; n := 1;
+    if (c0 > cmax) then
+    begin
+      cmax := c0;
+      n := 0;
+    end;
+    if (c2 > cmax) then
+      n := 2;
+{$else}
+    cmax := c1;
+    n := 1;
+    if (c2 > cmax) then
+    begin
+      cmax := c2;
+      n := 2;
+    end;
+    if (c0 > cmax) then
+      n := 0;
+{$endif}
+    { Choose split point along selected axis, and update box bounds.
+      Current algorithm: split at halfway point.
+      (Since the box has been shrunk to minimum volume,
+      any split will produce two nonempty subboxes.)
+      Note that lb value is max for lower box, so must be < old max. }
+
+    case n of
+    0:begin
+        lb := (b1^.c0max + b1^.c0min) div 2;
+        b1^.c0max := lb;
+        b2^.c0min := lb+1;
+      end;
+    1:begin
+        lb := (b1^.c1max + b1^.c1min) div 2;
+        b1^.c1max := lb;
+        b2^.c1min := lb+1;
+      end;
+    2:begin
+        lb := (b1^.c2max + b1^.c2min) div 2;
+        b1^.c2max := lb;
+        b2^.c2min := lb+1;
+      end;
+    end;
+    { Update stats for boxes }
+    update_box(cinfo, b1^);
+    update_box(cinfo, b2^);
+    Inc(numboxes);
+  end;
+  median_cut := numboxes;
+end;
+
+
+{LOCAL}
+procedure compute_color (cinfo : j_decompress_ptr;
+                         const boxp : box; icolor : int);
+{ Compute representative color for a box, put it in colormap[icolor] }
+var
+  { Current algorithm: mean weighted by pixels (not colors) }
+  { Note it is important to get the rounding correct! }
+  cquantize : my_cquantize_ptr;
+  histogram : hist3d;
+  histp : histptr;
+  c0,c1,c2 : int;
+  c0min,c0max,c1min,c1max,c2min,c2max : int;
+  count : long;
+  total : long;
+  c0total : long;
+  c1total : long;
+  c2total : long;
+begin
+  cquantize := my_cquantize_ptr(cinfo^.cquantize);
+  histogram := cquantize^.histogram;
+  total := 0;
+  c0total := 0;
+  c1total := 0;
+  c2total := 0;
+
+  c0min := boxp.c0min;  c0max := boxp.c0max;
+  c1min := boxp.c1min;  c1max := boxp.c1max;
+  c2min := boxp.c2min;  c2max := boxp.c2max;
+
+  for c0 := c0min to c0max do
+    for c1 := c1min to c1max do
+    begin
+      histp := @(histogram^[c0]^[c1][c2min]);
+      for c2 := c2min to c2max do
+      begin
+  count := histp^;
+        Inc(histp);
+  if (count <> 0) then
+        begin
+    Inc(total, count);
+    Inc(c0total, ((c0 shl C0_SHIFT) + ((1 shl C0_SHIFT) shr 1)) * count);
+    Inc(c1total, ((c1 shl C1_SHIFT) + ((1 shl C1_SHIFT) shr 1)) * count);
+    Inc(c2total, ((c2 shl C2_SHIFT) + ((1 shl C2_SHIFT) shr 1)) * count);
+  end;
+      end;
+    end;
+
+  cinfo^.colormap^[0]^[icolor] := JSAMPLE ((c0total + (total shr 1)) div total);
+  cinfo^.colormap^[1]^[icolor] := JSAMPLE ((c1total + (total shr 1)) div total);
+  cinfo^.colormap^[2]^[icolor] := JSAMPLE ((c2total + (total shr 1)) div total);
+end;
+
+
+{LOCAL}
+procedure select_colors (cinfo : j_decompress_ptr; desired_colors : int);
+{ Master routine for color selection }
+var
+  boxlist : boxlistptr;
+  numboxes : int;
+  i : int;
+begin
+  { Allocate workspace for box list }
+  boxlist := boxlistptr(cinfo^.mem^.alloc_small(
+    j_common_ptr(cinfo), JPOOL_IMAGE, desired_colors * SIZEOF(box)));
+  { Initialize one box containing whole space }
+  numboxes := 1;
+  boxlist^[0].c0min := 0;
+  boxlist^[0].c0max := MAXJSAMPLE shr C0_SHIFT;
+  boxlist^[0].c1min := 0;
+  boxlist^[0].c1max := MAXJSAMPLE shr C1_SHIFT;
+  boxlist^[0].c2min := 0;
+  boxlist^[0].c2max := MAXJSAMPLE shr C2_SHIFT;
+  { Shrink it to actually-used volume and set its statistics }
+  update_box(cinfo, boxlist^[0]);
+  { Perform median-cut to produce final box list }
+  numboxes := median_cut(cinfo, boxlist, numboxes, desired_colors);
+  { Compute the representative color for each box, fill colormap }
+  for i := 0 to pred(numboxes) do
+    compute_color(cinfo, boxlist^[i], i);
+  cinfo^.actual_number_of_colors := numboxes;
+  {$IFDEF DEBUG}
+  TRACEMS1(j_common_ptr(cinfo), 1, JTRC_QUANT_SELECTED, numboxes);
+  {$ENDIF}
+end;
+
+
+{ These routines are concerned with the time-critical task of mapping input
+  colors to the nearest color in the selected colormap.
+
+  We re-use the histogram space as an "inverse color map", essentially a
+  cache for the results of nearest-color searches.  All colors within a
+  histogram cell will be mapped to the same colormap entry, namely the one
+  closest to the cell's center.  This may not be quite the closest entry to
+  the actual input color, but it's almost as good.  A zero in the cache
+  indicates we haven't found the nearest color for that cell yet; the array
+  is cleared to zeroes before starting the mapping pass.  When we find the
+  nearest color for a cell, its colormap index plus one is recorded in the
+  cache for future use.  The pass2 scanning routines call fill_inverse_cmap
+  when they need to use an unfilled entry in the cache.
+
+  Our method of efficiently finding nearest colors is based on the "locally
+  sorted search" idea described by Heckbert and on the incremental distance
+  calculation described by Spencer W. Thomas in chapter III.1 of Graphics
+  Gems II (James Arvo, ed.  Academic Press, 1991).  Thomas points out that
+  the distances from a given colormap entry to each cell of the histogram can
+  be computed quickly using an incremental method: the differences between
+  distances to adjacent cells themselves differ by a constant.  This allows a
+  fairly fast implementation of the "brute force" approach of computing the
+  distance from every colormap entry to every histogram cell.  Unfortunately,
+  it needs a work array to hold the best-distance-so-far for each histogram
+  cell (because the inner loop has to be over cells, not colormap entries).
+  The work array elements have to be INT32s, so the work array would need
+  256Kb at our recommended precision.  This is not feasible in DOS machines.
+
+  To get around these problems, we apply Thomas' method to compute the
+  nearest colors for only the cells within a small subbox of the histogram.
+  The work array need be only as big as the subbox, so the memory usage
+  problem is solved.  Furthermore, we need not fill subboxes that are never
+  referenced in pass2; many images use only part of the color gamut, so a
+  fair amount of work is saved.  An additional advantage of this
+  approach is that we can apply Heckbert's locality criterion to quickly
+  eliminate colormap entries that are far away from the subbox; typically
+  three-fourths of the colormap entries are rejected by Heckbert's criterion,
+  and we need not compute their distances to individual cells in the subbox.
+  The speed of this approach is heavily influenced by the subbox size: too
+  small means too much overhead, too big loses because Heckbert's criterion
+  can't eliminate as many colormap entries.  Empirically the best subbox
+  size seems to be about 1/512th of the histogram (1/8th in each direction).
+
+  Thomas' article also describes a refined method which is asymptotically
+  faster than the brute-force method, but it is also far more complex and
+  cannot efficiently be applied to small subboxes.  It is therefore not
+  useful for programs intended to be portable to DOS machines.  On machines
+  with plenty of memory, filling the whole histogram in one shot with Thomas'
+  refined method might be faster than the present code --- but then again,
+  it might not be any faster, and it's certainly more complicated. }
+
+
+
+{ log2(histogram cells in update box) for each axis; this can be adjusted }
+const
+  BOX_C0_LOG = (HIST_C0_BITS-3);
+  BOX_C1_LOG = (HIST_C1_BITS-3);
+  BOX_C2_LOG = (HIST_C2_BITS-3);
+
+  BOX_C0_ELEMS = (1 shl BOX_C0_LOG); { # of hist cells in update box }
+  BOX_C1_ELEMS = (1 shl BOX_C1_LOG);
+  BOX_C2_ELEMS = (1 shl BOX_C2_LOG);
+
+  BOX_C0_SHIFT = (C0_SHIFT + BOX_C0_LOG);
+  BOX_C1_SHIFT = (C1_SHIFT + BOX_C1_LOG);
+  BOX_C2_SHIFT = (C2_SHIFT + BOX_C2_LOG);
+
+
+{ The next three routines implement inverse colormap filling.  They could
+  all be folded into one big routine, but splitting them up this way saves
+  some stack space (the mindist[] and bestdist[] arrays need not coexist)
+  and may allow some compilers to produce better code by registerizing more
+  inner-loop variables. }
+
+{LOCAL}
+function find_nearby_colors (cinfo : j_decompress_ptr;
+                             minc0 : int; minc1 : int; minc2 : int;
+                 var colorlist : array of JSAMPLE) : int;
+{ Locate the colormap entries close enough to an update box to be candidates
+  for the nearest entry to some cell(s) in the update box.  The update box
+  is specified by the center coordinates of its first cell.  The number of
+  candidate colormap entries is returned, and their colormap indexes are
+  placed in colorlist[].
+  This routine uses Heckbert's "locally sorted search" criterion to select
+  the colors that need further consideration. }
+
+var
+  numcolors : int;
+  maxc0, maxc1, maxc2 : int;
+  centerc0, centerc1, centerc2 : int;
+  i, x, ncolors : int;
+  minmaxdist, min_dist, max_dist, tdist : INT32;
+  mindist : array[0..MAXNUMCOLORS-1] of INT32;
+    { min distance to colormap entry i }
+begin
+  numcolors := cinfo^.actual_number_of_colors;
+
+  { Compute true coordinates of update box's upper corner and center.
+    Actually we compute the coordinates of the center of the upper-corner
+    histogram cell, which are the upper bounds of the volume we care about.
+    Note that since ">>" rounds down, the "center" values may be closer to
+    min than to max; hence comparisons to them must be "<=", not "<". }
+
+  maxc0 := minc0 + ((1 shl BOX_C0_SHIFT) - (1 shl C0_SHIFT));
+  centerc0 := (minc0 + maxc0) shr 1;
+  maxc1 := minc1 + ((1 shl BOX_C1_SHIFT) - (1 shl C1_SHIFT));
+  centerc1 := (minc1 + maxc1) shr 1;
+  maxc2 := minc2 + ((1 shl BOX_C2_SHIFT) - (1 shl C2_SHIFT));
+  centerc2 := (minc2 + maxc2) shr 1;
+
+  { For each color in colormap, find:
+     1. its minimum squared-distance to any point in the update box
+        (zero if color is within update box);
+     2. its maximum squared-distance to any point in the update box.
+    Both of these can be found by considering only the corners of the box.
+    We save the minimum distance for each color in mindist[];
+    only the smallest maximum distance is of interest. }
+
+  minmaxdist := long($7FFFFFFF);
+
+  for i := 0 to pred(numcolors) do
+  begin
+    { We compute the squared-c0-distance term, then add in the other two. }
+    x := GETJSAMPLE(cinfo^.colormap^[0]^[i]);
+    if (x < minc0) then
+    begin
+      tdist := (x - minc0) * C0_SCALE;
+      min_dist := tdist*tdist;
+      tdist := (x - maxc0) * C0_SCALE;
+      max_dist := tdist*tdist;
+    end
+    else
+      if (x > maxc0) then
+      begin
+        tdist := (x - maxc0) * C0_SCALE;
+        min_dist := tdist*tdist;
+        tdist := (x - minc0) * C0_SCALE;
+        max_dist := tdist*tdist;
+      end
+      else
+      begin
+        { within cell range so no contribution to min_dist }
+        min_dist := 0;
+        if (x <= centerc0) then
+        begin
+          tdist := (x - maxc0) * C0_SCALE;
+          max_dist := tdist*tdist;
+        end
+        else
+        begin
+          tdist := (x - minc0) * C0_SCALE;
+          max_dist := tdist*tdist;
+        end;
+      end;
+
+    x := GETJSAMPLE(cinfo^.colormap^[1]^[i]);
+    if (x < minc1) then
+    begin
+      tdist := (x - minc1) * C1_SCALE;
+      Inc(min_dist, tdist*tdist);
+      tdist := (x - maxc1) * C1_SCALE;
+      Inc(max_dist, tdist*tdist);
+    end
+    else
+      if (x > maxc1) then
+      begin
+        tdist := (x - maxc1) * C1_SCALE;
+        Inc(min_dist, tdist*tdist);
+        tdist := (x - minc1) * C1_SCALE;
+        Inc(max_dist, tdist*tdist);
+      end
+      else
+      begin
+        { within cell range so no contribution to min_dist }
+        if (x <= centerc1) then
+        begin
+    tdist := (x - maxc1) * C1_SCALE;
+    Inc(max_dist, tdist*tdist);
+        end
+        else
+        begin
+    tdist := (x - minc1) * C1_SCALE;
+    Inc(max_dist, tdist*tdist);
+        end
+      end;
+
+    x := GETJSAMPLE(cinfo^.colormap^[2]^[i]);
+    if (x < minc2) then
+    begin
+      tdist := (x - minc2) * C2_SCALE;
+      Inc(min_dist, tdist*tdist);
+      tdist := (x - maxc2) * C2_SCALE;
+      Inc(max_dist, tdist*tdist);
+    end
+    else
+      if (x > maxc2) then
+      begin
+        tdist := (x - maxc2) * C2_SCALE;
+        Inc(min_dist, tdist*tdist);
+        tdist := (x - minc2) * C2_SCALE;
+        Inc(max_dist, tdist*tdist);
+      end
+      else
+      begin
+        { within cell range so no contribution to min_dist }
+        if (x <= centerc2) then
+        begin
+    tdist := (x - maxc2) * C2_SCALE;
+    Inc(max_dist, tdist*tdist);
+        end
+        else
+        begin
+    tdist := (x - minc2) * C2_SCALE;
+    Inc(max_dist, tdist*tdist);
+        end;
+      end;
+
+    mindist[i] := min_dist; { save away the results }
+    if (max_dist < minmaxdist) then
+      minmaxdist := max_dist;
+  end;
+
+  { Now we know that no cell in the update box is more than minmaxdist
+    away from some colormap entry.  Therefore, only colors that are
+    within minmaxdist of some part of the box need be considered. }
+
+  ncolors := 0;
+  for i := 0 to pred(numcolors) do
+  begin
+    if (mindist[i] <= minmaxdist) then
+    begin
+      colorlist[ncolors] := JSAMPLE(i);
+      Inc(ncolors);
+    end;
+  end;
+  find_nearby_colors := ncolors;
+end;
+
+
+{LOCAL}
+procedure find_best_colors (cinfo : j_decompress_ptr;
+                            minc0 : int; minc1 : int; minc2 : int;
+                            numcolors : int;
+                            var colorlist : array of JSAMPLE;
+                            var bestcolor : array of JSAMPLE);
+{ Find the closest colormap entry for each cell in the update box,
+  given the list of candidate colors prepared by find_nearby_colors.
+  Return the indexes of the closest entries in the bestcolor[] array.
+  This routine uses Thomas' incremental distance calculation method to
+  find the distance from a colormap entry to successive cells in the box. }
+const
+  { Nominal steps between cell centers ("x" in Thomas article) }
+  STEP_C0 = ((1 shl C0_SHIFT) * C0_SCALE);
+  STEP_C1 = ((1 shl C1_SHIFT) * C1_SCALE);
+  STEP_C2 = ((1 shl C2_SHIFT) * C2_SCALE);
+var
+  ic0, ic1, ic2 : int;
+  i, icolor : int;
+  {register} bptr : INT32PTR;     { pointer into bestdist[] array }
+  cptr : JSAMPLE_PTR;              { pointer into bestcolor[] array }
+  dist0, dist1 : INT32;         { initial distance values }
+  {register} dist2 : INT32; { current distance in inner loop }
+  xx0, xx1 : INT32;             { distance increments }
+  {register} xx2 : INT32;
+  inc0, inc1, inc2 : INT32; { initial values for increments }
+  { This array holds the distance to the nearest-so-far color for each cell }
+  bestdist : array[0..BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS-1] of INT32;
+begin
+  { Initialize best-distance for each cell of the update box }
+  for i := BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1 downto 0 do
+    bestdist[i] := $7FFFFFFF;
+
+  { For each color selected by find_nearby_colors,
+    compute its distance to the center of each cell in the box.
+    If that's less than best-so-far, update best distance and color number. }
+
+
+
+  for i := 0 to pred(numcolors) do
+  begin
+    icolor := GETJSAMPLE(colorlist[i]);
+    { Compute (square of) distance from minc0/c1/c2 to this color }
+    inc0 := (minc0 - GETJSAMPLE(cinfo^.colormap^[0]^[icolor])) * C0_SCALE;
+    dist0 := inc0*inc0;
+    inc1 := (minc1 - GETJSAMPLE(cinfo^.colormap^[1]^[icolor])) * C1_SCALE;
+    Inc(dist0, inc1*inc1);
+    inc2 := (minc2 - GETJSAMPLE(cinfo^.colormap^[2]^[icolor])) * C2_SCALE;
+    Inc(dist0, inc2*inc2);
+    { Form the initial difference increments }
+    inc0 := inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
+    inc1 := inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;
+    inc2 := inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;
+    { Now loop over all cells in box, updating distance per Thomas method }
+    bptr := @bestdist[0];
+    cptr := @bestcolor[0];
+    xx0 := inc0;
+    for ic0 := BOX_C0_ELEMS-1 downto 0 do
+    begin
+      dist1 := dist0;
+      xx1 := inc1;
+      for ic1 := BOX_C1_ELEMS-1 downto 0 do
+      begin
+  dist2 := dist1;
+  xx2 := inc2;
+  for ic2 := BOX_C2_ELEMS-1 downto 0 do
+        begin
+    if (dist2 < bptr^) then
+          begin
+      bptr^ := dist2;
+      cptr^ := JSAMPLE (icolor);
+    end;
+    Inc(dist2, xx2);
+    Inc(xx2, 2 * STEP_C2 * STEP_C2);
+    Inc(bptr);
+    Inc(cptr);
+  end;
+  Inc(dist1, xx1);
+  Inc(xx1, 2 * STEP_C1 * STEP_C1);
+      end;
+      Inc(dist0, xx0);
+      Inc(xx0, 2 * STEP_C0 * STEP_C0);
+    end;
+  end;
+end;
+
+
+{LOCAL}
+procedure fill_inverse_cmap (cinfo : j_decompress_ptr;
+                             c0 : int; c1 : int; c2 : int);
+{ Fill the inverse-colormap entries in the update box that contains }
+{ histogram cell c0/c1/c2.  (Only that one cell MUST be filled, but }
+{ we can fill as many others as we wish.) }
+var
+  cquantize : my_cquantize_ptr;
+  histogram : hist3d;
+  minc0, minc1, minc2 : int;    { lower left corner of update box }
+  ic0, ic1, ic2 : int;
+  {register} cptr : JSAMPLE_PTR;  { pointer into bestcolor[] array }
+  {register} cachep : histptr;  { pointer into main cache array }
+  { This array lists the candidate colormap indexes. }
+  colorlist : array[0..MAXNUMCOLORS-1] of JSAMPLE;
+  numcolors : int;    { number of candidate colors }
+  { This array holds the actually closest colormap index for each cell. }
+  bestcolor : array[0..BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS-1] of JSAMPLE;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  histogram := cquantize^.histogram;
+
+  { Convert cell coordinates to update box ID }
+  c0 := c0 shr BOX_C0_LOG;
+  c1 := c1 shr BOX_C1_LOG;
+  c2 := c2 shr BOX_C2_LOG;
+
+  { Compute true coordinates of update box's origin corner.
+    Actually we compute the coordinates of the center of the corner
+    histogram cell, which are the lower bounds of the volume we care about.}
+
+  minc0 := (c0 shl BOX_C0_SHIFT) + ((1 shl C0_SHIFT) shr 1);
+  minc1 := (c1 shl BOX_C1_SHIFT) + ((1 shl C1_SHIFT) shr 1);
+  minc2 := (c2 shl BOX_C2_SHIFT) + ((1 shl C2_SHIFT) shr 1);
+
+  { Determine which colormap entries are close enough to be candidates
+    for the nearest entry to some cell in the update box. }
+
+  numcolors := find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
+
+  { Determine the actually nearest colors. }
+  find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,
+       bestcolor);
+
+  { Save the best color numbers (plus 1) in the main cache array }
+  c0 := c0 shl BOX_C0_LOG;    { convert ID back to base cell indexes }
+  c1 := c1 shl BOX_C1_LOG;
+  c2 := c2 shl BOX_C2_LOG;
+  cptr := @(bestcolor[0]);
+  for ic0 := 0 to pred(BOX_C0_ELEMS) do
+    for ic1 := 0 to pred(BOX_C1_ELEMS) do
+    begin
+      cachep := @(histogram^[c0+ic0]^[c1+ic1][c2]);
+      for ic2 := 0 to pred(BOX_C2_ELEMS) do
+      begin
+  cachep^ := histcell (GETJSAMPLE(cptr^) + 1);
+        Inc(cachep);
+        Inc(cptr);
+      end;
+    end;
+end;
+
+
+{ Map some rows of pixels to the output colormapped representation. }
+
+{METHODDEF}
+procedure pass2_no_dither (cinfo : j_decompress_ptr;
+               input_buf : JSAMPARRAY;
+                           output_buf : JSAMPARRAY;
+                           num_rows : int);
+{ This version performs no dithering }
+var
+  cquantize : my_cquantize_ptr;
+  histogram : hist3d;
+  {register} inptr : RGBptr;
+             outptr : JSAMPLE_PTR;
+  {register} cachep : histptr;
+  {register} c0, c1, c2 : int;
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  histogram := cquantize^.histogram;
+  width := cinfo^.output_width;
+
+  for row := 0 to pred(num_rows) do
+  begin
+    inptr := RGBptr(input_buf^[row]);
+    outptr := JSAMPLE_PTR(output_buf^[row]);
+    for col := pred(width) downto 0 do
+    begin
+      { get pixel value and index into the cache }
+      c0 := GETJSAMPLE(inptr^.r) shr C0_SHIFT;
+      c1 := GETJSAMPLE(inptr^.g) shr C1_SHIFT;
+      c2 := GETJSAMPLE(inptr^.b) shr C2_SHIFT;
+      Inc(inptr);
+      cachep := @(histogram^[c0]^[c1][c2]);
+      { If we have not seen this color before, find nearest colormap entry }
+      { and update the cache }
+      if (cachep^ = 0) then
+  fill_inverse_cmap(cinfo, c0,c1,c2);
+      { Now emit the colormap index for this cell }
+      outptr^ := JSAMPLE (cachep^ - 1);
+      Inc(outptr);
+    end;
+  end;
+end;
+
+
+{METHODDEF}
+procedure pass2_fs_dither (cinfo : j_decompress_ptr;
+               input_buf : JSAMPARRAY;
+                           output_buf : JSAMPARRAY;
+                           num_rows : int);
+{ This version performs Floyd-Steinberg dithering }
+var
+  cquantize : my_cquantize_ptr;
+  histogram : hist3d;
+  {register} cur : LOCRGB_FSERROR;  { current error or pixel value }
+  belowerr : LOCRGB_FSERROR; { error for pixel below cur }
+  bpreverr : LOCRGB_FSERROR; { error for below/prev col }
+  prev_errorptr,
+  {register} errorptr : RGB_FSERROR_PTR;  { => fserrors[] at column before current }
+  inptr : RGBptr;   { => current input pixel }
+  outptr : JSAMPLE_PTR;   { => current output pixel }
+  cachep : histptr;
+  dir : int;      { +1 or -1 depending on direction }
+  row : int;
+  col : JDIMENSION;
+  width : JDIMENSION;
+  range_limit : range_limit_table_ptr;
+  error_limit : error_limit_ptr;
+  colormap0 : JSAMPROW;
+  colormap1 : JSAMPROW;
+  colormap2 : JSAMPROW;
+  {register} pixcode : int;
+  {register} bnexterr, delta : LOCFSERROR;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  histogram := cquantize^.histogram;
+  width := cinfo^.output_width;
+  range_limit := cinfo^.sample_range_limit;
+  error_limit := cquantize^.error_limiter;
+  colormap0 := cinfo^.colormap^[0];
+  colormap1 := cinfo^.colormap^[1];
+  colormap2 := cinfo^.colormap^[2];
+
+  for row := 0 to pred(num_rows) do
+  begin
+    inptr := RGBptr(input_buf^[row]);
+    outptr := JSAMPLE_PTR(output_buf^[row]);
+    errorptr := RGB_FSERROR_PTR(cquantize^.fserrors); { => entry before first real column }
+    if (cquantize^.on_odd_row) then
+    begin
+      { work right to left in this row }
+      Inc(inptr, (width-1));     { so point to rightmost pixel }
+      Inc(outptr, width-1);
+      dir := -1;
+      Inc(errorptr, (width+1)); { => entry after last column }
+      cquantize^.on_odd_row := FALSE; { flip for next time }
+    end
+    else
+    begin
+      { work left to right in this row }
+      dir := 1;
+      cquantize^.on_odd_row := TRUE; { flip for next time }
+    end;
+
+    { Preset error values: no error propagated to first pixel from left }
+    cur.r := 0;
+    cur.g := 0;
+    cur.b := 0;
+    { and no error propagated to row below yet }
+    belowerr.r := 0;
+    belowerr.g := 0;
+    belowerr.b := 0;
+    bpreverr.r := 0;
+    bpreverr.g := 0;
+    bpreverr.b := 0;
+
+    for col := pred(width) downto 0 do
+    begin
+      prev_errorptr := errorptr;
+      Inc(errorptr, dir); { advance errorptr to current column }
+
+      { curN holds the error propagated from the previous pixel on the
+        current line.  Add the error propagated from the previous line
+        to form the complete error correction term for this pixel, and
+        round the error term (which is expressed * 16) to an integer.
+        RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+        for either sign of the error value.
+        Note: prev_errorptr points to *previous* column's array entry. }
+
+      { Nomssi Note: Borland Pascal SHR is unsigned }
+      cur.r := (cur.r + errorptr^.r + 8) div 16;
+      cur.g := (cur.g + errorptr^.g + 8) div 16;
+      cur.b := (cur.b + errorptr^.b + 8) div 16;
+      { Limit the error using transfer function set by init_error_limit.
+        See comments with init_error_limit for rationale. }
+
+      cur.r := error_limit^[cur.r];
+      cur.g := error_limit^[cur.g];
+      cur.b := error_limit^[cur.b];
+      { Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+        The maximum error is +- MAXJSAMPLE (or less with error limiting);
+        this sets the required size of the range_limit array. }
+
+      Inc(cur.r, GETJSAMPLE(inptr^.r));
+      Inc(cur.g, GETJSAMPLE(inptr^.g));
+      Inc(cur.b, GETJSAMPLE(inptr^.b));
+
+      cur.r := GETJSAMPLE(range_limit^[cur.r]);
+      cur.g := GETJSAMPLE(range_limit^[cur.g]);
+      cur.b := GETJSAMPLE(range_limit^[cur.b]);
+      { Index into the cache with adjusted pixel value }
+      cachep := @(histogram^[cur.r shr C0_SHIFT]^
+                            [cur.g shr C1_SHIFT][cur.b shr C2_SHIFT]);
+      { If we have not seen this color before, find nearest colormap }
+      { entry and update the cache }
+      if (cachep^ = 0) then
+  fill_inverse_cmap(cinfo, cur.r shr C0_SHIFT,
+                                 cur.g shr C1_SHIFT,
+                                 cur.b shr C2_SHIFT);
+      { Now emit the colormap index for this cell }
+
+      pixcode := cachep^ - 1;
+      outptr^ := JSAMPLE (pixcode);
+
+      { Compute representation error for this pixel }
+      Dec(cur.r, GETJSAMPLE(colormap0^[pixcode]));
+      Dec(cur.g, GETJSAMPLE(colormap1^[pixcode]));
+      Dec(cur.b, GETJSAMPLE(colormap2^[pixcode]));
+
+      { Compute error fractions to be propagated to adjacent pixels.
+        Add these into the running sums, and simultaneously shift the
+        next-line error sums left by 1 column. }
+
+      bnexterr := cur.r;  { Process component 0 }
+      delta := cur.r * 2;
+      Inc(cur.r, delta);    { form error * 3 }
+      prev_errorptr^.r := FSERROR (bpreverr.r + cur.r);
+      Inc(cur.r, delta);    { form error * 5 }
+      bpreverr.r := belowerr.r + cur.r;
+      belowerr.r := bnexterr;
+      Inc(cur.r, delta);    { form error * 7 }
+      bnexterr := cur.g;  { Process component 1 }
+      delta := cur.g * 2;
+      Inc(cur.g, delta);    { form error * 3 }
+      prev_errorptr^.g := FSERROR (bpreverr.g + cur.g);
+      Inc(cur.g, delta);    { form error * 5 }
+      bpreverr.g := belowerr.g + cur.g;
+      belowerr.g := bnexterr;
+      Inc(cur.g, delta);    { form error * 7 }
+      bnexterr := cur.b;  { Process component 2 }
+      delta := cur.b * 2;
+      Inc(cur.b, delta);    { form error * 3 }
+      prev_errorptr^.b := FSERROR (bpreverr.b + cur.b);
+      Inc(cur.b, delta);    { form error * 5 }
+      bpreverr.b := belowerr.b + cur.b;
+      belowerr.b := bnexterr;
+      Inc(cur.b, delta);    { form error * 7 }
+
+      { At this point curN contains the 7/16 error value to be propagated
+        to the next pixel on the current line, and all the errors for the
+        next line have been shifted over.  We are therefore ready to move on.}
+
+      Inc(inptr, dir);    { Advance pixel pointers to next column }
+      Inc(outptr, dir);
+    end;
+    { Post-loop cleanup: we must unload the final error values into the
+      final fserrors[] entry.  Note we need not unload belowerrN because
+      it is for the dummy column before or after the actual array. }
+
+    errorptr^.r := FSERROR (bpreverr.r); { unload prev errs into array }
+    errorptr^.g := FSERROR (bpreverr.g);
+    errorptr^.b := FSERROR (bpreverr.b);
+  end;
+end;
+
+
+{ Initialize the error-limiting transfer function (lookup table).
+  The raw F-S error computation can potentially compute error values of up to
+  +- MAXJSAMPLE.  But we want the maximum correction applied to a pixel to be
+  much less, otherwise obviously wrong pixels will be created.  (Typical
+  effects include weird fringes at color-area boundaries, isolated bright
+  pixels in a dark area, etc.)  The standard advice for avoiding this problem
+  is to ensure that the "corners" of the color cube are allocated as output
+  colors; then repeated errors in the same direction cannot cause cascading
+  error buildup.  However, that only prevents the error from getting
+  completely out of hand; Aaron Giles reports that error limiting improves
+  the results even with corner colors allocated.
+  A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
+  well, but the smoother transfer function used below is even better.  Thanks
+  to Aaron Giles for this idea. }
+
+{LOCAL}
+procedure init_error_limit (cinfo : j_decompress_ptr);
+const
+  STEPSIZE = ((MAXJSAMPLE+1) div 16);
+{ Allocate and fill in the error_limiter table }
+var
+  cquantize : my_cquantize_ptr;
+  table : error_limit_ptr;
+  inp, out : int;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  table := error_limit_ptr (cinfo^.mem^.alloc_small
+    (j_common_ptr (cinfo), JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int)));
+  { not needed: Inc(table, MAXJSAMPLE);
+                so can index -MAXJSAMPLE .. +MAXJSAMPLE }
+  cquantize^.error_limiter := table;
+  { Map errors 1:1 up to +- MAXJSAMPLE/16 }
+  out := 0;
+  for inp := 0 to pred(STEPSIZE) do
+  begin
+    table^[inp] := out;
+    table^[-inp] := -out;
+    Inc(out);
+  end;
+  { Map errors 1:2 up to +- 3*MAXJSAMPLE/16 }
+  inp := STEPSIZE;       { Nomssi: avoid problems with Delphi2 optimizer }
+  while (inp < STEPSIZE*3) do
+  begin
+    table^[inp] := out;
+    table^[-inp] := -out;
+    Inc(inp);
+    if Odd(inp) then
+      Inc(out);
+  end;
+  { Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) }
+  inp := STEPSIZE*3;     { Nomssi: avoid problems with Delphi 2 optimizer }
+  while inp <= MAXJSAMPLE do
+  begin
+    table^[inp] := out;
+    table^[-inp] := -out;
+    Inc(inp);
+  end;
+end;
+
+{ Finish up at the end of each pass. }
+
+{METHODDEF}
+procedure finish_pass1 (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+
+  { Select the representative colors and fill in cinfo^.colormap }
+  cinfo^.colormap := cquantize^.sv_colormap;
+  select_colors(cinfo, cquantize^.desired);
+  { Force next pass to zero the color index table }
+  cquantize^.needs_zeroed := TRUE;
+end;
+
+
+{METHODDEF}
+procedure finish_pass2 (cinfo : j_decompress_ptr);
+begin
+  { no work }
+end;
+
+
+{ Initialize for each processing pass. }
+
+{METHODDEF}
+procedure start_pass_2_quant (cinfo : j_decompress_ptr;
+                              is_pre_scan : boolean);
+var
+  cquantize : my_cquantize_ptr;
+  histogram : hist3d;
+  i : int;
+var
+  arraysize : size_t;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+  histogram := cquantize^.histogram;
+  { Only F-S dithering or no dithering is supported. }
+  { If user asks for ordered dither, give him F-S. }
+  if (cinfo^.dither_mode <> JDITHER_NONE) then
+    cinfo^.dither_mode := JDITHER_FS;
+
+  if (is_pre_scan) then
+  begin
+    { Set up method pointers }
+    cquantize^.pub.color_quantize := prescan_quantize;
+    cquantize^.pub.finish_pass := finish_pass1;
+    cquantize^.needs_zeroed := TRUE; { Always zero histogram }
+  end
+  else
+  begin
+    { Set up method pointers }
+    if (cinfo^.dither_mode = JDITHER_FS) then
+      cquantize^.pub.color_quantize := pass2_fs_dither
+    else
+      cquantize^.pub.color_quantize := pass2_no_dither;
+    cquantize^.pub.finish_pass := finish_pass2;
+
+    { Make sure color count is acceptable }
+    i := cinfo^.actual_number_of_colors;
+    if (i < 1) then
+      ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_FEW_COLORS, 1);
+    if (i > MAXNUMCOLORS) then
+      ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+
+    if (cinfo^.dither_mode = JDITHER_FS) then
+    begin
+      arraysize := size_t ((cinfo^.output_width + 2) *
+           (3 * SIZEOF(FSERROR)));
+      { Allocate Floyd-Steinberg workspace if we didn't already. }
+      if (cquantize^.fserrors = NIL) then
+  cquantize^.fserrors := FS_ERROR_FIELD_PTR (cinfo^.mem^.alloc_large
+    (j_common_ptr(cinfo), JPOOL_IMAGE, arraysize));
+      { Initialize the propagated errors to zero. }
+      jzero_far(cquantize^.fserrors, arraysize);
+      { Make the error-limit table if we didn't already. }
+      if (cquantize^.error_limiter = NIL) then
+  init_error_limit(cinfo);
+      cquantize^.on_odd_row := FALSE;
+    end;
+
+  end;
+  { Zero the histogram or inverse color map, if necessary }
+  if (cquantize^.needs_zeroed) then
+  begin
+    for i := 0 to pred(HIST_C0_ELEMS) do
+    begin
+      jzero_far( histogram^[i],
+    HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+    end;
+    cquantize^.needs_zeroed := FALSE;
+  end;
+end;
+
+
+{ Switch to a new external colormap between output passes. }
+
+{METHODDEF}
+procedure new_color_map_2_quant (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+begin
+  cquantize := my_cquantize_ptr (cinfo^.cquantize);
+
+  { Reset the inverse color map }
+  cquantize^.needs_zeroed := TRUE;
+end;
+
+
+{ Module initialization routine for 2-pass color quantization. }
+
+
+{GLOBAL}
+procedure jinit_2pass_quantizer (cinfo : j_decompress_ptr);
+var
+  cquantize : my_cquantize_ptr;
+  i : int;
+var
+  desired : int;
+begin
+  cquantize := my_cquantize_ptr(
+    cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
+        SIZEOF(my_cquantizer)));
+  cinfo^.cquantize := jpeg_color_quantizer_ptr(cquantize);
+  cquantize^.pub.start_pass := start_pass_2_quant;
+  cquantize^.pub.new_color_map := new_color_map_2_quant;
+  cquantize^.fserrors := NIL; { flag optional arrays not allocated }
+  cquantize^.error_limiter := NIL;
+
+  { Make sure jdmaster didn't give me a case I can't handle }
+  if (cinfo^.out_color_components <> 3) then
+    ERREXIT(j_common_ptr(cinfo), JERR_NOTIMPL);
+
+  { Allocate the histogram/inverse colormap storage }
+  cquantize^.histogram := hist3d (cinfo^.mem^.alloc_small
+    (j_common_ptr (cinfo), JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d)));
+  for i := 0 to pred(HIST_C0_ELEMS) do
+  begin
+    cquantize^.histogram^[i] := hist2d (cinfo^.mem^.alloc_large
+      (j_common_ptr (cinfo), JPOOL_IMAGE,
+       HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)));
+  end;
+  cquantize^.needs_zeroed := TRUE; { histogram is garbage now }
+
+  { Allocate storage for the completed colormap, if required.
+    We do this now since it is FAR storage and may affect
+    the memory manager's space calculations. }
+
+  if (cinfo^.enable_2pass_quant) then
+  begin
+    { Make sure color count is acceptable }
+    desired := cinfo^.desired_number_of_colors;
+    { Lower bound on # of colors ... somewhat arbitrary as long as > 0 }
+    if (desired < 8) then
+      ERREXIT1(j_common_ptr (cinfo), JERR_QUANT_FEW_COLORS, 8);
+    { Make sure colormap indexes can be represented by JSAMPLEs }
+    if (desired > MAXNUMCOLORS) then
+      ERREXIT1(j_common_ptr (cinfo), JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+    cquantize^.sv_colormap := cinfo^.mem^.alloc_sarray
+      (j_common_ptr (cinfo),JPOOL_IMAGE, JDIMENSION(desired), JDIMENSION(3));
+    cquantize^.desired := desired;
+  end
+  else
+    cquantize^.sv_colormap := NIL;
+
+  { Only F-S dithering or no dithering is supported. }
+  { If user asks for ordered dither, give him F-S. }
+  if (cinfo^.dither_mode <> JDITHER_NONE) then
+    cinfo^.dither_mode := JDITHER_FS;
+
+  { Allocate Floyd-Steinberg workspace if necessary.
+    This isn't really needed until pass 2, but again it is FAR storage.
+    Although we will cope with a later change in dither_mode,
+    we do not promise to honor max_memory_to_use if dither_mode changes. }
+
+  if (cinfo^.dither_mode = JDITHER_FS) then
+  begin
+    cquantize^.fserrors := FS_ERROR_FIELD_PTR (cinfo^.mem^.alloc_large
+      (j_common_ptr(cinfo), JPOOL_IMAGE,
+       size_t ((cinfo^.output_width + 2) * (3 * SIZEOF(FSERROR))) ) );
+    { Might as well create the error-limiting table too. }
+    init_error_limit(cinfo);
+  end;
+end;
+{ QUANT_2PASS_SUPPORTED }
+end.
diff --git a/src/lib/vampimg/JpegLib/imjutils.pas b/src/lib/vampimg/JpegLib/imjutils.pas
new file mode 100644 (file)
index 0000000..fc0eac7
--- /dev/null
@@ -0,0 +1,232 @@
+unit imjutils;
+
+{ This file contains tables and miscellaneous utility routines needed
+  for both compression and decompression.
+  Note we prefix all global names with "j" to minimize conflicts with
+  a surrounding application. }
+
+{ Source: jutils.c; Copyright (C) 1991-1996, Thomas G. Lane. }
+
+interface
+
+{$I imjconfig.inc}
+
+uses
+  imjmorecfg,
+  imjinclude,
+  imjpeglib;
+
+
+{ jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
+  of a DCT block read in natural order (left to right, top to bottom). }
+
+
+{$ifdef FALSE}      { This table is not actually needed in v6a }
+
+const
+  jpeg_zigzag_order : array[0..DCTSIZE2] of int =
+  (0,  1,  5,  6, 14, 15, 27, 28,
+   2,  4,  7, 13, 16, 26, 29, 42,
+   3,  8, 12, 17, 25, 30, 41, 43,
+   9, 11, 18, 24, 31, 40, 44, 53,
+  10, 19, 23, 32, 39, 45, 52, 54,
+  20, 22, 33, 38, 46, 51, 55, 60,
+  21, 34, 37, 47, 50, 56, 59, 61,
+  35, 36, 48, 49, 57, 58, 62, 63);
+
+{$endif}
+
+
+{ jpeg_natural_order[i] is the natural-order position of the i'th element
+  of zigzag order.
+
+  When reading corrupted data, the Huffman decoders could attempt
+  to reference an entry beyond the end of this array (if the decoded
+  zero run length reaches past the end of the block).  To prevent
+  wild stores without adding an inner-loop test, we put some extra
+  "63"s after the real entries.  This will cause the extra coefficient
+  to be stored in location 63 of the block, not somewhere random.
+  The worst case would be a run-length of 15, which means we need 16
+  fake entries. }
+
+
+const
+  jpeg_natural_order : array[0..DCTSIZE2+16-1] of int =
+ (0,  1,  8, 16,  9,  2,  3, 10,
+ 17, 24, 32, 25, 18, 11,  4,  5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13,  6,  7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, { extra entries for safety in decoder }
+ 63, 63, 63, 63, 63, 63, 63, 63);
+
+
+
+{ Arithmetic utilities }
+
+{GLOBAL}
+function jdiv_round_up (a : long; b : long) : long;
+
+{GLOBAL}
+function jround_up (a : long; b : long) : long;
+
+{GLOBAL}
+procedure jcopy_sample_rows (input_array : JSAMPARRAY;
+                             source_row : int;
+                             output_array : JSAMPARRAY; dest_row : int;
+                 num_rows : int; num_cols : JDIMENSION);
+
+{GLOBAL}
+procedure jcopy_block_row (input_row : JBLOCKROW;
+                           output_row : JBLOCKROW;
+                           num_blocks : JDIMENSION);
+
+{GLOBAL}
+procedure jzero_far (target : pointer;{far} bytestozero : size_t);
+
+procedure FMEMZERO(target : pointer; size : size_t);
+
+procedure FMEMCOPY(dest,src : pointer; size : size_t);
+
+implementation
+
+{GLOBAL}
+function jdiv_round_up (a : long; b : long) : long;
+{ Compute a/b rounded up to next integer, ie, ceil(a/b) }
+{ Assumes a >= 0, b > 0 }
+begin
+  jdiv_round_up := (a + b - long(1)) div b;
+end;
+
+
+{GLOBAL}
+function jround_up (a : long; b : long) : long;
+{ Compute a rounded up to next multiple of b, ie, ceil(a/b)*b }
+{ Assumes a >= 0, b > 0 }
+begin
+  Inc(a, b - long(1));
+  jround_up := a - (a mod b);
+end;
+
+{ On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
+  and coefficient-block arrays.  This won't work on 80x86 because the arrays
+  are FAR and we're assuming a small-pointer memory model.  However, some
+  DOS compilers provide far-pointer versions of memcpy() and memset() even
+  in the small-model libraries.  These will be used if USE_FMEM is defined.
+  Otherwise, the routines below do it the hard way.  (The performance cost
+  is not all that great, because these routines aren't very heavily used.) }
+
+
+{$ifndef NEED_FAR_POINTERS}      { normal case, same as regular macros }
+procedure FMEMZERO(target : pointer; size : size_t);
+begin
+  FillChar(target^, size, 0);
+end;
+
+procedure FMEMCOPY(dest,src : pointer; size : size_t);
+begin
+  Move(src^, dest^, size);
+end;
+
+
+{$else}                       { 80x86 case, define if we can }
+  {$ifdef USE_FMEM}
+   FMEMCOPY(dest,src,size)    _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))
+   FMEMZERO(target,size)      _fmemset((void FAR *)(target), 0, (size_t)(size))
+  {$endif}
+{$endif}
+
+
+{GLOBAL}
+procedure jcopy_sample_rows (input_array : JSAMPARRAY; source_row : int;
+                             output_array : JSAMPARRAY; dest_row : int;
+                 num_rows : int; num_cols : JDIMENSION);
+{ Copy some rows of samples from one place to another.
+  num_rows rows are copied from input_array[source_row++]
+  to output_array[dest_row++]; these areas may overlap for duplication.
+  The source and destination arrays must be at least as wide as num_cols. }
+var
+  inptr, outptr : JSAMPLE_PTR; {register}
+{$ifdef FMEMCOPY}
+  count : size_t; {register}
+{$else}
+  count : JDIMENSION; {register}
+{$endif}
+  row : int; {register}
+begin
+{$ifdef FMEMCOPY}
+  count := size_t(num_cols * SIZEOF(JSAMPLE));
+{$endif}
+  Inc(JSAMPROW_PTR(input_array), source_row);
+  Inc(JSAMPROW_PTR(output_array), dest_row);
+
+  for row := pred(num_rows) downto 0 do
+  begin
+    inptr := JSAMPLE_PTR(input_array^[0]);
+    Inc(JSAMPROW_PTR(input_array));
+    outptr := JSAMPLE_PTR(output_array^[0]);
+    Inc(JSAMPROW_PTR(output_array));
+{$ifdef FMEMCOPY}
+    FMEMCOPY(outptr, inptr, count);
+{$else}
+    for count := pred(num_cols) downto 0 do
+    begin
+      outptr^ := inptr^;        { needn't bother with GETJSAMPLE() here }
+      Inc(inptr);
+      Inc(outptr);
+    end;
+{$endif}
+  end;
+end;
+
+
+{GLOBAL}
+procedure jcopy_block_row (input_row : JBLOCKROW;
+                           output_row : JBLOCKROW;
+                           num_blocks : JDIMENSION);
+{ Copy a row of coefficient blocks from one place to another. }
+{$ifdef FMEMCOPY}
+begin
+  FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));
+{$else}
+var
+  inptr, outptr : JCOEFPTR; {register}
+  count : long; {register}
+begin
+  inptr := JCOEFPTR (input_row);
+  outptr := JCOEFPTR (output_row);
+  for count := long(num_blocks) * DCTSIZE2 -1 downto 0 do
+  begin
+    outptr^ := inptr^;
+    Inc(outptr);
+    Inc(inptr);
+  end;
+{$endif}
+end;
+
+
+{GLOBAL}
+procedure jzero_far (target : pointer;{far} bytestozero : size_t);
+{ Zero out a chunk of FAR memory. }
+{ This might be sample-array data, block-array data, or alloc_large data. }
+{$ifdef FMEMZERO}
+begin
+  FMEMZERO(target, bytestozero);
+{$else}
+var
+  ptr : byteptr;
+  count : size_t; {register}
+begin
+  ptr := target;
+  for count := bytestozero-1 downto 0 do
+  begin
+    ptr^ := 0;
+    Inc(ptr);
+  end;
+{$endif}
+end;
+
+end.
diff --git a/src/lib/vampimg/JpegLib/readme.txt b/src/lib/vampimg/JpegLib/readme.txt
new file mode 100644 (file)
index 0000000..6df345b
--- /dev/null
@@ -0,0 +1,381 @@
+_____________________________________________________________________________
+
+PASJPEG 1.1                                                   May 29th, 1999
+
+Based on the Independent JPEG Group's JPEG software release 6b
+
+Copyright (C) 1996,1998,1999 by NOMSSI NZALI Jacques H. C.
+[kn&n DES]         See "Legal issues" for conditions of distribution and use.
+_____________________________________________________________________________
+
+
+Information in this file
+========================
+
+  o Introduction
+  o Notes
+  o File list
+  o Translation
+  o Legal issues
+  o Archive Locations
+
+Introduction
+============
+
+PASJPEG is a port of the sixth public release of the IJG C source (release
+6b of 27-Mar-98) [3], that implements JPEG baseline, extended-sequential, and
+progressive compression processes to Turbo Pascal 7.0 for DOS (TP). The code
+has been tested under Delphi 3.0, it can be ported to other Pascal
+environments, since many compilers try to be compatible to TP.
+
+JPEG (pronounced "jay-peg") is a standardized familly of algorithms for
+compression of continous tone still images. Most JPEG processes are lossy,
+the output image is not exactly identical to the input image. However, on
+typical photographic images, very good compression levels can be obtained
+with no visible change, and remarkably high compression levels are possible
+if you can tolerate a low-quality image [1],[2]. The Independent JPEG Group
+(IJG) has created a free, portable C library for JPEG compression and
+decompression of JPEG images.
+
+The IJG documentation (system architecture, using the IJG JPEG library,
+usage and file list) is a must read. The files DEMO.PAS, TEST.PAS, CJPEG.PAS,
+DJPEG.PAS and EXAMPLE.PAS demonstrate the usage of the JPEG decompression
+and compression library. The RDJPGCOM application shows how to parse a JFIF
+file.
+
+Notes:
+======
+
+* Please report any errors/problems you may find in code and in the
+  documentation (e.g. this README.TXT file).
+
+* The sample applications (CJPEG, DJPEG) doesn't support all the options
+  of the original C code. WRJPGCOM is not ported.
+
+* Environment variable JPEGMEM syntax changed;
+
+* You can modify the jpeg.pas unit from the Delphi 3 distribution to
+  use PasJPEG.
+
+Change log
+==========
+
+1. bugs fixed:
+   * in procedure read_gif_map(), unit RDCOLMAP.PAS (used by DJPEG sample
+     application). Davie Lee Reed <smatters@iquest.net>
+   * -dct int and -dct fast now bytewise equal to the IJG output.
+   * -dct float produced large files
+
+2. Support for scripts
+
+3. BASM version of JIDCTINT.PAS for Delphi 2 and 3.
+
+4. images with integral sampling ratios were not decoded correctly.
+   Create a jpeg file with cjpeg and the option "-sample 4x1" and try to decode
+   it with any software that uses PasJpeg. Thanks to Jannie Gerber for reporting
+   this with a fix: In JDSAMPLE.PAS, procedure int_upsample(),
+
+    for h := pred(h_expand) downto 0 do
+    begin
+      outptr^ := invalue;
+ +=>  inc(outptr);   { this is the culprit that was left out!!! }
+      Dec(outcount);
+    end;
+
+File list
+=========
+
+Here is a road map to the files in the PasJPEG distribution.  The
+distribution includes the JPEG library proper, plus two application
+programs ("cjpeg" and "djpeg") which use the library to convert JPEG
+files to and from some other popular image formats.  A third application
+"jpegtran" uses the library to do lossless conversion between different
+variants of JPEG.  There is also the stand-alone applications "rdjpgcom".
+
+Documentation(see README for a guide to the documentation files):
+
+readme.txt      Introduction, Documentation
+
+Additional files
+
+demo.pas        Demo program, uses example.pas
+example.pas     Sample code for calling JPEG library.
+test.pas        Sample application code for demo.pas
+
+Configuration/installation files and programs (see install.doc for more info):
+
+jconfig.inc     Configuration declarations.
+
+*.ijg           script files
+
+Pascal source code files:
+
+jinclude.pas    Central include file used by all IJG .c files to reference
+    system include files.
+jpeglib.pas     JPEG library's internal data structures, exported data
+                and function declarations.
+jmorecfg.pas    Additional configuration declarations; need not be changed
+                for a standard installation.
+jdeferr.pas     defines the error and message text.
+jerror.pas      Declares JPEG library's error and trace message codes.
+jinclude.pas    the place to specify system depedent input/output code.
+jdct.pas        Private declarations for forward & reverse DCT subsystems.
+
+These files contain most of the functions intended to be called directly by
+an application program:
+
+jcapimin.pas    Application program interface: core routines for compression.
+jcapistd.pas    Application program interface: standard compression.
+jdapimin.pas    Application program interface: core routines for decompression.
+jdapistd.pas    Application program interface: standard decompression.
+jcomapi.pas     Application program interface routines common to compression
+                and decompression.
+jcparam.pas     Compression parameter setting helper routines.
+jctrans.pas     API and library routines for transcoding compression.
+jdtrans.pas     API and library routines for transcoding decompression.
+
+Compression side of the library:
+
+jcinit.pas      Initialization: determines which other modules to use.
+jcmaster.pas    Master control: setup and inter-pass sequencing logic.
+jcmainct.pas    Main buffer controller (preprocessor => JPEG compressor).
+jcprepct.pas    Preprocessor buffer controller.
+jccoefct.pas    Buffer controller for DCT coefficient buffer.
+jccolor.pas     Color space conversion.
+jcsample.pas    Downsampling.
+jcdctmgr.pas    DCT manager (DCT implementation selection & control).
+jfdctint.pas    Forward DCT using slow-but-accurate integer method.
+jfdctfst.pas    Forward DCT using faster, less accurate integer method.
+jfdctflt.pas    Forward DCT using floating-point arithmetic.
+jchuff.pas      Huffman entropy coding for sequential JPEG.
+jcphuff.pas     Huffman entropy coding for progressive JPEG.
+jcmarker.pas    JPEG marker writing.
+jdatadst.pas    Data destination manager for stdio output.
+
+Decompression side of the library:
+
+jdmaster.pas    Master control: determines which other modules to use.
+jdinput.pas     Input controller: controls input processing modules.
+jdmainct.pas    Main buffer controller (JPEG decompressor => postprocessor).
+jdcoefct.pas    Buffer controller for DCT coefficient buffer.
+jdpostct.pas    Postprocessor buffer controller.
+jdmarker.pas    JPEG marker reading.
+jdhuff.pas      Huffman entropy decoding for sequential JPEG.
+jdphuff.pas     Huffman entropy decoding for progressive JPEG.
+jddctmgr.pas    IDCT manager (IDCT implementation selection & control).
+jidctint.pas    Inverse DCT using slow-but-accurate integer method.
+jidctasm.pas    BASM specific version of jidctint.pas for 32bit Delphi.
+jidctfst.pas    Inverse DCT using faster, less accurate integer method.
+jidctflt.pas    Inverse DCT using floating-point arithmetic.
+jidctred.pas    Inverse DCTs with reduced-size outputs.
+jidct2d.pas     How to for a direct 2D Inverse DCT - not used
+jdsample.pas    Upsampling.
+jdcolor.pas     Color space conversion.
+jdmerge.pas     Merged upsampling/color conversion (faster, lower quality).
+jquant1.pas     One-pass color quantization using a fixed-spacing colormap.
+jquant2.pas     Two-pass color quantization using a custom-generated colormap.
+    Also handles one-pass quantization to an externally given map.
+jdatasrc.pas    Data source manager for stdio input.
+
+Support files for both compression and decompression:
+
+jerror.pas      Standard error handling routines (application replaceable).
+jmemmgr.pas     System-independent (more or less) memory management code.
+jutils.pas      Miscellaneous utility routines.
+
+jmemmgr.pas relies on a system-dependent memory management module.  The
+PASJPEG distribution includes the following implementations of the system-
+dependent module:
+
+jmemnobs.pas    "No backing store": assumes adequate virtual memory exists.
+jmemdos.pas     Custom implementation for MS-DOS (16-bit environment only):
+                can use extended and expanded memory as well as temporary
+                files.
+jmemsys.pas     A skeleton with all the declaration you need to create a
+                working system-dependent JPEG memory manager on unusual
+                systems.
+
+Exactly one of the system-dependent units should be used in jmemmgr.pas.
+
+jmemdosa.pas    BASM 80x86 assembly code support for jmemdos.pas; used only
+                in MS-DOS-specific configurations of the JPEG library.
+
+
+Applications using the library should use jmorecfg, jerror, jpeglib, and
+include jconfig.inc.
+
+CJPEG/DJPEG/JPEGTRAN
+
+Pascal source code files:
+
+cderror.pas     Additional error and trace message codes for cjpeg/djpeg.
+                Not used, Those errors have been added to jdeferr.
+cjpeg.pas       Main program for cjpeg.
+djpeg.pas       Main program for djpeg.
+jpegtran.pas    Main program for jpegtran.
+cdjpeg.pas      Utility routines used by all three programs.
+rdcolmap.pas    Code to read a colormap file for djpeg's "-map" switch.
+rdswitch.pas    Code to process some of cjpeg's more complex switches.
+                Also used by jpegtran.
+transupp.pas    Support code for jpegtran: lossless image manipulations.
+
+fcache.pas
+rdswitch.pas    Code to process some of cjpeg's more complex switches.
+                Also used by jpegtran.
+
+Image file writer modules for djpeg:
+
+wrbmp.pas       BMP file output.
+wrppm.pas PPM/PGM file output.
+wrtarga.pas     Targa file output.
+
+Image file reader modules for cjpeg:
+
+rdbmp.pas       BMP file input.
+rdppm.pas       PPM/PGM file input.
+rdtarga.pas     Targa file input. - NOT READY YET
+
+This program does not depend on the JPEG library
+
+rdjpgcom.pas  Stand-alone rdjpgcom application.
+
+
+Translation
+===========
+
+TP is unit-centric, exported type definitions and routines are declared
+in the "interface" part of the unit, "make" files are not needed.
+Macros are not supported, they were either copied as needed or translated
+to Pascal routines (procedure). The procedures will be replaced by code in
+later releases.
+Conditional defines that indicate whether to include various optional
+functions are defined in the file JCONFIG.INC. This file is included first
+in all source files.
+
+The base type definitions are in the unit JMORECFG.PAS. The error handling
+macros have been converted to procedures in JERROR.PAS. The error codes are
+in JDEFERR.PAS. jpegint.h and jpeglib.h were merged into one large unit
+JPEGLIB.PAS containing type definitions with global scope.
+
+The translation of the header file is the most sophisticated work, a good
+understanding of the syntax is required. Once the header files are done,
+the translation turns into a lot of editing work. Each C source file was
+converted to a unit by editing the syntax (separate variable definition
+and usage, define labels, group variable definitions, expanding macros, etc).
+
+The IJG source labels routines GLOBAL, METHODDEF and LOCAL. All globals
+routines are in the interface section of the units. The "far" directive is
+used for methods (METHODDEF).
+
+Some C  ->  Pascal  examples.
+
+* "{"  -> "begin"    "->"  ->  "^."        " = "  -> " := "  "<<"  -> " shl "
+  "}"  -> "end;"     "!="  ->  "<>"        " == " -> " = "   ">>"  -> " shr "
+  "/*" -> "{"      routine ->  function    "0x"   -> "$"
+  "*/" -> "}"      (void)      procedure   "NULL" -> "NIL"
+
+* structs are records, Unions are variable records, pointers are always far,
+  the operators && and || (and/or) have not the same priority in both
+  languages, so parenthesis are important. The Pascal "case" doesn't have the
+  falltrough option of the C "switch" statement, my work around is to split
+  one "switch" statement into many case statements.
+* The pointer type in C is not readily interchangeable. It is used to address
+  an array (Pascal pointer to an array) or in pointer arithmetic a pointer to
+  a single element. I've used the Inc() statement with type casting to
+  translate pointer arithmetic most of the time.
+
+  C example:
+    typedef JSAMPLE* JSAMPROW;  /* ptr to one image row of pixel samples. */
+
+  Pascal
+  type
+    JSAMPLE_PTR = ^JSAMPLE;     { ptr to a single pixel sample. }
+    jTSample = 0..(MaxInt div SIZEOF(JSAMPLE))-1;
+    JSAMPLE_ARRAY = Array[jTSample] of JSAMPLE;  {far}
+    JSAMPROW = ^JSAMPLE_ARRAY;  { ptr to one image row of pixel samples. }
+
+  The following code
+
+    JSAMPROW buffer0, buffer1;  /* ptr to a JSAMPLE buffer. */
+
+    ...
+
+    buffer1 = buffer0 + i;
+
+  can be translated to
+
+  var
+    buffer0, buffer1 : JSAMPROW;
+
+  ...
+
+    buffer1 := buffer0;
+    Inc(JSAMPLE_PTR(buffer1), i);
+
+  or
+
+    buffer1 := JSAMPROW(@ buffer0^[i]);
+
+  Declaring the variables as JSAMPLE_PTR may reduce type casting in some
+  places. I use help pointers to handle negative array offsets.
+
+While translating the type of function parameter from C to Pascal, one can
+often use "var", "const", or "array of" parameters instead of pointers.
+
+While translating for(;;)-loops with more than one induction variable to
+Pascal "for to/downto do"-loops, the extra induction variables have to be
+manually updated at the end of the loop and before "continue"-statements.
+
+
+Legal issues
+============
+
+Copyright (C) 1996,1998 by Jacques Nomssi Nzali
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the author be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+
+Archive Locations:
+==================
+
+[1] Thomas G. Lane, JPEG FAQ
+
+      in comp.graphics.misc and related newsgroups
+
+[2] Wallace, Gregory K.: The JPEG Still Picture Compression Standard
+
+      ftp.uu.net, graphics/jpeg/wallace.ps.Z
+
+[3] The Independent JPEG Group C library for JPEG encoding and decoding,
+    rev 6b.
+
+      ftp://ftp.uu.net/graphics/jpeg/
+
+      or SimTel in msdos/graphics/
+
+[4] JPEG implementation, written by the PVRG group at Stanford,
+      ftp havefun.stanford.edu:/pub/jpeg/JPEGv1.2.tar.Z.
+
+[5] PASJPEG.ZIP at NView ftp site
+
+      ftp://druckfix.physik.tu-chemnitz.de/pub/nv/
+      http://www.tu-chemnitz.de/~nomssi/pub/pasjpeg.zip
+
+[6] The PasJPEG home page with links
+
+      http://www.tu-chemnitz.de/~nomssi/pasjpeg.html
+_____________________________________________________________________________
diff --git a/src/lib/vampimg/ZLib/dzlib.pas b/src/lib/vampimg/ZLib/dzlib.pas
new file mode 100644 (file)
index 0000000..05e278d
--- /dev/null
@@ -0,0 +1,523 @@
+{*******************************************************}
+{                                                       }
+{       Delphi Supplemental Components                  }
+{       ZLIB Data Compression Interface Unit            }
+{                                                       }
+{       Copyright (c) 1997 Borland International        }
+{       Copyright (c) 1998 Jacques Nomssi Nzali         }
+{                                                       }
+{*******************************************************}
+
+{
+  Modified for
+  Vampyre Imaging Library
+  by Marek Mauder
+  http://imaginglib.sourceforge.net
+
+  You can choose which pascal zlib implementation will be
+  used. IMPASZLIB and FPCPASZLIB are translations of zlib
+  to pascal so they don't need any *.obj files.
+  The others are interfaces to *.obj files (Windows) or
+  *.so libraries (Linux).
+    Default implementation is IMPASZLIB because it can be compiled
+  by all supported compilers and works on all supported platforms.
+  I usually use implementation with the fastest decompression
+  when building release Win32 binaries.
+    FPCPASZLIB is useful for Lazarus applications. FPC's zlib is linked
+  to exe by default so there is no need to link additional (and almost identical)
+  IMPASZLIB.
+
+  There is a small speed comparison table of some of the
+  supported implementations (TGA image 28 311 570 bytes, compression level = 6,
+  Delphi 9, Win32, Athlon XP 1900).
+
+                 ZLib version Decompression  Compression   Comp. Size
+  IMPASZLIB     |   1.1.2   |    824 ms    |  4 280 ms  |  18 760 133 B
+  ZLIBEX        |   1.2.2   |    710 ms    |  1 590 ms* |  19 056 621 B
+  DELPHIZLIB    |   1.0.4   |    976 ms    |  9 190 ms  |  18 365 562 B
+  ZLIBPAS       |   1.2.3   |    680 ms    |  3 790  ms |  18 365 387 B
+    * obj files are compiled with compression level hardcoded to 1 (fastest)
+}
+
+unit dzlib;
+
+{$I ImagingOptions.inc}
+
+interface
+
+{$DEFINE IMPASZLIB}
+{ $DEFINE ZLIBPAS}
+{ $DEFINE FPCPASZLIB}
+{ $DEFINE ZLIBEX}
+{ $DEFINE DELPHIZLIB}
+
+{ Automatically use FPC's PasZLib when compiling with FPC.}
+
+{$IFDEF FPC}
+  {$UNDEF IMPASZLIB}
+  {$DEFINE FPCPASZLIB}
+{$ENDIF}
+
+uses
+{$IF Defined(IMPASZLIB)}
+  { Use paszlib modified by me for Delphi and FPC }
+  imzdeflate, imzinflate, impaszlib,
+{$ELSEIF Defined(FPCPASZLIB)}
+  { Use FPC's paszlib }
+  zbase, paszlib,
+{$ELSEIF Defined(ZLIBPAS)}
+  { Pascal interface to ZLib shipped with ZLib C source }
+  zlibpas,
+{$ELSEIF Defined(ZLIBEX)}
+  { Use ZlibEx unit }
+  ZLibEx,
+{$ELSEIF Defined(DELPHIZLIB)}
+  { Use ZLib unit shipped with Delphi }
+  ZLib,
+{$IFEND}
+  ImagingTypes, SysUtils, Classes;
+
+{$IF Defined(IMPASZLIB) or Defined(FPCPASZLIB) or Defined(ZLIBPAS)}
+type
+  TZStreamRec = z_stream;
+{$IFEND}
+
+const
+  Z_NO_FLUSH      = 0;
+  Z_PARTIAL_FLUSH = 1;
+  Z_SYNC_FLUSH    = 2;
+  Z_FULL_FLUSH    = 3;
+  Z_FINISH        = 4;
+
+  Z_OK            =  0;
+  Z_STREAM_END    =  1;
+  Z_NEED_DICT     =  2;
+  Z_ERRNO         = -1;
+  Z_STREAM_ERROR  = -2;
+  Z_DATA_ERROR    = -3;
+  Z_MEM_ERROR     = -4;
+  Z_BUF_ERROR     = -5;
+  Z_VERSION_ERROR = -6;
+
+  Z_NO_COMPRESSION       =  0;
+  Z_BEST_SPEED           =  1;
+  Z_BEST_COMPRESSION     =  9;
+  Z_DEFAULT_COMPRESSION  = -1;
+
+  Z_FILTERED            = 1;
+  Z_HUFFMAN_ONLY        = 2;
+  Z_RLE                 = 3;
+  Z_DEFAULT_STRATEGY    = 0;
+
+  Z_BINARY   = 0;
+  Z_ASCII    = 1;
+  Z_UNKNOWN  = 2;
+
+  Z_DEFLATED = 8;
+
+type
+  { Abstract ancestor class }
+  TCustomZlibStream = class(TStream)
+  private
+    FStrm: TStream;
+    FStrmPos: Integer;
+    FOnProgress: TNotifyEvent;
+    FZRec: TZStreamRec;
+    FBuffer: array [Word] of Byte;
+  protected
+    procedure Progress(Sender: TObject); dynamic;
+    property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
+    constructor Create(Strm: TStream);
+  end;
+
+{ TCompressionStream compresses data on the fly as data is written to it, and
+  stores the compressed data to another stream.
+
+  TCompressionStream is write-only and strictly sequential. Reading from the
+  stream will raise an exception. Using Seek to move the stream pointer
+  will raise an exception.
+
+  Output data is cached internally, written to the output stream only when
+  the internal output buffer is full.  All pending output data is flushed
+  when the stream is destroyed.
+
+  The Position property returns the number of uncompressed bytes of
+  data that have been written to the stream so far.
+
+  CompressionRate returns the on-the-fly percentage by which the original
+  data has been compressed:  (1 - (CompressedBytes / UncompressedBytes)) * 100
+  If raw data size = 100 and compressed data size = 25, the CompressionRate
+  is 75%
+
+  The OnProgress event is called each time the output buffer is filled and
+  written to the output stream.  This is useful for updating a progress
+  indicator when you are writing a large chunk of data to the compression
+  stream in a single call.}
+
+
+  TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+  TCompressionStream = class(TCustomZlibStream)
+  private
+    function GetCompressionRate: Single;
+  public
+    constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    property CompressionRate: Single read GetCompressionRate;
+    property OnProgress;
+  end;
+
+{ TDecompressionStream decompresses data on the fly as data is read from it.
+
+  Compressed data comes from a separate source stream.  TDecompressionStream
+  is read-only and unidirectional; you can seek forward in the stream, but not
+  backwards.  The special case of setting the stream position to zero is
+  allowed.  Seeking forward decompresses data until the requested position in
+  the uncompressed data has been reached.  Seeking backwards, seeking relative
+  to the end of the stream, requesting the size of the stream, and writing to
+  the stream will raise an exception.
+
+  The Position property returns the number of bytes of uncompressed data that
+  have been read from the stream so far.
+
+  The OnProgress event is called each time the internal input buffer of
+  compressed data is exhausted and the next block is read from the input stream.
+  This is useful for updating a progress indicator when you are reading a
+  large chunk of data from the decompression stream in a single call.}
+
+  TDecompressionStream = class(TCustomZlibStream)
+  public
+    constructor Create(Source: TStream);
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    property OnProgress;
+  end;
+
+
+
+{ CompressBuf compresses data, buffer to buffer, in one call.
+   In: InBuf = ptr to compressed data
+       InBytes = number of bytes in InBuf
+  Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+       OutBytes = number of bytes in OutBuf   }
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+  var OutBuf: Pointer; var OutBytes: Integer;
+  CompressLevel: Integer = Z_DEFAULT_COMPRESSION;
+  CompressStrategy: Integer = Z_DEFAULT_STRATEGY);
+
+{ DecompressBuf decompresses data, buffer to buffer, in one call.
+   In: InBuf = ptr to compressed data
+       InBytes = number of bytes in InBuf
+       OutEstimate = zero, or est. size of the decompressed data
+  Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+       OutBytes = number of bytes in OutBuf   }
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer);
+
+
+type
+  EZlibError = class(Exception);
+  ECompressionError = class(EZlibError);
+  EDecompressionError = class(EZlibError);
+
+implementation
+
+const
+  ZErrorMessages: array[0..9] of PAnsiChar = (
+    'need dictionary',        // Z_NEED_DICT      (2)
+    'stream end',             // Z_STREAM_END     (1)
+    '',                       // Z_OK             (0)
+    'file error',             // Z_ERRNO          (-1)
+    'stream error',           // Z_STREAM_ERROR   (-2)
+    'data error',             // Z_DATA_ERROR     (-3)
+    'insufficient memory',    // Z_MEM_ERROR      (-4)
+    'buffer error',           // Z_BUF_ERROR      (-5)
+    'incompatible version',   // Z_VERSION_ERROR  (-6)
+    '');
+
+function zlibAllocMem(AppData: Pointer; Items, Size: Cardinal): Pointer;
+begin
+  GetMem(Result, Items*Size);
+end;
+
+procedure zlibFreeMem(AppData, Block: Pointer);
+begin
+  FreeMem(Block);
+end;
+
+function CCheck(code: Integer): Integer;
+begin
+  Result := code;
+  if code < 0 then
+    raise ECompressionError.Create('zlib: ' + ZErrorMessages[2 - code]);
+end;
+
+function DCheck(code: Integer): Integer;
+begin
+  Result := code;
+  if code < 0 then
+    raise EDecompressionError.Create('zlib: ' + ZErrorMessages[2 - code]);
+end;
+
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+  var OutBuf: Pointer; var OutBytes: Integer;
+  CompressLevel, CompressStrategy: Integer);
+var
+  strm: TZStreamRec;
+  P: Pointer;
+begin
+  FillChar(strm, sizeof(strm), 0);
+{$IFNDEF FPCPASZLIB}
+  strm.zalloc := @zlibAllocMem;
+  strm.zfree := @zlibFreeMem;
+{$ENDIF}
+  OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
+  GetMem(OutBuf, OutBytes);
+  try
+    strm.next_in := InBuf;
+    strm.avail_in := InBytes;
+    strm.next_out := OutBuf;
+    strm.avail_out := OutBytes;
+
+    CCheck(deflateInit2(strm, CompressLevel, Z_DEFLATED, MAX_WBITS,
+      DEF_MEM_LEVEL, CompressStrategy));
+
+    try
+      while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
+      begin
+        P := OutBuf;
+        Inc(OutBytes, 256);
+        ReallocMem(OutBuf, OutBytes);
+        strm.next_out := Pointer(PtrUInt(OutBuf) + (PtrUInt(strm.next_out) - PtrUInt(P)));
+        strm.avail_out := 256;
+      end;
+    finally
+      CCheck(deflateEnd(strm));
+    end;
+    ReallocMem(OutBuf, strm.total_out);
+    OutBytes := strm.total_out;
+  except
+    zlibFreeMem(nil, OutBuf);
+    raise
+  end;
+end;
+
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer);
+var
+  strm: TZStreamRec;
+  P: Pointer;
+  BufInc: Integer;
+begin
+  FillChar(strm, sizeof(strm), 0);
+{$IFNDEF FPCPASZLIB}
+  strm.zalloc := @zlibAllocMem;
+  strm.zfree := @zlibFreeMem;
+{$ENDIF}
+  BufInc := (InBytes + 255) and not 255;
+  if OutEstimate = 0 then
+    OutBytes := BufInc
+  else
+    OutBytes := OutEstimate;
+  GetMem(OutBuf, OutBytes);
+  try
+    strm.next_in := InBuf;
+    strm.avail_in := InBytes;
+    strm.next_out := OutBuf;
+    strm.avail_out := OutBytes;
+    DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
+    try
+      while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do
+      begin
+        P := OutBuf;
+        Inc(OutBytes, BufInc);
+        ReallocMem(OutBuf, OutBytes);
+        strm.next_out := Pointer(PtrUInt(OutBuf) + (PtrUInt(strm.next_out) - PtrUInt(P)));
+        strm.avail_out := BufInc;
+      end;
+    finally
+      DCheck(inflateEnd(strm));
+    end;
+    ReallocMem(OutBuf, strm.total_out);
+    OutBytes := strm.total_out;
+  except
+    zlibFreeMem(nil, OutBuf);
+    raise
+  end;
+end;
+
+
+{ TCustomZlibStream }
+
+constructor TCustomZLibStream.Create(Strm: TStream);
+begin
+  inherited Create;
+  FStrm := Strm;
+  FStrmPos := Strm.Position;
+{$IFNDEF FPCPASZLIB}
+  FZRec.zalloc := @zlibAllocMem;
+  FZRec.zfree := @zlibFreeMem;
+{$ENDIF}
+end;
+
+procedure TCustomZLibStream.Progress(Sender: TObject);
+begin
+  if Assigned(FOnProgress) then FOnProgress(Sender);
+end;
+
+{ TCompressionStream }
+
+constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
+  Dest: TStream);
+const
+  Levels: array [TCompressionLevel] of ShortInt =
+    (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
+begin
+  inherited Create(Dest);
+  FZRec.next_out := @FBuffer;
+  FZRec.avail_out := sizeof(FBuffer);
+  CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
+end;
+
+destructor TCompressionStream.Destroy;
+begin
+  FZRec.next_in := nil;
+  FZRec.avail_in := 0;
+  try
+    if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+    while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
+      and (FZRec.avail_out = 0) do
+    begin
+      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+      FZRec.next_out := @FBuffer;
+      FZRec.avail_out := sizeof(FBuffer);
+    end;
+    if FZRec.avail_out < sizeof(FBuffer) then
+      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
+  finally
+    deflateEnd(FZRec);
+  end;
+  inherited Destroy;
+end;
+
+function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+  raise ECompressionError.Create('Invalid stream operation');
+end;
+
+function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+  FZRec.next_in := @Buffer;
+  FZRec.avail_in := Count;
+  if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+  while (FZRec.avail_in > 0) do
+  begin
+    CCheck(deflate(FZRec, 0));
+    if FZRec.avail_out = 0 then
+    begin
+      FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+      FZRec.next_out := @FBuffer;
+      FZRec.avail_out := sizeof(FBuffer);
+      FStrmPos := FStrm.Position;
+      Progress(Self);
+    end;
+  end;
+  Result := Count;
+end;
+
+function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+  if (Offset = 0) and (Origin = soFromCurrent) then
+    Result := FZRec.total_in
+  else
+    raise ECompressionError.Create('Invalid stream operation');
+end;
+
+function TCompressionStream.GetCompressionRate: Single;
+begin
+  if FZRec.total_in = 0 then
+    Result := 0
+  else
+    Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
+end;
+
+{ TDecompressionStream }
+
+constructor TDecompressionStream.Create(Source: TStream);
+begin
+  inherited Create(Source);
+  FZRec.next_in := @FBuffer;
+  FZRec.avail_in := 0;
+  DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
+end;
+
+destructor TDecompressionStream.Destroy;
+begin
+  inflateEnd(FZRec);
+  inherited Destroy;
+end;
+
+function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+  FZRec.next_out := @Buffer;
+  FZRec.avail_out := Count;
+  if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+  while (FZRec.avail_out > 0) do
+  begin
+    if FZRec.avail_in = 0 then
+    begin
+      FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
+      if FZRec.avail_in = 0 then
+        begin
+          Result := Count - Integer(FZRec.avail_out);
+          Exit;
+        end;
+      FZRec.next_in := @FBuffer;
+      FStrmPos := FStrm.Position;
+      Progress(Self);
+    end;
+    CCheck(inflate(FZRec, 0));
+  end;
+  Result := Count;
+end;
+
+function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+  raise EDecompressionError.Create('Invalid stream operation');
+end;
+
+function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+  I: Integer;
+  Buf: array [0..4095] of Byte;
+begin
+  if (Offset = 0) and (Origin = soFromBeginning) then
+  begin
+    DCheck(inflateReset(FZRec));
+    FZRec.next_in := @FBuffer;
+    FZRec.avail_in := 0;
+    FStrm.Position := 0;
+    FStrmPos := 0;
+  end
+  else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
+          ( ((Offset - Integer(FZRec.total_out)) > 0) and (Origin = soFromBeginning)) then
+  begin
+    if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
+    if Offset > 0 then
+    begin
+      for I := 1 to Offset div sizeof(Buf) do
+        ReadBuffer(Buf, sizeof(Buf));
+      ReadBuffer(Buf, Offset mod sizeof(Buf));
+    end;
+  end
+  else
+    raise EDecompressionError.Create('Invalid stream operation');
+  Result := FZRec.total_out;
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/imadler.pas b/src/lib/vampimg/ZLib/imadler.pas
new file mode 100644 (file)
index 0000000..ff769a2
--- /dev/null
@@ -0,0 +1,113 @@
+Unit imadler;
+
+{
+  adler32.c -- compute the Adler-32 checksum of a data stream
+  Copyright (C) 1995-1998 Mark Adler
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  imzutil;
+
+function adler32(adler : uLong; buf : pBytef; len : uInt) : uLong;
+
+{    Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NIL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+   var
+     adler : uLong;
+   begin
+     adler := adler32(0, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) <> EOF) do
+       adler := adler32(adler, buffer, length);
+
+     if (adler <> original_adler) then
+       error();
+   end;
+}
+
+implementation
+
+const
+  BASE = uLong(65521); { largest prime smaller than 65536 }
+  {NMAX = 5552; original code with unsigned 32 bit integer }
+  { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 }
+  NMAX = 3854;        { code with signed 32 bit integer }
+  { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 }
+  { The penalty is the time loss in the extra MOD-calls. }
+
+
+{ ========================================================================= }
+
+function adler32(adler : uLong; buf : pBytef; len : uInt) : uLong;
+var
+  s1, s2 : uLong;
+  k : int;
+begin
+  s1 := adler and $ffff;
+  s2 := (adler shr 16) and $ffff;
+
+  if not Assigned(buf) then
+  begin
+    adler32 := uLong(1);
+    exit;
+  end;
+
+  while (len > 0) do
+  begin
+    if len < NMAX then
+      k := len
+    else
+      k := NMAX;
+    Dec(len, k);
+    {
+    while (k >= 16) do
+    begin
+      DO16(buf);
+      Inc(buf, 16);
+      Dec(k, 16);
+    end;
+    if (k <> 0) then
+    repeat
+      Inc(s1, buf^);
+      Inc(puf);
+      Inc(s2, s1);
+      Dec(k);
+    until (k = 0);
+    }
+    while (k > 0) do
+    begin
+      Inc(s1, buf^);
+      Inc(s2, s1);
+      Inc(buf);
+      Dec(k);
+    end;
+    s1 := s1 mod BASE;
+    s2 := s2 mod BASE;
+  end;
+  adler32 := (s2 shl 16) or s1;
+end;
+
+{
+#define DO1(buf,i)
+  begin
+    Inc(s1, buf[i]);
+    Inc(s2, s1);
+  end;
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+}
+end.
diff --git a/src/lib/vampimg/ZLib/iminfblock.pas b/src/lib/vampimg/ZLib/iminfblock.pas
new file mode 100644 (file)
index 0000000..413e9b6
--- /dev/null
@@ -0,0 +1,951 @@
+Unit iminfblock;
+
+{ infblock.h and
+  infblock.c -- interpret and process block types to last block
+  Copyright (C) 1995-1998 Mark Adler
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  {$IFDEF DEBUG}
+  SysUtils, strutils,
+  {$ENDIF}
+  imzutil, impaszlib;
+
+function inflate_blocks_new(var z : z_stream;
+                            c : check_func;  { check function }
+                            w : uInt     { window size }
+                            ) : pInflate_blocks_state;
+
+function inflate_blocks (var s : inflate_blocks_state;
+                         var z : z_stream;
+                         r : int             { initial return code }
+                         ) : int;
+
+procedure inflate_blocks_reset (var s : inflate_blocks_state;
+                                var z : z_stream;
+                                c : puLong); { check value on output }
+
+
+function inflate_blocks_free(s : pInflate_blocks_state;
+                             var z : z_stream) : int;
+
+procedure inflate_set_dictionary(var s : inflate_blocks_state;
+                                 const d : array of byte;  { dictionary }
+                                 n : uInt);         { dictionary length }
+
+function inflate_blocks_sync_point(var s : inflate_blocks_state) : int;
+
+implementation
+
+uses
+  iminfcodes, iminftrees, iminfutil;
+
+{ Tables for deflate from PKZIP's appnote.txt. }
+Const
+  border : Array [0..18] Of Word  { Order of the bit length code lengths }
+    = (16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
+
+{ Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths. }
+
+
+procedure inflate_blocks_reset (var s : inflate_blocks_state;
+                                var z : z_stream;
+                                c : puLong); { check value on output }
+begin
+  if (c <> Z_NULL) then
+    c^ := s.check;
+  if (s.mode = BTREE) or (s.mode = DTREE) then
+    ZFREE(z, s.sub.trees.blens);
+  if (s.mode = CODES) then
+    inflate_codes_free(s.sub.decode.codes, z);
+
+  s.mode := ZTYPE;
+  s.bitk := 0;
+  s.bitb := 0;
+
+  s.write := s.window;
+  s.read := s.window;
+  if Assigned(s.checkfn) then
+  begin
+    s.check := s.checkfn(uLong(0), pBytef(NIL), 0);
+    z.adler := s.check;
+  end;
+  {$IFDEF DEBUG}
+  Tracev('inflate:   blocks reset');
+  {$ENDIF}
+end;
+
+
+function inflate_blocks_new(var z : z_stream;
+                            c : check_func;  { check function }
+                            w : uInt         { window size }
+                            ) : pInflate_blocks_state;
+var
+  s : pInflate_blocks_state;
+begin
+  s := pInflate_blocks_state( ZALLOC(z,1, sizeof(inflate_blocks_state)) );
+  if (s = Z_NULL) then
+  begin
+    inflate_blocks_new := s;
+    exit;
+  end;
+  s^.hufts := huft_ptr( ZALLOC(z, sizeof(inflate_huft), MANY) );
+
+  if (s^.hufts = Z_NULL) then
+  begin
+    ZFREE(z, s);
+    inflate_blocks_new := Z_NULL;
+    exit;
+  end;
+
+  s^.window := pBytef( ZALLOC(z, 1, w) );
+  if (s^.window = Z_NULL) then
+  begin
+    ZFREE(z, s^.hufts);
+    ZFREE(z, s);
+    inflate_blocks_new := Z_NULL;
+    exit;
+  end;
+  s^.zend := s^.window;
+  Inc(s^.zend, w);
+  s^.checkfn := c;
+  s^.mode := ZTYPE;
+  {$IFDEF DEBUG}
+  Tracev('inflate:   blocks allocated');
+  {$ENDIF}
+  inflate_blocks_reset(s^, z, Z_NULL);
+  inflate_blocks_new := s;
+end;
+
+
+function inflate_blocks (var s : inflate_blocks_state;
+                         var z : z_stream;
+                         r : int) : int;           { initial return code }
+label
+  start_btree, start_dtree,
+  start_blkdone, start_dry,
+  start_codes;
+
+var
+  t : uInt;               { temporary storage }
+  b : uLong;              { bit buffer }
+  k : uInt;               { bits in bit buffer }
+  p : pBytef;             { input data pointer }
+  n : uInt;               { bytes available there }
+  q : pBytef;             { output window write pointer }
+  m : uInt;               { bytes to end of window or read pointer }
+{ fixed code blocks }
+var
+  bl, bd : uInt;
+  tl, td : pInflate_huft;
+var
+  h : pInflate_huft;
+  i, j, c : uInt;
+var
+  cs : pInflate_codes_state;
+begin
+  { copy input/output information to locals }
+  p := z.next_in;
+  n := z.avail_in;
+  b := s.bitb;
+  k := s.bitk;
+  q := s.write;
+  if ptr2int(q) < ptr2int(s.read) then
+    m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+  else
+    m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+{ decompress an inflated block }
+
+
+  { process input based on current state }
+  while True do
+  Case s.mode of
+    ZTYPE:
+      begin
+        {NEEDBITS(3);}
+        while (k < 3) do
+        begin
+          {NEEDBYTE;}
+          if (n <> 0) then
+            r :=Z_OK
+          else
+          begin
+            {UPDATE}
+            s.bitb := b;
+            s.bitk := k;
+            z.avail_in := n;
+            Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+            z.next_in := p;
+            s.write := q;
+            inflate_blocks := inflate_flush(s,z,r);
+            exit;
+          end;
+          Dec(n);
+          b := b or (uLong(p^) shl k);
+          Inc(p);
+          Inc(k, 8);
+        end;
+
+        t := uInt(b) and 7;
+        s.last := boolean(t and 1);
+        case (t shr 1) of
+          0:                         { stored }
+            begin
+              {$IFDEF DEBUG}
+              if s.last then
+                Tracev('inflate:     stored block (last)')
+              else
+                Tracev('inflate:     stored block');
+              {$ENDIF}
+              {DUMPBITS(3);}
+              b := b shr 3;
+              Dec(k, 3);
+
+              t := k and 7;                  { go to byte boundary }
+              {DUMPBITS(t);}
+              b := b shr t;
+              Dec(k, t);
+
+              s.mode := LENS;                { get length of stored block }
+            end;
+          1:                         { fixed }
+            begin
+              begin
+                {$IFDEF DEBUG}
+                if s.last then
+                  Tracev('inflate:     fixed codes blocks (last)')
+                else
+                  Tracev('inflate:     fixed codes blocks');
+                {$ENDIF}
+                inflate_trees_fixed(bl, bd, tl, td, z);
+                s.sub.decode.codes := inflate_codes_new(bl, bd, tl, td, z);
+                if (s.sub.decode.codes = Z_NULL) then
+                begin
+                  r := Z_MEM_ERROR;
+                  { update pointers and return }
+                  s.bitb := b;
+                  s.bitk := k;
+                  z.avail_in := n;
+                  Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+                  z.next_in := p;
+                  s.write := q;
+                  inflate_blocks := inflate_flush(s,z,r);
+                  exit;
+                end;
+              end;
+              {DUMPBITS(3);}
+              b := b shr 3;
+              Dec(k, 3);
+
+              s.mode := CODES;
+            end;
+          2:                         { dynamic }
+            begin
+              {$IFDEF DEBUG}
+              if s.last then
+                Tracev('inflate:     dynamic codes block (last)')
+              else
+                Tracev('inflate:     dynamic codes block');
+              {$ENDIF}
+              {DUMPBITS(3);}
+              b := b shr 3;
+              Dec(k, 3);
+
+              s.mode := TABLE;
+            end;
+          3:
+            begin                   { illegal }
+              {DUMPBITS(3);}
+              b := b shr 3;
+              Dec(k, 3);
+
+              s.mode := BLKBAD;
+              z.msg := 'invalid block type';
+              r := Z_DATA_ERROR;
+              { update pointers and return }
+              s.bitb := b;
+              s.bitk := k;
+              z.avail_in := n;
+              Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+              z.next_in := p;
+              s.write := q;
+              inflate_blocks := inflate_flush(s,z,r);
+              exit;
+            end;
+        end;
+      end;
+    LENS:
+      begin
+        {NEEDBITS(32);}
+        while (k < 32) do
+        begin
+          {NEEDBYTE;}
+          if (n <> 0) then
+            r :=Z_OK
+          else
+          begin
+            {UPDATE}
+            s.bitb := b;
+            s.bitk := k;
+            z.avail_in := n;
+            Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+            z.next_in := p;
+            s.write := q;
+            inflate_blocks := inflate_flush(s,z,r);
+            exit;
+          end;
+          Dec(n);
+          b := b or (uLong(p^) shl k);
+          Inc(p);
+          Inc(k, 8);
+        end;
+
+        if (((not b) shr 16) and $ffff) <> (b and $ffff) then
+        begin
+          s.mode := BLKBAD;
+          z.msg := 'invalid stored block lengths';
+          r := Z_DATA_ERROR;
+          { update pointers and return }
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_blocks := inflate_flush(s,z,r);
+          exit;
+        end;
+        s.sub.left := uInt(b) and $ffff;
+        k := 0;
+        b := 0;                      { dump bits }
+        {$IFDEF DEBUG}
+        Tracev('inflate:       stored length '+IntToStr(s.sub.left));
+        {$ENDIF}
+        if s.sub.left <> 0 then
+          s.mode := STORED
+        else
+          if s.last then
+            s.mode := DRY
+          else
+            s.mode := ZTYPE;
+      end;
+    STORED:
+      begin
+        if (n = 0) then
+        begin
+          { update pointers and return }
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_blocks := inflate_flush(s,z,r);
+          exit;
+        end;
+        {NEEDOUT}
+        if (m = 0) then
+        begin
+          {WRAP}
+          if (q = s.zend) and (s.read <> s.window) then
+          begin
+            q := s.window;
+            if ptr2int(q) < ptr2int(s.read) then
+              m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+            else
+              m := uInt(ptr2int(s.zend)-ptr2int(q));
+          end;
+
+          if (m = 0) then
+          begin
+            {FLUSH}
+            s.write := q;
+            r := inflate_flush(s,z,r);
+            q := s.write;
+            if ptr2int(q) < ptr2int(s.read) then
+              m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+            else
+              m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+            {WRAP}
+            if (q = s.zend) and (s.read <> s.window) then
+            begin
+              q := s.window;
+              if ptr2int(q) < ptr2int(s.read) then
+                m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+              else
+                m := uInt(ptr2int(s.zend)-ptr2int(q));
+            end;
+
+            if (m = 0) then
+            begin
+              {UPDATE}
+              s.bitb := b;
+              s.bitk := k;
+              z.avail_in := n;
+              Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+              z.next_in := p;
+              s.write := q;
+              inflate_blocks := inflate_flush(s,z,r);
+              exit;
+            end;
+          end;
+        end;
+        r := Z_OK;
+
+        t := s.sub.left;
+        if (t > n) then
+          t := n;
+        if (t > m) then
+          t := m;
+        zmemcpy(q, p, t);
+        Inc(p, t);  Dec(n, t);
+        Inc(q, t);  Dec(m, t);
+        Dec(s.sub.left, t);
+        if (s.sub.left = 0) then
+        begin
+          {$IFDEF DEBUG}
+          if (ptr2int(q) >= ptr2int(s.read)) then
+            Tracev('inflate:       stored end '+
+                IntToStr(z.total_out + ptr2int(q) - ptr2int(s.read)) + ' total out')
+          else
+            Tracev('inflate:       stored end '+
+                    IntToStr(z.total_out + ptr2int(s.zend) - ptr2int(s.read) +
+                    ptr2int(q) - ptr2int(s.window)) +  ' total out');
+          {$ENDIF}
+          if s.last then
+            s.mode := DRY
+          else
+            s.mode := ZTYPE;
+        end;
+      end;
+    TABLE:
+      begin
+        {NEEDBITS(14);}
+        while (k < 14) do
+        begin
+          {NEEDBYTE;}
+          if (n <> 0) then
+            r :=Z_OK
+          else
+          begin
+            {UPDATE}
+            s.bitb := b;
+            s.bitk := k;
+            z.avail_in := n;
+            Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+            z.next_in := p;
+            s.write := q;
+            inflate_blocks := inflate_flush(s,z,r);
+            exit;
+          end;
+          Dec(n);
+          b := b or (uLong(p^) shl k);
+          Inc(p);
+          Inc(k, 8);
+        end;
+
+        t := uInt(b) and $3fff;
+        s.sub.trees.table := t;
+  {$ifndef PKZIP_BUG_WORKAROUND}
+        if ((t and $1f) > 29) or (((t shr 5) and $1f) > 29) then
+        begin
+          s.mode := BLKBAD;
+          z.msg := 'too many length or distance symbols';
+          r := Z_DATA_ERROR;
+          { update pointers and return }
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_blocks := inflate_flush(s,z,r);
+          exit;
+        end;
+  {$endif}
+        t := 258 + (t and $1f) + ((t shr 5) and $1f);
+        s.sub.trees.blens := puIntArray( ZALLOC(z, t, sizeof(uInt)) );
+        if (s.sub.trees.blens = Z_NULL) then
+        begin
+          r := Z_MEM_ERROR;
+          { update pointers and return }
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_blocks := inflate_flush(s,z,r);
+          exit;
+        end;
+        {DUMPBITS(14);}
+        b := b shr 14;
+        Dec(k, 14);
+
+        s.sub.trees.index := 0;
+        {$IFDEF DEBUG}
+        Tracev('inflate:       table sizes ok');
+        {$ENDIF}
+        s.mode := BTREE;
+        { fall trough case is handled by the while }
+        { try GOTO for speed - Nomssi }
+        goto start_btree;
+      end;
+    BTREE:
+      begin
+        start_btree:
+        while (s.sub.trees.index < 4 + (s.sub.trees.table shr 10)) do
+        begin
+          {NEEDBITS(3);}
+          while (k < 3) do
+          begin
+            {NEEDBYTE;}
+            if (n <> 0) then
+              r :=Z_OK
+            else
+            begin
+              {UPDATE}
+              s.bitb := b;
+              s.bitk := k;
+              z.avail_in := n;
+              Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+              z.next_in := p;
+              s.write := q;
+              inflate_blocks := inflate_flush(s,z,r);
+              exit;
+            end;
+            Dec(n);
+            b := b or (uLong(p^) shl k);
+            Inc(p);
+            Inc(k, 8);
+          end;
+
+          s.sub.trees.blens^[border[s.sub.trees.index]] := uInt(b) and 7;
+          Inc(s.sub.trees.index);
+          {DUMPBITS(3);}
+          b := b shr 3;
+          Dec(k, 3);
+        end;
+        while (s.sub.trees.index < 19) do
+        begin
+          s.sub.trees.blens^[border[s.sub.trees.index]] := 0;
+          Inc(s.sub.trees.index);
+        end;
+        s.sub.trees.bb := 7;
+        t := inflate_trees_bits(s.sub.trees.blens^, s.sub.trees.bb,
+                                s.sub.trees.tb, s.hufts^, z);
+        if (t <> Z_OK) then
+        begin
+          ZFREE(z, s.sub.trees.blens);
+          r := t;
+          if (r = Z_DATA_ERROR) then
+            s.mode := BLKBAD;
+          { update pointers and return }
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_blocks := inflate_flush(s,z,r);
+          exit;
+        end;
+        s.sub.trees.index := 0;
+        {$IFDEF DEBUG}
+        Tracev('inflate:       bits tree ok');
+        {$ENDIF}
+        s.mode := DTREE;
+        { fall through again }
+        goto start_dtree;
+      end;
+    DTREE:
+      begin
+        start_dtree:
+        while TRUE do
+        begin
+          t := s.sub.trees.table;
+          if not (s.sub.trees.index < 258 +
+                                     (t and $1f) + ((t shr 5) and $1f)) then
+            break;
+          t := s.sub.trees.bb;
+          {NEEDBITS(t);}
+          while (k < t) do
+          begin
+            {NEEDBYTE;}
+            if (n <> 0) then
+              r :=Z_OK
+            else
+            begin
+              {UPDATE}
+              s.bitb := b;
+              s.bitk := k;
+              z.avail_in := n;
+              Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+              z.next_in := p;
+              s.write := q;
+              inflate_blocks := inflate_flush(s,z,r);
+              exit;
+            end;
+            Dec(n);
+            b := b or (uLong(p^) shl k);
+            Inc(p);
+            Inc(k, 8);
+          end;
+
+          h := s.sub.trees.tb;
+          Inc(h, uInt(b) and inflate_mask[t]);
+          t := h^.Bits;
+          c := h^.Base;
+
+          if (c < 16) then
+          begin
+            {DUMPBITS(t);}
+            b := b shr t;
+            Dec(k, t);
+
+            s.sub.trees.blens^[s.sub.trees.index] := c;
+            Inc(s.sub.trees.index);
+          end
+          else { c = 16..18 }
+          begin
+            if c = 18 then
+            begin
+              i := 7;
+              j := 11;
+            end
+            else
+            begin
+              i := c - 14;
+              j := 3;
+            end;
+            {NEEDBITS(t + i);}
+            while (k < t + i) do
+            begin
+              {NEEDBYTE;}
+              if (n <> 0) then
+                r :=Z_OK
+              else
+              begin
+                {UPDATE}
+                s.bitb := b;
+                s.bitk := k;
+                z.avail_in := n;
+                Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+                z.next_in := p;
+                s.write := q;
+                inflate_blocks := inflate_flush(s,z,r);
+                exit;
+              end;
+              Dec(n);
+              b := b or (uLong(p^) shl k);
+              Inc(p);
+              Inc(k, 8);
+            end;
+
+            {DUMPBITS(t);}
+            b := b shr t;
+            Dec(k, t);
+
+            Inc(j, uInt(b) and inflate_mask[i]);
+            {DUMPBITS(i);}
+            b := b shr i;
+            Dec(k, i);
+
+            i := s.sub.trees.index;
+            t := s.sub.trees.table;
+            if (i + j > 258 + (t and $1f) + ((t shr 5) and $1f)) or
+               ((c = 16) and (i < 1)) then
+            begin
+              ZFREE(z, s.sub.trees.blens);
+              s.mode := BLKBAD;
+              z.msg := 'invalid bit length repeat';
+              r := Z_DATA_ERROR;
+              { update pointers and return }
+              s.bitb := b;
+              s.bitk := k;
+              z.avail_in := n;
+              Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+              z.next_in := p;
+              s.write := q;
+              inflate_blocks := inflate_flush(s,z,r);
+              exit;
+            end;
+            if c = 16 then
+              c := s.sub.trees.blens^[i - 1]
+            else
+              c := 0;
+            repeat
+              s.sub.trees.blens^[i] := c;
+              Inc(i);
+              Dec(j);
+            until (j=0);
+            s.sub.trees.index := i;
+          end;
+        end; { while }
+        s.sub.trees.tb := Z_NULL;
+        begin
+          bl := 9;         { must be <= 9 for lookahead assumptions }
+          bd := 6;         { must be <= 9 for lookahead assumptions }
+          t := s.sub.trees.table;
+          t := inflate_trees_dynamic(257 + (t and $1f),
+                  1 + ((t shr 5) and $1f),
+                  s.sub.trees.blens^, bl, bd, tl, td, s.hufts^, z);
+          ZFREE(z, s.sub.trees.blens);
+          if (t <> Z_OK) then
+          begin
+            if (t = uInt(Z_DATA_ERROR)) then
+              s.mode := BLKBAD;
+            r := t;
+            { update pointers and return }
+            s.bitb := b;
+            s.bitk := k;
+            z.avail_in := n;
+            Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+            z.next_in := p;
+            s.write := q;
+            inflate_blocks := inflate_flush(s,z,r);
+            exit;
+          end;
+          {$IFDEF DEBUG}
+          Tracev('inflate:       trees ok');
+          {$ENDIF}
+          { c renamed to cs }
+          cs := inflate_codes_new(bl, bd, tl, td, z);
+          if (cs = Z_NULL) then
+          begin
+            r := Z_MEM_ERROR;
+            { update pointers and return }
+            s.bitb := b;
+            s.bitk := k;
+            z.avail_in := n;
+            Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+            z.next_in := p;
+            s.write := q;
+            inflate_blocks := inflate_flush(s,z,r);
+            exit;
+          end;
+          s.sub.decode.codes := cs;
+        end;
+        s.mode := CODES;
+        { yet another falltrough }
+        goto start_codes;
+      end;
+    CODES:
+      begin
+        start_codes:
+        { update pointers }
+        s.bitb := b;
+        s.bitk := k;
+        z.avail_in := n;
+        Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+        z.next_in := p;
+        s.write := q;
+
+        r := inflate_codes(s, z, r);
+        if (r <> Z_STREAM_END) then
+        begin
+          inflate_blocks := inflate_flush(s, z, r);
+          exit;
+        end;
+        r := Z_OK;
+        inflate_codes_free(s.sub.decode.codes, z);
+        { load local pointers }
+        p := z.next_in;
+        n := z.avail_in;
+        b := s.bitb;
+        k := s.bitk;
+        q := s.write;
+        if ptr2int(q) < ptr2int(s.read) then
+          m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+        else
+          m := uInt(ptr2int(s.zend)-ptr2int(q));
+        {$IFDEF DEBUG}
+        if (ptr2int(q) >= ptr2int(s.read)) then
+          Tracev('inflate:       codes end '+
+              IntToStr(z.total_out + ptr2int(q) - ptr2int(s.read)) + ' total out')
+        else
+          Tracev('inflate:       codes end '+
+                  IntToStr(z.total_out + ptr2int(s.zend) - ptr2int(s.read) +
+                  ptr2int(q) - ptr2int(s.window)) +  ' total out');
+        {$ENDIF}
+        if (not s.last) then
+        begin
+          s.mode := ZTYPE;
+          continue; { break for switch statement in C-code }
+        end;
+        {$ifndef patch112}
+        if (k > 7) then           { return unused byte, if any }
+        begin
+          {$IFDEF DEBUG}
+          Assert(k < 16, 'inflate_codes grabbed too many bytes');
+          {$ENDIF}
+          Dec(k, 8);
+          Inc(n);
+          Dec(p);                    { can always return one }
+        end;
+        {$endif}
+        s.mode := DRY;
+        { another falltrough }
+        goto start_dry;
+      end;
+    DRY:
+      begin
+        start_dry:
+        {FLUSH}
+        s.write := q;
+        r := inflate_flush(s,z,r);
+        q := s.write;
+
+        { not needed anymore, we are done:
+        if ptr2int(q) < ptr2int(s.read) then
+          m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+        else
+          m := uInt(ptr2int(s.zend)-ptr2int(q));
+        }
+
+        if (s.read <> s.write) then
+        begin
+          { update pointers and return }
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_blocks := inflate_flush(s,z,r);
+          exit;
+        end;
+        s.mode := BLKDONE;
+        goto start_blkdone;
+      end;
+    BLKDONE:
+      begin
+        start_blkdone:
+        r := Z_STREAM_END;
+        { update pointers and return }
+        s.bitb := b;
+        s.bitk := k;
+        z.avail_in := n;
+        Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+        z.next_in := p;
+        s.write := q;
+        inflate_blocks := inflate_flush(s,z,r);
+        exit;
+      end;
+    BLKBAD:
+      begin
+        r := Z_DATA_ERROR;
+        { update pointers and return }
+        s.bitb := b;
+        s.bitk := k;
+        z.avail_in := n;
+        Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+        z.next_in := p;
+        s.write := q;
+        inflate_blocks := inflate_flush(s,z,r);
+        exit;
+      end;
+    else
+    begin
+      r := Z_STREAM_ERROR;
+      { update pointers and return }
+      s.bitb := b;
+      s.bitk := k;
+      z.avail_in := n;
+      Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+      z.next_in := p;
+      s.write := q;
+      inflate_blocks := inflate_flush(s,z,r);
+      exit;
+    end;
+  end; { Case s.mode of }
+
+end;
+
+
+function inflate_blocks_free(s : pInflate_blocks_state;
+                             var z : z_stream) : int;
+begin
+  inflate_blocks_reset(s^, z, Z_NULL);
+  ZFREE(z, s^.window);
+  ZFREE(z, s^.hufts);
+  ZFREE(z, s);
+  {$IFDEF DEBUG}
+  Trace('inflate:   blocks freed');
+  {$ENDIF}
+  inflate_blocks_free := Z_OK;
+end;
+
+
+procedure inflate_set_dictionary(var s : inflate_blocks_state;
+                                 const d : array of byte; { dictionary }
+                                 n : uInt);         { dictionary length }
+begin
+  zmemcpy(s.window, pBytef(@d), n);
+  s.write := s.window;
+  Inc(s.write, n);
+  s.read := s.write;
+end;
+
+
+{ Returns true if inflate is currently at the end of a block generated
+  by Z_SYNC_FLUSH or Z_FULL_FLUSH.
+  IN assertion: s <> Z_NULL }
+
+function inflate_blocks_sync_point(var s : inflate_blocks_state) : int;
+begin
+  inflate_blocks_sync_point := int(s.mode = LENS);
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/iminfcodes.pas b/src/lib/vampimg/ZLib/iminfcodes.pas
new file mode 100644 (file)
index 0000000..1396e13
--- /dev/null
@@ -0,0 +1,576 @@
+Unit iminfcodes;
+
+{ infcodes.c -- process literals and length/distance pairs
+  Copyright (C) 1995-1998 Mark Adler
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  {$IFDEF DEBUG}
+  SysUtils, strutils,
+  {$ENDIF}
+  imzutil, impaszlib;
+
+function inflate_codes_new (bl : uInt;
+                            bd : uInt;
+                            tl : pInflate_huft;
+                            td : pInflate_huft;
+                            var z : z_stream): pInflate_codes_state;
+
+function inflate_codes(var s : inflate_blocks_state;
+                       var z : z_stream;
+                       r : int) : int;
+
+procedure inflate_codes_free(c : pInflate_codes_state;
+                             var z : z_stream);
+
+implementation
+
+uses
+  iminfutil, iminffast;
+
+
+function inflate_codes_new (bl : uInt;
+                            bd : uInt;
+                            tl : pInflate_huft;
+                            td : pInflate_huft;
+                            var z : z_stream): pInflate_codes_state;
+var
+ c : pInflate_codes_state;
+begin
+  c := pInflate_codes_state( ZALLOC(z,1,sizeof(inflate_codes_state)) );
+  if (c <> Z_NULL) then
+  begin
+    c^.mode := START;
+    c^.lbits := Byte(bl);
+    c^.dbits := Byte(bd);
+    c^.ltree := tl;
+    c^.dtree := td;
+    {$IFDEF DEBUG}
+    Tracev('inflate:       codes new');
+    {$ENDIF}
+  end;
+  inflate_codes_new := c;
+end;
+
+
+function inflate_codes(var s : inflate_blocks_state;
+                       var z : z_stream;
+                       r : int) : int;
+var
+  j : uInt;               { temporary storage }
+  t : pInflate_huft;      { temporary pointer }
+  e : uInt;               { extra bits or operation }
+  b : uLong;              { bit buffer }
+  k : uInt;               { bits in bit buffer }
+  p : pBytef;             { input data pointer }
+  n : uInt;               { bytes available there }
+  q : pBytef;             { output window write pointer }
+  m : uInt;               { bytes to end of window or read pointer }
+  f : pBytef;             { pointer to copy strings from }
+var
+  c : pInflate_codes_state;
+begin
+  c := s.sub.decode.codes;  { codes state }
+
+  { copy input/output information to locals }
+  p := z.next_in;
+  n := z.avail_in;
+  b := s.bitb;
+  k := s.bitk;
+  q := s.write;
+  if ptr2int(q) < ptr2int(s.read) then
+    m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+  else
+    m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+  { process input and output based on current state }
+  while True do
+  case (c^.mode) of
+    { waiting for "i:"=input, "o:"=output, "x:"=nothing }
+  START:         { x: set up for LEN }
+    begin
+{$ifndef SLOW}
+      if (m >= 258) and (n >= 10) then
+      begin
+        {UPDATE}
+        s.bitb := b;
+        s.bitk := k;
+        z.avail_in := n;
+        Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+        z.next_in := p;
+        s.write := q;
+
+        r := inflate_fast(c^.lbits, c^.dbits, c^.ltree, c^.dtree, s, z);
+        {LOAD}
+        p := z.next_in;
+        n := z.avail_in;
+        b := s.bitb;
+        k := s.bitk;
+        q := s.write;
+        if ptr2int(q) < ptr2int(s.read) then
+          m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+        else
+          m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+        if (r <> Z_OK) then
+        begin
+          if (r = Z_STREAM_END) then
+            c^.mode := WASH
+          else
+            c^.mode := BADCODE;
+          continue;    { break for switch-statement in C }
+        end;
+      end;
+{$endif} { not SLOW }
+      c^.sub.code.need := c^.lbits;
+      c^.sub.code.tree := c^.ltree;
+      c^.mode := LEN;  { falltrough }
+    end;
+  LEN:           { i: get length/literal/eob next }
+    begin
+      j := c^.sub.code.need;
+      {NEEDBITS(j);}
+      while (k < j) do
+      begin
+        {NEEDBYTE;}
+        if (n <> 0) then
+          r :=Z_OK
+        else
+        begin
+          {UPDATE}
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_codes := inflate_flush(s,z,r);
+          exit;
+        end;
+        Dec(n);
+        b := b or (uLong(p^) shl k);
+        Inc(p);
+        Inc(k, 8);
+      end;
+      t := c^.sub.code.tree;
+      Inc(t, uInt(b) and inflate_mask[j]);
+      {DUMPBITS(t^.bits);}
+      b := b shr t^.bits;
+      Dec(k, t^.bits);
+
+      e := uInt(t^.exop);
+      if (e = 0) then            { literal }
+      begin
+        c^.sub.lit := t^.base;
+       {$IFDEF DEBUG}
+        if (t^.base >= $20) and (t^.base < $7f) then
+          Tracevv('inflate:         literal '+AnsiChar(t^.base))
+        else
+          Tracevv('inflate:         literal '+IntToStr(t^.base));
+        {$ENDIF}
+        c^.mode := LIT;
+        continue;  { break switch statement }
+      end;
+      if (e and 16 <> 0) then            { length }
+      begin
+        c^.sub.copy.get := e and 15;
+        c^.len := t^.base;
+        c^.mode := LENEXT;
+        continue;         { break C-switch statement }
+      end;
+      if (e and 64 = 0) then             { next table }
+      begin
+        c^.sub.code.need := e;
+        c^.sub.code.tree := @huft_ptr(t)^[t^.base];
+        continue;         { break C-switch statement }
+      end;
+      if (e and 32 <> 0) then            { end of block }
+      begin
+        {$IFDEF DEBUG}
+        Tracevv('inflate:         end of block');
+        {$ENDIF}
+        c^.mode := WASH;
+        continue;         { break C-switch statement }
+      end;
+      c^.mode := BADCODE;        { invalid code }
+      z.msg := 'invalid literal/length code';
+      r := Z_DATA_ERROR;
+      {UPDATE}
+      s.bitb := b;
+      s.bitk := k;
+      z.avail_in := n;
+      Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+      z.next_in := p;
+      s.write := q;
+      inflate_codes := inflate_flush(s,z,r);
+      exit;
+    end;
+  LENEXT:        { i: getting length extra (have base) }
+    begin
+      j := c^.sub.copy.get;
+      {NEEDBITS(j);}
+      while (k < j) do
+      begin
+        {NEEDBYTE;}
+        if (n <> 0) then
+          r :=Z_OK
+        else
+        begin
+          {UPDATE}
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_codes := inflate_flush(s,z,r);
+          exit;
+        end;
+        Dec(n);
+        b := b or (uLong(p^) shl k);
+        Inc(p);
+        Inc(k, 8);
+      end;
+      Inc(c^.len, uInt(b and inflate_mask[j]));
+      {DUMPBITS(j);}
+      b := b shr j;
+      Dec(k, j);
+
+      c^.sub.code.need := c^.dbits;
+      c^.sub.code.tree := c^.dtree;
+      {$IFDEF DEBUG}
+      Tracevv('inflate:         length '+IntToStr(c^.len));
+      {$ENDIF}
+      c^.mode := DIST;
+      { falltrough }
+    end;
+  DIST:          { i: get distance next }
+    begin
+      j := c^.sub.code.need;
+      {NEEDBITS(j);}
+      while (k < j) do
+      begin
+        {NEEDBYTE;}
+        if (n <> 0) then
+          r :=Z_OK
+        else
+        begin
+          {UPDATE}
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_codes := inflate_flush(s,z,r);
+          exit;
+        end;
+        Dec(n);
+        b := b or (uLong(p^) shl k);
+        Inc(p);
+        Inc(k, 8);
+      end;
+      t := @huft_ptr(c^.sub.code.tree)^[uInt(b) and inflate_mask[j]];
+      {DUMPBITS(t^.bits);}
+      b := b shr t^.bits;
+      Dec(k, t^.bits);
+
+      e := uInt(t^.exop);
+      if (e and 16 <> 0) then            { distance }
+      begin
+        c^.sub.copy.get := e and 15;
+        c^.sub.copy.dist := t^.base;
+        c^.mode := DISTEXT;
+        continue;     { break C-switch statement }
+      end;
+      if (e and 64 = 0) then     { next table }
+      begin
+        c^.sub.code.need := e;
+        c^.sub.code.tree := @huft_ptr(t)^[t^.base];
+        continue;     { break C-switch statement }
+      end;
+      c^.mode := BADCODE;        { invalid code }
+      z.msg := 'invalid distance code';
+      r := Z_DATA_ERROR;
+      {UPDATE}
+      s.bitb := b;
+      s.bitk := k;
+      z.avail_in := n;
+      Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+      z.next_in := p;
+      s.write := q;
+      inflate_codes := inflate_flush(s,z,r);
+      exit;
+    end;
+  DISTEXT:       { i: getting distance extra }
+    begin
+      j := c^.sub.copy.get;
+      {NEEDBITS(j);}
+      while (k < j) do
+      begin
+        {NEEDBYTE;}
+        if (n <> 0) then
+          r :=Z_OK
+        else
+        begin
+          {UPDATE}
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_codes := inflate_flush(s,z,r);
+          exit;
+        end;
+        Dec(n);
+        b := b or (uLong(p^) shl k);
+        Inc(p);
+        Inc(k, 8);
+      end;
+      Inc(c^.sub.copy.dist, uInt(b) and inflate_mask[j]);
+      {DUMPBITS(j);}
+      b := b shr j;
+      Dec(k, j);
+      {$IFDEF DEBUG}
+      Tracevv('inflate:         distance '+ IntToStr(c^.sub.copy.dist));
+      {$ENDIF}
+      c^.mode := COPY;
+      { falltrough }
+    end;
+  COPY:          { o: copying bytes in window, waiting for space }
+    begin
+      f := q;
+      Dec(f, c^.sub.copy.dist);
+      if (uInt(ptr2int(q) - ptr2int(s.window)) < c^.sub.copy.dist) then
+      begin
+        f := s.zend;
+        Dec(f, c^.sub.copy.dist - uInt(ptr2int(q) - ptr2int(s.window)));
+      end;
+
+      while (c^.len <> 0) do
+      begin
+        {NEEDOUT}
+        if (m = 0) then
+        begin
+          {WRAP}
+          if (q = s.zend) and (s.read <> s.window) then
+          begin
+            q := s.window;
+            if ptr2int(q) < ptr2int(s.read) then
+              m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+            else
+              m := uInt(ptr2int(s.zend)-ptr2int(q));
+          end;
+
+          if (m = 0) then
+          begin
+            {FLUSH}
+            s.write := q;
+            r := inflate_flush(s,z,r);
+            q := s.write;
+            if ptr2int(q) < ptr2int(s.read) then
+              m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+            else
+              m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+            {WRAP}
+            if (q = s.zend) and (s.read <> s.window) then
+            begin
+              q := s.window;
+              if ptr2int(q) < ptr2int(s.read) then
+                m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+              else
+                m := uInt(ptr2int(s.zend)-ptr2int(q));
+            end;
+
+            if (m = 0) then
+            begin
+              {UPDATE}
+              s.bitb := b;
+              s.bitk := k;
+              z.avail_in := n;
+              Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+              z.next_in := p;
+              s.write := q;
+              inflate_codes := inflate_flush(s,z,r);
+              exit;
+            end;
+          end;
+        end;
+        r := Z_OK;
+
+        {OUTBYTE( *f++)}
+        q^ := f^;
+        Inc(q);
+        Inc(f);
+        Dec(m);
+
+        if (f = s.zend) then
+          f := s.window;
+        Dec(c^.len);
+      end;
+      c^.mode := START;
+      { C-switch break; not needed }
+    end;
+  LIT:           { o: got literal, waiting for output space }
+    begin
+      {NEEDOUT}
+      if (m = 0) then
+      begin
+        {WRAP}
+        if (q = s.zend) and (s.read <> s.window) then
+        begin
+          q := s.window;
+          if ptr2int(q) < ptr2int(s.read) then
+            m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+          else
+            m := uInt(ptr2int(s.zend)-ptr2int(q));
+        end;
+
+        if (m = 0) then
+        begin
+          {FLUSH}
+          s.write := q;
+          r := inflate_flush(s,z,r);
+          q := s.write;
+          if ptr2int(q) < ptr2int(s.read) then
+            m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+          else
+            m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+          {WRAP}
+          if (q = s.zend) and (s.read <> s.window) then
+          begin
+            q := s.window;
+            if ptr2int(q) < ptr2int(s.read) then
+              m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+            else
+              m := uInt(ptr2int(s.zend)-ptr2int(q));
+          end;
+
+          if (m = 0) then
+          begin
+            {UPDATE}
+            s.bitb := b;
+            s.bitk := k;
+            z.avail_in := n;
+            Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+            z.next_in := p;
+            s.write := q;
+            inflate_codes := inflate_flush(s,z,r);
+            exit;
+          end;
+        end;
+      end;
+      r := Z_OK;
+
+      {OUTBYTE(c^.sub.lit);}
+      q^ := c^.sub.lit;
+      Inc(q);
+      Dec(m);
+
+      c^.mode := START;
+      {break;}
+    end;
+  WASH:          { o: got eob, possibly more output }
+    begin
+      {$ifdef patch112}
+      if (k > 7) then           { return unused byte, if any }
+      begin
+        {$IFDEF DEBUG}
+        Assert(k < 16, 'inflate_codes grabbed too many bytes');
+        {$ENDIF}
+        Dec(k, 8);
+        Inc(n);
+        Dec(p);                    { can always return one }
+      end;
+      {$endif}
+      {FLUSH}
+      s.write := q;
+      r := inflate_flush(s,z,r);
+      q := s.write;
+      if ptr2int(q) < ptr2int(s.read) then
+        m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+      else
+        m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+      if (s.read <> s.write) then
+      begin
+        {UPDATE}
+        s.bitb := b;
+        s.bitk := k;
+        z.avail_in := n;
+        Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+        z.next_in := p;
+        s.write := q;
+        inflate_codes := inflate_flush(s,z,r);
+        exit;
+      end;
+      c^.mode := ZEND;
+      { falltrough }
+    end;
+
+  ZEND:
+    begin
+      r := Z_STREAM_END;
+      {UPDATE}
+      s.bitb := b;
+      s.bitk := k;
+      z.avail_in := n;
+      Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+      z.next_in := p;
+      s.write := q;
+      inflate_codes := inflate_flush(s,z,r);
+      exit;
+    end;
+  BADCODE:       { x: got error }
+    begin
+      r := Z_DATA_ERROR;
+      {UPDATE}
+      s.bitb := b;
+      s.bitk := k;
+      z.avail_in := n;
+      Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+      z.next_in := p;
+      s.write := q;
+      inflate_codes := inflate_flush(s,z,r);
+      exit;
+    end;
+  else
+    begin
+      r := Z_STREAM_ERROR;
+      {UPDATE}
+      s.bitb := b;
+      s.bitk := k;
+      z.avail_in := n;
+      Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+      z.next_in := p;
+      s.write := q;
+      inflate_codes := inflate_flush(s,z,r);
+      exit;
+    end;
+  end;
+{NEED_DUMMY_RETURN - Delphi2+ dumb compilers complain without this }
+  inflate_codes := Z_STREAM_ERROR;
+end;
+
+
+procedure inflate_codes_free(c : pInflate_codes_state;
+                             var z : z_stream);
+begin
+  ZFREE(z, c);
+  {$IFDEF DEBUG}
+  Tracev('inflate:       codes free');
+  {$ENDIF}
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/iminffast.pas b/src/lib/vampimg/ZLib/iminffast.pas
new file mode 100644 (file)
index 0000000..936c922
--- /dev/null
@@ -0,0 +1,318 @@
+Unit iminffast;
+
+{
+  inffast.h and
+  inffast.c -- process literals and length/distance pairs fast
+  Copyright (C) 1995-1998 Mark Adler
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  {$ifdef DEBUG}
+  SysUtils, strutils,
+  {$ENDIF}
+  imzutil, impaszlib;
+
+function inflate_fast( bl : uInt;
+                       bd : uInt;
+                       tl : pInflate_huft;
+                       td : pInflate_huft;
+                      var s : inflate_blocks_state;
+                      var z : z_stream) : int;
+
+
+implementation
+
+uses
+  iminfutil;
+
+
+{ Called with number of bytes left to write in window at least 258
+  (the maximum string length) and number of input bytes available
+  at least ten.  The ten bytes are six bytes for the longest length/
+  distance pair plus four bytes for overloading the bit buffer. }
+
+function inflate_fast( bl : uInt;
+                       bd : uInt;
+                       tl : pInflate_huft;
+                       td : pInflate_huft;
+                      var s : inflate_blocks_state;
+                      var z : z_stream) : int;
+
+var
+  t : pInflate_huft;      { temporary pointer }
+  e : uInt;               { extra bits or operation }
+  b : uLong;              { bit buffer }
+  k : uInt;               { bits in bit buffer }
+  p : pBytef;             { input data pointer }
+  n : uInt;               { bytes available there }
+  q : pBytef;             { output window write pointer }
+  m : uInt;               { bytes to end of window or read pointer }
+  ml : uInt;              { mask for literal/length tree }
+  md : uInt;              { mask for distance tree }
+  c : uInt;               { bytes to copy }
+  d : uInt;               { distance back to copy from }
+  r : pBytef;             { copy source pointer }
+begin
+  { load input, output, bit values (macro LOAD) }
+  p := z.next_in;
+  n := z.avail_in;
+  b := s.bitb;
+  k := s.bitk;
+  q := s.write;
+  if ptr2int(q) < ptr2int(s.read) then
+    m := uInt(ptr2int(s.read)-ptr2int(q)-1)
+  else
+    m := uInt(ptr2int(s.zend)-ptr2int(q));
+
+  { initialize masks }
+  ml := inflate_mask[bl];
+  md := inflate_mask[bd];
+
+  { do until not enough input or output space for fast loop }
+  repeat                      { assume called with (m >= 258) and (n >= 10) }
+    { get literal/length code }
+    {GRABBITS(20);}             { max bits for literal/length code }
+    while (k < 20) do
+    begin
+      Dec(n);
+      b := b or (uLong(p^) shl k);
+      Inc(p);
+      Inc(k, 8);
+    end;
+
+    t := @(huft_ptr(tl)^[uInt(b) and ml]);
+
+    e := t^.exop;
+    if (e = 0) then
+    begin
+      {DUMPBITS(t^.bits);}
+      b := b shr t^.bits;
+      Dec(k, t^.bits);
+     {$IFDEF DEBUG}
+      if (t^.base >= $20) and (t^.base < $7f) then
+        Tracevv('inflate:         * literal '+AnsiChar(t^.base))
+      else
+        Tracevv('inflate:         * literal '+ IntToStr(t^.base));
+      {$ENDIF}
+      q^ := Byte(t^.base);
+      Inc(q);
+      Dec(m);
+      continue;
+    end;
+    repeat
+      {DUMPBITS(t^.bits);}
+      b := b shr t^.bits;
+      Dec(k, t^.bits);
+
+      if (e and 16 <> 0) then
+      begin
+        { get extra bits for length }
+        e := e and 15;
+        c := t^.base + (uInt(b) and inflate_mask[e]);
+        {DUMPBITS(e);}
+        b := b shr e;
+        Dec(k, e);
+        {$IFDEF DEBUG}
+        Tracevv('inflate:         * length ' + IntToStr(c));
+        {$ENDIF}
+        { decode distance base of block to copy }
+        {GRABBITS(15);}           { max bits for distance code }
+        while (k < 15) do
+        begin
+          Dec(n);
+          b := b or (uLong(p^) shl k);
+          Inc(p);
+          Inc(k, 8);
+        end;
+
+        t := @huft_ptr(td)^[uInt(b) and md];
+        e := t^.exop;
+        repeat
+          {DUMPBITS(t^.bits);}
+          b := b shr t^.bits;
+          Dec(k, t^.bits);
+
+          if (e and 16 <> 0) then
+          begin
+            { get extra bits to add to distance base }
+            e := e and 15;
+            {GRABBITS(e);}         { get extra bits (up to 13) }
+            while (k < e) do
+            begin
+              Dec(n);
+              b := b or (uLong(p^) shl k);
+              Inc(p);
+              Inc(k, 8);
+            end;
+
+            d := t^.base + (uInt(b) and inflate_mask[e]);
+            {DUMPBITS(e);}
+            b := b shr e;
+            Dec(k, e);
+
+            {$IFDEF DEBUG}
+            Tracevv('inflate:         * distance '+IntToStr(d));
+            {$ENDIF}
+            { do the copy }
+            Dec(m, c);
+            if (uInt(ptr2int(q) - ptr2int(s.window)) >= d) then     { offset before dest }
+            begin                                  {  just copy }
+              r := q;
+              Dec(r, d);
+              q^ := r^;  Inc(q); Inc(r); Dec(c); { minimum count is three, }
+              q^ := r^;  Inc(q); Inc(r); Dec(c); { so unroll loop a little }
+            end
+            else                        { else offset after destination }
+            begin
+              e := d - uInt(ptr2int(q) - ptr2int(s.window)); { bytes from offset to end }
+              r := s.zend;
+              Dec(r, e);                  { pointer to offset }
+              if (c > e) then             { if source crosses, }
+              begin
+                Dec(c, e);                { copy to end of window }
+                repeat
+                  q^ := r^;
+                  Inc(q);
+                  Inc(r);
+                  Dec(e);
+                until (e=0);
+                r := s.window;           { copy rest from start of window }
+              end;
+            end;
+            repeat                       { copy all or what's left }
+              q^ := r^;
+              Inc(q);
+              Inc(r);
+              Dec(c);
+            until (c = 0);
+            break;
+          end
+          else
+            if (e and 64 = 0) then
+            begin
+              Inc(t, t^.base + (uInt(b) and inflate_mask[e]));
+              e := t^.exop;
+            end
+          else
+          begin
+            z.msg := 'invalid distance code';
+            {UNGRAB}
+            c := z.avail_in-n;
+            if (k shr 3) < c then
+              c := k shr 3;
+            Inc(n, c);
+            Dec(p, c);
+            Dec(k, c shl 3);
+            {UPDATE}
+            s.bitb := b;
+            s.bitk := k;
+            z.avail_in := n;
+            Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+            z.next_in := p;
+            s.write := q;
+
+            inflate_fast := Z_DATA_ERROR;
+            exit;
+          end;
+        until FALSE;
+        break;
+      end;
+      if (e and 64 = 0) then
+      begin
+         {t += t->base;
+          e = (t += ((uInt)b & inflate_mask[e]))->exop;}
+
+        Inc(t, t^.base + (uInt(b) and inflate_mask[e]));
+        e := t^.exop;
+        if (e = 0) then
+        begin
+          {DUMPBITS(t^.bits);}
+          b := b shr t^.bits;
+          Dec(k, t^.bits);
+
+         {$IFDEF DEBUG}
+          if (t^.base >= $20) and (t^.base < $7f) then
+            Tracevv('inflate:         * literal '+AnsiChar(t^.base))
+          else
+            Tracevv('inflate:         * literal '+IntToStr(t^.base));
+          {$ENDIF}
+          q^ := Byte(t^.base);
+          Inc(q);
+          Dec(m);
+          break;
+        end;
+      end
+      else
+        if (e and 32 <> 0) then
+        begin
+          {$IFDEF DEBUG}
+          Tracevv('inflate:         * end of block');
+          {$ENDIF}
+          {UNGRAB}
+          c := z.avail_in-n;
+          if (k shr 3) < c then
+            c := k shr 3;
+          Inc(n, c);
+          Dec(p, c);
+          Dec(k, c shl 3);
+          {UPDATE}
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_fast := Z_STREAM_END;
+          exit;
+        end
+        else
+        begin
+          z.msg := 'invalid literal/length code';
+          {UNGRAB}
+          c := z.avail_in-n;
+          if (k shr 3) < c then
+            c := k shr 3;
+          Inc(n, c);
+          Dec(p, c);
+          Dec(k, c shl 3);
+          {UPDATE}
+          s.bitb := b;
+          s.bitk := k;
+          z.avail_in := n;
+          Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+          z.next_in := p;
+          s.write := q;
+          inflate_fast := Z_DATA_ERROR;
+          exit;
+        end;
+    until FALSE;
+  until (m < 258) or (n < 10);
+
+  { not enough input or output--restore pointers and return }
+  {UNGRAB}
+  c := z.avail_in-n;
+  if (k shr 3) < c then
+    c := k shr 3;
+  Inc(n, c);
+  Dec(p, c);
+  Dec(k, c shl 3);
+  {UPDATE}
+  s.bitb := b;
+  s.bitk := k;
+  z.avail_in := n;
+  Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
+  z.next_in := p;
+  s.write := q;
+  inflate_fast := Z_OK;
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/iminftrees.pas b/src/lib/vampimg/ZLib/iminftrees.pas
new file mode 100644 (file)
index 0000000..af545a7
--- /dev/null
@@ -0,0 +1,781 @@
+Unit iminftrees;
+
+{ inftrees.h -- header to use inftrees.c
+  inftrees.c -- generate Huffman trees for efficient decoding
+  Copyright (C) 1995-1998 Mark Adler
+
+  WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change.
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+Interface
+
+{$I imzconf.inc}
+
+uses
+  imzutil, impaszlib;
+
+
+{ Maximum size of dynamic tree.  The maximum found in a long but non-
+  exhaustive search was 1004 huft structures (850 for length/literals
+  and 154 for distances, the latter actually the result of an
+  exhaustive search).  The actual maximum is not known, but the
+  value below is more than safe. }
+const
+  MANY = 1440;
+
+
+{$ifdef DEBUG}
+var
+  inflate_hufts : uInt;
+{$endif}
+
+function inflate_trees_bits(
+  var c : array of uIntf;  { 19 code lengths }
+  var bb : uIntf;          { bits tree desired/actual depth }
+  var tb : pinflate_huft;  { bits tree result }
+  var hp : array of Inflate_huft;      { space for trees }
+  var z : z_stream         { for messages }
+    ) : int;
+
+function inflate_trees_dynamic(
+    nl : uInt;                    { number of literal/length codes }
+    nd : uInt;                    { number of distance codes }
+    var c : Array of uIntf;           { that many (total) code lengths }
+    var bl : uIntf;               { literal desired/actual bit depth }
+    var bd : uIntf;               { distance desired/actual bit depth }
+var tl : pInflate_huft;           { literal/length tree result }
+var td : pInflate_huft;           { distance tree result }
+var hp : array of Inflate_huft;   { space for trees }
+var z : z_stream                  { for messages }
+     ) : int;
+
+function inflate_trees_fixed (
+    var bl : uInt;                { literal desired/actual bit depth }
+    var bd : uInt;                { distance desired/actual bit depth }
+    var tl : pInflate_huft;       { literal/length tree result }
+    var td : pInflate_huft;       { distance tree result }
+    var z : z_stream              { for memory allocation }
+     ) : int;
+
+
+implementation
+
+const
+ inflate_copyright = 'inflate 1.1.2 Copyright 1995-1998 Mark Adler';
+
+{
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+}
+
+
+const
+{ Tables for deflate from PKZIP's appnote.txt. }
+  cplens : Array [0..30] Of uInt  { Copy lengths for literal codes 257..285 }
+     = (3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0);
+        { actually lengths - 2; also see note #13 above about 258 }
+
+  invalid_code = 112;
+
+  cplext : Array [0..30] Of uInt  { Extra bits for literal codes 257..285 }
+     = (0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, invalid_code, invalid_code);
+
+  cpdist : Array [0..29] Of uInt { Copy offsets for distance codes 0..29 }
+     = (1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577);
+
+  cpdext : Array [0..29] Of uInt { Extra bits for distance codes }
+     = (0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13);
+
+{  Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary. }
+
+
+{ If BMAX needs to be larger than 16, then h and x[] should be uLong. }
+const
+  BMAX = 15;         { maximum bit length of any code }
+
+{$DEFINE USE_PTR}
+
+function huft_build(
+var b : array of uIntf;    { code lengths in bits (all assumed <= BMAX) }
+    n : uInt;              { number of codes (assumed <= N_MAX) }
+    s : uInt;              { number of simple-valued codes (0..s-1) }
+const d : array of uIntf;  { list of base values for non-simple codes }
+{ array of word }
+const e : array of uIntf;  { list of extra bits for non-simple codes }
+{ array of byte }
+  t : ppInflate_huft;     { result: starting table }
+var m : uIntf;             { maximum lookup bits, returns actual }
+var hp : array of inflate_huft;  { space for trees }
+var hn : uInt;             { hufts used in space }
+var v : array of uIntf     { working area: values in order of bit length }
+   ) : int;
+{ Given a list of code lengths and a maximum table size, make a set of
+  tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+  if the given code set is incomplete (the tables are still built in this
+  case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+  lengths), or Z_MEM_ERROR if not enough memory. }
+Var
+  a : uInt;                     { counter for codes of length k }
+  c : Array [0..BMAX] Of uInt;  { bit length count table }
+  f : uInt;                     { i repeats in table every f entries }
+  g : int;                      { maximum code length }
+  h : int;                      { table level }
+  i : uInt;  {register}         { counter, current code }
+  j : uInt;  {register}         { counter }
+  k : Int;   {register}         { number of bits in current code }
+  l : int;      { bits per table (returned in m) }
+  mask : uInt;                  { (1 shl w) - 1, to avoid cc -O bug on HP }
+  p : ^uIntf; {register}        { pointer into c[], b[], or v[] }
+  q : pInflate_huft;            { points to current table }
+  r : inflate_huft;             { table entry for structure assignment }
+  u : Array [0..BMAX-1] Of pInflate_huft; { table stack }
+  w : int;   {register}         { bits before this table = (l*h) }
+  x : Array [0..BMAX] Of uInt;  { bit offsets, then code stack }
+  {$IFDEF USE_PTR}
+  xp : puIntf;                  { pointer into x }
+  {$ELSE}
+  xp : uInt;
+  {$ENDIF}
+  y : int;                      { number of dummy codes added }
+  z : uInt;                     { number of entries in current table }
+Begin
+  { Generate counts for each bit length }
+  FillChar(c,SizeOf(c),0) ;     { clear c[] }
+
+  for i := 0 to n-1 do
+    Inc (c[b[i]]);              { assume all entries <= BMAX }
+
+  If (c[0] = n) Then            { null input--all zero length codes }
+  Begin
+    t^ := pInflate_huft(NIL);
+    m := 0 ;
+    huft_build := Z_OK ;
+    Exit;
+  End ;
+
+  { Find minimum and maximum length, bound [m] by those }
+  l := m;
+  for j:=1 To BMAX do
+    if (c[j] <> 0) then
+      break;
+  k := j ;                      { minimum code length }
+  if (uInt(l) < j) then
+    l := j;
+  for i := BMAX downto 1 do
+    if (c[i] <> 0) then
+      break ;
+  g := i ;                      { maximum code length }
+  if (uInt(l) > i) then
+     l := i;
+  m := l;
+
+  { Adjust last length count to fill out codes, if needed }
+  y := 1 shl j ;
+  while (j < i) do
+  begin
+    Dec(y, c[j]) ;
+    if (y < 0) then
+    begin
+      huft_build := Z_DATA_ERROR;   { bad input: more codes than bits }
+      exit;
+    end ;
+    Inc(j) ;
+    y := y shl 1
+  end;
+  Dec (y, c[i]) ;
+  if (y < 0) then
+  begin
+    huft_build := Z_DATA_ERROR;     { bad input: more codes than bits }
+    exit;
+  end;
+  Inc(c[i], y);
+
+  { Generate starting offsets into the value table FOR each length }
+  {$IFDEF USE_PTR}
+  x[1] := 0;
+  j := 0;
+
+  p := @c[1];
+  xp := @x[2];
+
+  dec(i);               { note that i = g from above }
+  WHILE (i > 0) DO
+  BEGIN
+    inc(j, p^);
+    xp^ := j;
+    inc(p);
+    inc(xp);
+    dec(i);
+  END;
+  {$ELSE}
+  x[1] := 0;
+  j := 0 ;
+  for i := 1 to g do
+  begin
+    x[i] := j;
+    Inc(j, c[i]);
+  end;
+  {$ENDIF}
+
+  { Make a table of values in order of bit lengths }
+  for i := 0 to n-1 do
+  begin
+    j := b[i];
+    if (j <> 0) then
+    begin
+      v[ x[j] ] := i;
+      Inc(x[j]);
+    end;
+  end;
+  n := x[g];                     { set n to length of v }
+
+  { Generate the Huffman codes and for each, make the table entries }
+  i := 0 ;
+  x[0] := 0 ;                   { first Huffman code is zero }
+  p := Addr(v) ;                { grab values in bit order }
+  h := -1 ;                     { no tables yet--level -1 }
+  w := -l ;                     { bits decoded = (l*h) }
+
+  u[0] := pInflate_huft(NIL);   { just to keep compilers happy }
+  q := pInflate_huft(NIL);      { ditto }
+  z := 0 ;                      { ditto }
+
+  { go through the bit lengths (k already is bits in shortest code) }
+  while (k <= g) Do
+  begin
+    a := c[k] ;
+    while (a<>0) Do
+    begin
+      Dec (a) ;
+      { here i is the Huffman code of length k bits for value p^ }
+      { make tables up to required level }
+      while (k > w + l) do
+      begin
+
+        Inc (h) ;
+        Inc (w, l);              { add bits already decoded }
+                                 { previous table always l bits }
+        { compute minimum size table less than or equal to l bits }
+
+        { table size upper limit }
+        z := g - w;
+        If (z > uInt(l)) Then
+          z := l;
+
+        { try a k-w bit table }
+        j := k - w;
+        f := 1 shl j;
+        if (f > a+1) Then        { too few codes for k-w bit table }
+        begin
+          Dec(f, a+1);           { deduct codes from patterns left }
+          {$IFDEF USE_PTR}
+          xp := Addr(c[k]);
+
+          if (j < z) then
+          begin
+            Inc(j);
+            while (j < z) do
+            begin                { try smaller tables up to z bits }
+              f := f shl 1;
+              Inc (xp) ;
+              If (f <= xp^) Then
+                break;           { enough codes to use up j bits }
+              Dec(f, xp^);       { else deduct codes from patterns }
+              Inc(j);
+            end;
+          end;
+          {$ELSE}
+          xp := k;
+
+          if (j < z) then
+          begin
+            Inc (j) ;
+            While (j < z) Do
+            begin                 { try smaller tables up to z bits }
+              f := f * 2;
+              Inc (xp) ;
+              if (f <= c[xp]) then
+                Break ;           { enough codes to use up j bits }
+              Dec (f, c[xp]) ;      { else deduct codes from patterns }
+              Inc (j);
+            end;
+          end;
+          {$ENDIF}
+        end;
+
+        z := 1 shl j;            { table entries for j-bit table }
+
+        { allocate new table }
+        if (hn + z > MANY) then { (note: doesn't matter for fixed) }
+        begin
+          huft_build := Z_MEM_ERROR;     { not enough memory }
+          exit;
+        end;
+
+        q := @hp[hn];
+        u[h] := q;
+        Inc(hn, z);
+
+        { connect to last table, if there is one }
+        if (h <> 0) then
+        begin
+          x[h] := i;             { save pattern for backing up }
+          r.bits := Byte(l);     { bits to dump before this table }
+          r.exop := Byte(j);     { bits in this table }
+          j := i shr (w - l);
+          {r.base := uInt( q - u[h-1] -j);}   { offset to this table }
+          r.base := (ptr2int(q) - ptr2int(u[h-1]) ) div sizeof(q^) - j;
+          huft_Ptr(u[h-1])^[j] := r;  { connect to last table }
+        end
+        else
+          t^ := q;               { first table is returned result }
+      end;
+
+      { set up table entry in r }
+      r.bits := Byte(k - w);
+
+      { C-code: if (p >= v + n) - see ZUTIL.PAS for comments }
+
+      if ptr2int(p)>=ptr2int(@(v[n])) then  { also works under DPMI ?? }
+        r.exop := 128 + 64                  { out of values--invalid code }
+      else
+        if (p^ < s) then
+        begin
+          if (p^ < 256) then     { 256 is end-of-block code }
+            r.exop := 0
+          Else
+            r.exop := 32 + 64;   { EOB_code; }
+          r.base := p^;          { simple code is just the value }
+          Inc(p);
+        end
+        Else
+        begin
+          r.exop := Byte(e[p^-s] + 16 + 64);  { non-simple--look up in lists }
+          r.base := d[p^-s];
+          Inc (p);
+        end ;
+
+      { fill code-like entries with r }
+      f := 1 shl (k - w);
+      j := i shr w;
+      while (j < z) do
+      begin
+        huft_Ptr(q)^[j] := r;
+        Inc(j, f);
+      end;
+
+      { backwards increment the k-bit code i }
+      j := 1 shl (k-1) ;
+      while (i and j) <> 0 do
+      begin
+        i := i xor j;         { bitwise exclusive or }
+        j := j shr 1
+      end ;
+      i := i xor j;
+
+      { backup over finished tables }
+      mask := (1 shl w) - 1;   { needed on HP, cc -O bug }
+      while ((i and mask) <> x[h]) do
+      begin
+        Dec(h);                { don't need to update q }
+        Dec(w, l);
+        mask := (1 shl w) - 1;
+      end;
+
+    end;
+
+    Inc(k);
+  end;
+
+  { Return Z_BUF_ERROR if we were given an incomplete table }
+  if (y <> 0) And (g <> 1) then
+    huft_build := Z_BUF_ERROR
+  else
+    huft_build := Z_OK;
+end; { huft_build}
+
+
+function inflate_trees_bits(
+  var c : array of uIntf;  { 19 code lengths }
+  var bb : uIntf;          { bits tree desired/actual depth }
+  var tb : pinflate_huft;  { bits tree result }
+  var hp : array of Inflate_huft;      { space for trees }
+  var z : z_stream         { for messages }
+    ) : int;
+var
+  r : int;
+  hn : uInt;          { hufts used in space }
+  v : PuIntArray;     { work area for huft_build }
+begin
+  hn := 0;
+  v := PuIntArray( ZALLOC(z, 19, sizeof(uInt)) );
+  if (v = Z_NULL) then
+  begin
+    inflate_trees_bits := Z_MEM_ERROR;
+    exit;
+  end;
+
+  r := huft_build(c, 19, 19, cplens, cplext,
+                             {puIntf(Z_NULL), puIntf(Z_NULL),}
+                  @tb, bb, hp, hn, v^);
+  if (r = Z_DATA_ERROR) then
+    z.msg := 'oversubscribed dynamic bit lengths tree'
+  else
+    if (r = Z_BUF_ERROR) or (bb = 0) then
+    begin
+      z.msg := 'incomplete dynamic bit lengths tree';
+      r := Z_DATA_ERROR;
+    end;
+  ZFREE(z, v);
+  inflate_trees_bits := r;
+end;
+
+
+function inflate_trees_dynamic(
+    nl : uInt;                    { number of literal/length codes }
+    nd : uInt;                    { number of distance codes }
+    var c : Array of uIntf;           { that many (total) code lengths }
+    var bl : uIntf;          { literal desired/actual bit depth }
+    var bd : uIntf;          { distance desired/actual bit depth }
+var tl : pInflate_huft;           { literal/length tree result }
+var td : pInflate_huft;           { distance tree result }
+var hp : array of Inflate_huft;   { space for trees }
+var z : z_stream                  { for messages }
+     ) : int;
+var
+  r : int;
+  hn : uInt;          { hufts used in space }
+  v : PuIntArray;     { work area for huft_build }
+begin
+  hn := 0;
+  { allocate work area }
+  v := PuIntArray( ZALLOC(z, 288, sizeof(uInt)) );
+  if (v = Z_NULL) then
+  begin
+    inflate_trees_dynamic := Z_MEM_ERROR;
+    exit;
+  end;
+
+  { build literal/length tree }
+  r := huft_build(c, nl, 257, cplens, cplext, @tl, bl, hp, hn, v^);
+  if (r <> Z_OK) or (bl = 0) then
+  begin
+    if (r = Z_DATA_ERROR) then
+      z.msg := 'oversubscribed literal/length tree'
+    else
+      if (r <> Z_MEM_ERROR) then
+      begin
+        z.msg := 'incomplete literal/length tree';
+        r := Z_DATA_ERROR;
+      end;
+
+    ZFREE(z, v);
+    inflate_trees_dynamic := r;
+    exit;
+  end;
+
+  { build distance tree }
+  r := huft_build(puIntArray(@c[nl])^, nd, 0,
+                  cpdist, cpdext, @td, bd, hp, hn, v^);
+  if (r <> Z_OK) or ((bd = 0) and (nl > 257)) then
+  begin
+    if (r = Z_DATA_ERROR) then
+      z.msg := 'oversubscribed literal/length tree'
+    else
+      if (r = Z_BUF_ERROR) then
+      begin
+{$ifdef PKZIP_BUG_WORKAROUND}
+        r := Z_OK;
+      end;
+{$else}
+        z.msg := 'incomplete literal/length tree';
+        r := Z_DATA_ERROR;
+      end
+      else
+        if (r <> Z_MEM_ERROR) then
+        begin
+          z.msg := 'empty distance tree with lengths';
+          r := Z_DATA_ERROR;
+        end;
+    ZFREE(z, v);
+    inflate_trees_dynamic := r;
+    exit;
+{$endif}
+  end;
+
+  { done }
+  ZFREE(z, v);
+  inflate_trees_dynamic := Z_OK;
+end;
+
+{$UNDEF BUILDFIXED}
+
+{ build fixed tables only once--keep them here }
+{$IFNDEF BUILDFIXED}
+{ locals }
+var
+  fixed_built : Boolean = false;
+const
+  FIXEDH = 544;      { number of hufts used by fixed tables }
+var
+  fixed_mem : array[0..FIXEDH-1] of inflate_huft;
+  fixed_bl : uInt;
+  fixed_bd : uInt;
+  fixed_tl : pInflate_huft;
+  fixed_td : pInflate_huft;
+
+{$ELSE}
+
+{ inffixed.h -- table for decoding fixed codes }
+
+{local}
+const
+  fixed_bl = uInt(9);
+{local}
+const
+  fixed_bd = uInt(5);
+{local}
+const
+  fixed_tl : array [0..288-1] of inflate_huft = (
+    Exop,             { number of extra bits or operation }
+    bits : Byte;      { number of bits in this code or subcode }
+    {pad : uInt;}       { pad structure to a power of 2 (4 bytes for }
+                      {  16-bit, 8 bytes for 32-bit int's) }
+    base : uInt;      { literal, length base, or distance base }
+                      { or table offset }
+
+    ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115), ((82,7),31),
+    ((0,8),112), ((0,8),48), ((0,9),192), ((80,7),10), ((0,8),96),
+    ((0,8),32), ((0,9),160), ((0,8),0), ((0,8),128), ((0,8),64),
+    ((0,9),224), ((80,7),6), ((0,8),88), ((0,8),24), ((0,9),144),
+    ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),208), ((81,7),17),
+    ((0,8),104), ((0,8),40), ((0,9),176), ((0,8),8), ((0,8),136),
+    ((0,8),72), ((0,9),240), ((80,7),4), ((0,8),84), ((0,8),20),
+    ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52), ((0,9),200),
+    ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),168), ((0,8),4),
+    ((0,8),132), ((0,8),68), ((0,9),232), ((80,7),8), ((0,8),92),
+    ((0,8),28), ((0,9),152), ((84,7),83), ((0,8),124), ((0,8),60),
+    ((0,9),216), ((82,7),23), ((0,8),108), ((0,8),44), ((0,9),184),
+    ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),248), ((80,7),3),
+    ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35), ((0,8),114),
+    ((0,8),50), ((0,9),196), ((81,7),11), ((0,8),98), ((0,8),34),
+    ((0,9),164), ((0,8),2), ((0,8),130), ((0,8),66), ((0,9),228),
+    ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),148), ((84,7),67),
+    ((0,8),122), ((0,8),58), ((0,9),212), ((82,7),19), ((0,8),106),
+    ((0,8),42), ((0,9),180), ((0,8),10), ((0,8),138), ((0,8),74),
+    ((0,9),244), ((80,7),5), ((0,8),86), ((0,8),22), ((192,8),0),
+    ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),204), ((81,7),15),
+    ((0,8),102), ((0,8),38), ((0,9),172), ((0,8),6), ((0,8),134),
+    ((0,8),70), ((0,9),236), ((80,7),9), ((0,8),94), ((0,8),30),
+    ((0,9),156), ((84,7),99), ((0,8),126), ((0,8),62), ((0,9),220),
+    ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),188), ((0,8),14),
+    ((0,8),142), ((0,8),78), ((0,9),252), ((96,7),256), ((0,8),81),
+    ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113), ((0,8),49),
+    ((0,9),194), ((80,7),10), ((0,8),97), ((0,8),33), ((0,9),162),
+    ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),226), ((80,7),6),
+    ((0,8),89), ((0,8),25), ((0,9),146), ((83,7),59), ((0,8),121),
+    ((0,8),57), ((0,9),210), ((81,7),17), ((0,8),105), ((0,8),41),
+    ((0,9),178), ((0,8),9), ((0,8),137), ((0,8),73), ((0,9),242),
+    ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258), ((83,7),43),
+    ((0,8),117), ((0,8),53), ((0,9),202), ((81,7),13), ((0,8),101),
+    ((0,8),37), ((0,9),170), ((0,8),5), ((0,8),133), ((0,8),69),
+    ((0,9),234), ((80,7),8), ((0,8),93), ((0,8),29), ((0,9),154),
+    ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),218), ((82,7),23),
+    ((0,8),109), ((0,8),45), ((0,9),186), ((0,8),13), ((0,8),141),
+    ((0,8),77), ((0,9),250), ((80,7),3), ((0,8),83), ((0,8),19),
+    ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51), ((0,9),198),
+    ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),166), ((0,8),3),
+    ((0,8),131), ((0,8),67), ((0,9),230), ((80,7),7), ((0,8),91),
+    ((0,8),27), ((0,9),150), ((84,7),67), ((0,8),123), ((0,8),59),
+    ((0,9),214), ((82,7),19), ((0,8),107), ((0,8),43), ((0,9),182),
+    ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),246), ((80,7),5),
+    ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51), ((0,8),119),
+    ((0,8),55), ((0,9),206), ((81,7),15), ((0,8),103), ((0,8),39),
+    ((0,9),174), ((0,8),7), ((0,8),135), ((0,8),71), ((0,9),238),
+    ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),158), ((84,7),99),
+    ((0,8),127), ((0,8),63), ((0,9),222), ((82,7),27), ((0,8),111),
+    ((0,8),47), ((0,9),190), ((0,8),15), ((0,8),143), ((0,8),79),
+    ((0,9),254), ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115),
+    ((82,7),31), ((0,8),112), ((0,8),48), ((0,9),193), ((80,7),10),
+    ((0,8),96), ((0,8),32), ((0,9),161), ((0,8),0), ((0,8),128),
+    ((0,8),64), ((0,9),225), ((80,7),6), ((0,8),88), ((0,8),24),
+    ((0,9),145), ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),209),
+    ((81,7),17), ((0,8),104), ((0,8),40), ((0,9),177), ((0,8),8),
+    ((0,8),136), ((0,8),72), ((0,9),241), ((80,7),4), ((0,8),84),
+    ((0,8),20), ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52),
+    ((0,9),201), ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),169),
+    ((0,8),4), ((0,8),132), ((0,8),68), ((0,9),233), ((80,7),8),
+    ((0,8),92), ((0,8),28), ((0,9),153), ((84,7),83), ((0,8),124),
+    ((0,8),60), ((0,9),217), ((82,7),23), ((0,8),108), ((0,8),44),
+    ((0,9),185), ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),249),
+    ((80,7),3), ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35),
+    ((0,8),114), ((0,8),50), ((0,9),197), ((81,7),11), ((0,8),98),
+    ((0,8),34), ((0,9),165), ((0,8),2), ((0,8),130), ((0,8),66),
+    ((0,9),229), ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),149),
+    ((84,7),67), ((0,8),122), ((0,8),58), ((0,9),213), ((82,7),19),
+    ((0,8),106), ((0,8),42), ((0,9),181), ((0,8),10), ((0,8),138),
+    ((0,8),74), ((0,9),245), ((80,7),5), ((0,8),86), ((0,8),22),
+    ((192,8),0), ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),205),
+    ((81,7),15), ((0,8),102), ((0,8),38), ((0,9),173), ((0,8),6),
+    ((0,8),134), ((0,8),70), ((0,9),237), ((80,7),9), ((0,8),94),
+    ((0,8),30), ((0,9),157), ((84,7),99), ((0,8),126), ((0,8),62),
+    ((0,9),221), ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),189),
+    ((0,8),14), ((0,8),142), ((0,8),78), ((0,9),253), ((96,7),256),
+    ((0,8),81), ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113),
+    ((0,8),49), ((0,9),195), ((80,7),10), ((0,8),97), ((0,8),33),
+    ((0,9),163), ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),227),
+    ((80,7),6), ((0,8),89), ((0,8),25), ((0,9),147), ((83,7),59),
+    ((0,8),121), ((0,8),57), ((0,9),211), ((81,7),17), ((0,8),105),
+    ((0,8),41), ((0,9),179), ((0,8),9), ((0,8),137), ((0,8),73),
+    ((0,9),243), ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258),
+    ((83,7),43), ((0,8),117), ((0,8),53), ((0,9),203), ((81,7),13),
+    ((0,8),101), ((0,8),37), ((0,9),171), ((0,8),5), ((0,8),133),
+    ((0,8),69), ((0,9),235), ((80,7),8), ((0,8),93), ((0,8),29),
+    ((0,9),155), ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),219),
+    ((82,7),23), ((0,8),109), ((0,8),45), ((0,9),187), ((0,8),13),
+    ((0,8),141), ((0,8),77), ((0,9),251), ((80,7),3), ((0,8),83),
+    ((0,8),19), ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51),
+    ((0,9),199), ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),167),
+    ((0,8),3), ((0,8),131), ((0,8),67), ((0,9),231), ((80,7),7),
+    ((0,8),91), ((0,8),27), ((0,9),151), ((84,7),67), ((0,8),123),
+    ((0,8),59), ((0,9),215), ((82,7),19), ((0,8),107), ((0,8),43),
+    ((0,9),183), ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),247),
+    ((80,7),5), ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51),
+    ((0,8),119), ((0,8),55), ((0,9),207), ((81,7),15), ((0,8),103),
+    ((0,8),39), ((0,9),175), ((0,8),7), ((0,8),135), ((0,8),71),
+    ((0,9),239), ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),159),
+    ((84,7),99), ((0,8),127), ((0,8),63), ((0,9),223), ((82,7),27),
+    ((0,8),111), ((0,8),47), ((0,9),191), ((0,8),15), ((0,8),143),
+    ((0,8),79), ((0,9),255)
+  );
+
+{local}
+const
+  fixed_td : array[0..32-1] of inflate_huft = (
+(Exop:80;bits:5;base:1),      (Exop:87;bits:5;base:257),   (Exop:83;bits:5;base:17),
+(Exop:91;bits:5;base:4097),   (Exop:81;bits:5;base),       (Exop:89;bits:5;base:1025),
+(Exop:85;bits:5;base:65),     (Exop:93;bits:5;base:16385), (Exop:80;bits:5;base:3),
+(Exop:88;bits:5;base:513),    (Exop:84;bits:5;base:33),    (Exop:92;bits:5;base:8193),
+(Exop:82;bits:5;base:9),      (Exop:90;bits:5;base:2049),  (Exop:86;bits:5;base:129),
+(Exop:192;bits:5;base:24577), (Exop:80;bits:5;base:2),     (Exop:87;bits:5;base:385),
+(Exop:83;bits:5;base:25),     (Exop:91;bits:5;base:6145),  (Exop:81;bits:5;base:7),
+(Exop:89;bits:5;base:1537),   (Exop:85;bits:5;base:97),    (Exop:93;bits:5;base:24577),
+(Exop:80;bits:5;base:4),      (Exop:88;bits:5;base:769),   (Exop:84;bits:5;base:49),
+(Exop:92;bits:5;base:12289),  (Exop:82;bits:5;base:13),    (Exop:90;bits:5;base:3073),
+(Exop:86;bits:5;base:193),    (Exop:192;bits:5;base:24577)
+  );
+{$ENDIF}
+
+function inflate_trees_fixed(
+var bl : uInt;               { literal desired/actual bit depth }
+var bd : uInt;               { distance desired/actual bit depth }
+var tl : pInflate_huft;      { literal/length tree result }
+var td : pInflate_huft;      { distance tree result }
+var  z : z_stream            { for memory allocation }
+      ) : int;
+type
+  pFixed_table = ^fixed_table;
+  fixed_table = array[0..288-1] of uIntf;
+var
+  k : int;                   { temporary variable }
+  c : pFixed_table;          { length list for huft_build }
+  v : PuIntArray;            { work area for huft_build }
+var
+  f : uInt;                  { number of hufts used in fixed_mem }
+begin
+  { build fixed tables if not already (multiple overlapped executions ok) }
+  if not fixed_built then
+  begin
+    f := 0;
+
+    { allocate memory }
+    c := pFixed_table( ZALLOC(z, 288, sizeof(uInt)) );
+    if (c = Z_NULL) then
+    begin
+      inflate_trees_fixed := Z_MEM_ERROR;
+      exit;
+    end;
+    v := PuIntArray( ZALLOC(z, 288, sizeof(uInt)) );
+    if (v = Z_NULL) then
+    begin
+      ZFREE(z, c);
+      inflate_trees_fixed := Z_MEM_ERROR;
+      exit;
+    end;
+
+    { literal table }
+    for k := 0 to Pred(144) do
+      c^[k] := 8;
+    for k := 144 to Pred(256) do
+      c^[k] := 9;
+    for k := 256 to Pred(280) do
+      c^[k] := 7;
+    for k := 280 to Pred(288) do
+      c^[k] := 8;
+    fixed_bl := 9;
+    huft_build(c^, 288, 257, cplens, cplext, @fixed_tl, fixed_bl,
+               fixed_mem, f, v^);
+
+    { distance table }
+    for k := 0 to Pred(30) do
+      c^[k] := 5;
+    fixed_bd := 5;
+    huft_build(c^, 30, 0, cpdist, cpdext, @fixed_td, fixed_bd,
+               fixed_mem, f, v^);
+
+    { done }
+    ZFREE(z, v);
+    ZFREE(z, c);
+    fixed_built := True;
+  end;
+  bl := fixed_bl;
+  bd := fixed_bd;
+  tl := fixed_tl;
+  td := fixed_td;
+  inflate_trees_fixed := Z_OK;
+end; { inflate_trees_fixed }
+
+
+end.
diff --git a/src/lib/vampimg/ZLib/iminfutil.pas b/src/lib/vampimg/ZLib/iminfutil.pas
new file mode 100644 (file)
index 0000000..384f0d3
--- /dev/null
@@ -0,0 +1,222 @@
+Unit iminfutil;
+
+{ types and macros common to blocks and codes
+  Copyright (C) 1995-1998 Mark Adler
+
+   WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change.
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  imzutil, impaszlib;
+
+{ copy as much as possible from the sliding window to the output area }
+function inflate_flush(var s : inflate_blocks_state;
+                       var z : z_stream;
+                       r : int) : int;
+
+{ And'ing with mask[n] masks the lower n bits }
+const
+  inflate_mask : array[0..17-1] of uInt = (
+    $0000,
+    $0001, $0003, $0007, $000f, $001f, $003f, $007f, $00ff,
+    $01ff, $03ff, $07ff, $0fff, $1fff, $3fff, $7fff, $ffff);
+
+{procedure GRABBITS(j : int);}
+{procedure DUMPBITS(j : int);}
+{procedure NEEDBITS(j : int);}
+
+implementation
+
+{ macros for bit input with no checking and for returning unused bytes }
+procedure GRABBITS(j : int);
+begin
+  {while (k < j) do
+  begin
+    Dec(z^.avail_in);
+    Inc(z^.total_in);
+    b := b or (uLong(z^.next_in^) shl k);
+    Inc(z^.next_in);
+    Inc(k, 8);
+  end;}
+end;
+
+procedure DUMPBITS(j : int);
+begin
+  {b := b shr j;
+  Dec(k, j);}
+end;
+
+procedure NEEDBITS(j : int);
+begin
+ (*
+          while (k < j) do
+          begin
+            {NEEDBYTE;}
+            if (n <> 0) then
+              r :=Z_OK
+            else
+            begin
+              {UPDATE}
+              s.bitb := b;
+              s.bitk := k;
+              z.avail_in := n;
+              Inc(z.total_in, LongInt(p)-LongInt(z.next_in));
+              z.next_in := p;
+              s.write := q;
+              result := inflate_flush(s,z,r);
+              exit;
+            end;
+            Dec(n);
+            b := b or (uLong(p^) shl k);
+            Inc(p);
+            Inc(k, 8);
+          end;
+ *)
+end;
+
+procedure NEEDOUT;
+begin
+ (*
+  if (m = 0) then
+  begin
+    {WRAP}
+    if (q = s.zend) and (s.read <> s.window) then
+    begin
+      q := s.window;
+      if LongInt(q) < LongInt(s.read) then
+        m := uInt(LongInt(s.read)-LongInt(q)-1)
+      else
+        m := uInt(LongInt(s.zend)-LongInt(q));
+    end;
+
+    if (m = 0) then
+    begin
+      {FLUSH}
+      s.write := q;
+      r := inflate_flush(s,z,r);
+      q := s.write;
+      if LongInt(q) < LongInt(s.read) then
+        m := uInt(LongInt(s.read)-LongInt(q)-1)
+      else
+        m := uInt(LongInt(s.zend)-LongInt(q));
+
+      {WRAP}
+      if (q = s.zend) and (s.read <> s.window) then
+      begin
+        q := s.window;
+        if LongInt(q) < LongInt(s.read) then
+          m := uInt(LongInt(s.read)-LongInt(q)-1)
+        else
+          m := uInt(LongInt(s.zend)-LongInt(q));
+      end;
+
+      if (m = 0) then
+      begin
+        {UPDATE}
+        s.bitb := b;
+        s.bitk := k;
+        z.avail_in := n;
+        Inc(z.total_in, LongInt(p)-LongInt(z.next_in));
+        z.next_in := p;
+        s.write := q;
+        result := inflate_flush(s,z,r);
+        exit;
+      end;
+    end;
+  end;
+  r := Z_OK;
+ *)
+end;
+
+{ copy as much as possible from the sliding window to the output area }
+function inflate_flush(var s : inflate_blocks_state;
+                       var z : z_stream;
+                       r : int) : int;
+var
+  n : uInt;
+  p : pBytef;
+  q : pBytef;
+begin
+  { local copies of source and destination pointers }
+  p := z.next_out;
+  q := s.read;
+
+  { compute number of bytes to copy as far as end of window }
+  if ptr2int(q) <= ptr2int(s.write) then
+    n := uInt(ptr2int(s.write) - ptr2int(q))
+  else
+    n := uInt(ptr2int(s.zend) - ptr2int(q));
+  if (n > z.avail_out) then
+    n := z.avail_out;
+  if (n <> 0) and (r = Z_BUF_ERROR) then
+    r := Z_OK;
+
+  { update counters }
+  Dec(z.avail_out, n);
+  Inc(z.total_out, n);
+
+
+  { update check information }
+  if Assigned(s.checkfn) then
+  begin
+    s.check := s.checkfn(s.check, q, n);
+    z.adler := s.check;
+  end;
+
+  { copy as far as end of window }
+  zmemcpy(p, q, n);
+  Inc(p, n);
+  Inc(q, n);
+
+  { see if more to copy at beginning of window }
+  if (q = s.zend) then
+  begin
+    { wrap pointers }
+    q := s.window;
+    if (s.write = s.zend) then
+      s.write := s.window;
+
+    { compute bytes to copy }
+    n := uInt(ptr2int(s.write) - ptr2int(q));
+    if (n > z.avail_out) then
+      n := z.avail_out;
+    if (n <> 0) and (r = Z_BUF_ERROR) then
+      r := Z_OK;
+
+    { update counters }
+    Dec( z.avail_out, n);
+    Inc( z.total_out, n);
+
+    { update check information }
+    if Assigned(s.checkfn) then
+    begin
+      s.check := s.checkfn(s.check, q, n);
+      z.adler := s.check;
+    end;
+
+    { copy }
+    zmemcpy(p, q, n);
+    Inc(p, n);
+    Inc(q, n);
+  end;
+
+
+  { update pointers }
+  z.next_out := p;
+  s.read := q;
+
+  { done }
+  inflate_flush := r;
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/impaszlib.pas b/src/lib/vampimg/ZLib/impaszlib.pas
new file mode 100644 (file)
index 0000000..7827dec
--- /dev/null
@@ -0,0 +1,520 @@
+Unit impaszlib;
+
+
+{ Original:
+   zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.0, Feb 24th, 1998
+
+  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  imzutil;
+
+{ zconf.h -- configuration of the zlib compression library }
+{ zutil.c -- target dependent utility functions for the compression library }
+
+{ The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input. }
+
+
+
+{ Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+  than 64k bytes at a time (needed on systems with 16-bit int). }
+
+{ Maximum value for memLevel in deflateInit2 }
+const
+  MAX_MEM_LEVEL = 9;
+  DEF_MEM_LEVEL = 8; { if MAX_MEM_LEVEL > 8 }
+
+{ Maximum value for windowBits in deflateInit2 and inflateInit2 }
+const
+  MAX_WBITS = 15; { 32K LZ77 window }
+
+{ default windowBits for decompression. MAX_WBITS is for compression only }
+const
+  DEF_WBITS = MAX_WBITS;
+
+{ The memory requirements for deflate are (in bytes):
+            1 shl (windowBits+2)   +  1 shl (memLevel+9)
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     DMAX_WBITS=14 DMAX_MEM_LEVEL=7
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 shl windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects. }
+
+
+{ Huffman code lookup table entry--this entry is four bytes for machines
+  that have 16-bit pointers (e.g. PC's in the small or medium model). }
+
+type
+  pInflate_huft = ^inflate_huft;
+  inflate_huft = Record
+    Exop,             { number of extra bits or operation }
+    bits : Byte;      { number of bits in this code or subcode }
+    {pad : uInt;}       { pad structure to a power of 2 (4 bytes for }
+                      {  16-bit, 8 bytes for 32-bit int's) }
+    base : uInt;      { literal, length base, or distance base }
+                      { or table offset }
+  End;
+
+type
+  huft_field = Array[0..(MaxInt div SizeOf(inflate_huft))-1] of inflate_huft;
+  huft_ptr = ^huft_field;
+type
+  ppInflate_huft = ^pInflate_huft;
+
+type
+  inflate_codes_mode = ( { waiting for "i:"=input, "o:"=output, "x:"=nothing }
+        START,    { x: set up for LEN }
+        LEN,      { i: get length/literal/eob next }
+        LENEXT,   { i: getting length extra (have base) }
+        DIST,     { i: get distance next }
+        DISTEXT,  { i: getting distance extra }
+        COPY,     { o: copying bytes in window, waiting for space }
+        LIT,      { o: got literal, waiting for output space }
+        WASH,     { o: got eob, possibly still output waiting }
+        ZEND,     { x: got eob and all data flushed }
+        BADCODE); { x: got error }
+
+{ inflate codes private state }
+type
+  pInflate_codes_state = ^inflate_codes_state;
+  inflate_codes_state = record
+
+    mode : inflate_codes_mode;        { current inflate_codes mode }
+
+    { mode dependent information }
+    len : uInt;
+    sub : record                      { submode }
+      Case Byte of
+      0:(code : record                { if LEN or DIST, where in tree }
+          tree : pInflate_huft;       { pointer into tree }
+          need : uInt;                { bits needed }
+         end);
+      1:(lit : uInt);                 { if LIT, literal }
+      2:(copy: record                 { if EXT or COPY, where and how much }
+           get : uInt;                { bits to get for extra }
+           dist : uInt;               { distance back to copy from }
+         end);
+    end;
+
+    { mode independent information }
+    lbits : Byte;                     { ltree bits decoded per branch }
+    dbits : Byte;                     { dtree bits decoder per branch }
+    ltree : pInflate_huft;            { literal/length/eob tree }
+    dtree : pInflate_huft;            { distance tree }
+  end;
+
+type
+  check_func = function(check : uLong;
+                        buf : pBytef;
+                        {const buf : array of byte;}
+                  len : uInt) : uLong;
+type
+  inflate_block_mode =
+     (ZTYPE,    { get type bits (3, including end bit) }
+      LENS,     { get lengths for stored }
+      STORED,   { processing stored block }
+      TABLE,    { get table lengths }
+      BTREE,    { get bit lengths tree for a dynamic block }
+      DTREE,    { get length, distance trees for a dynamic block }
+      CODES,    { processing fixed or dynamic block }
+      DRY,      { output remaining window bytes }
+      BLKDONE,  { finished last block, done }
+      BLKBAD);  { got a data error--stuck here }
+
+type
+  pInflate_blocks_state = ^inflate_blocks_state;
+
+{ inflate blocks semi-private state }
+  inflate_blocks_state = record
+
+    mode : inflate_block_mode;     { current inflate_block mode }
+
+    { mode dependent information }
+    sub : record                  { submode }
+    case Byte of
+    0:(left : uInt);              { if STORED, bytes left to copy }
+    1:(trees : record             { if DTREE, decoding info for trees }
+        table : uInt;               { table lengths (14 bits) }
+        index : uInt;               { index into blens (or border) }
+        blens : PuIntArray;         { bit lengths of codes }
+        bb : uInt;                  { bit length tree depth }
+        tb : pInflate_huft;         { bit length decoding tree }
+      end);
+    2:(decode : record            { if CODES, current state }
+        tl : pInflate_huft;
+        td : pInflate_huft;         { trees to free }
+        codes : pInflate_codes_state;
+      end);
+    end;
+    last : boolean;               { true if this block is the last block }
+
+    { mode independent information }
+    bitk : uInt;            { bits in bit buffer }
+    bitb : uLong;           { bit buffer }
+    hufts : huft_ptr; {pInflate_huft;}  { single malloc for tree space }
+    window : pBytef;        { sliding window }
+    zend : pBytef;          { one byte after sliding window }
+    read : pBytef;          { window read pointer }
+    write : pBytef;         { window write pointer }
+    checkfn : check_func;   { check function }
+    check : uLong;          { check on output }
+  end;
+
+type
+  inflate_mode = (
+      METHOD,   { waiting for method byte }
+      FLAG,     { waiting for flag byte }
+      DICT4,    { four dictionary check bytes to go }
+      DICT3,    { three dictionary check bytes to go }
+      DICT2,    { two dictionary check bytes to go }
+      DICT1,    { one dictionary check byte to go }
+      DICT0,    { waiting for inflateSetDictionary }
+      BLOCKS,   { decompressing blocks }
+      CHECK4,   { four check bytes to go }
+      CHECK3,   { three check bytes to go }
+      CHECK2,   { two check bytes to go }
+      CHECK1,   { one check byte to go }
+      DONE,     { finished check, done }
+      BAD);     { got an error--stay here }
+
+{ inflate private state }
+type
+  pInternal_state = ^internal_state; { or point to a deflate_state record }
+  internal_state = record
+
+     mode : inflate_mode;  { current inflate mode }
+
+     { mode dependent information }
+     sub : record          { submode }
+       case byte of
+       0:(method : uInt);  { if FLAGS, method byte }
+       1:(check : record   { if CHECK, check values to compare }
+           was : uLong;        { computed check value }
+           need : uLong;       { stream check value }
+          end);
+       2:(marker : uInt);  { if BAD, inflateSync's marker bytes count }
+     end;
+
+     { mode independent information }
+     nowrap : boolean;      { flag for no wrapper }
+     wbits : uInt;          { log2(window size)  (8..15, defaults to 15) }
+     blocks : pInflate_blocks_state;    { current inflate_blocks state }
+   end;
+
+type
+  alloc_func = function(opaque : voidpf; items : uInt; size : uInt) : voidpf;
+  free_func = procedure(opaque : voidpf; address : voidpf);
+
+type
+  z_streamp = ^z_stream;
+  z_stream = record
+    next_in : pBytef;     { next input byte }
+    avail_in : uInt;      { number of bytes available at next_in }
+    total_in : uLong;     { total nb of input bytes read so far }
+
+    next_out : pBytef;    { next output byte should be put there }
+    avail_out : uInt;     { remaining free space at next_out }
+    total_out : uLong;    { total nb of bytes output so far }
+
+    msg : string[255];         { last error message, '' if no error }
+    state : pInternal_state; { not visible by applications }
+
+    zalloc : alloc_func;  { used to allocate the internal state }
+    zfree : free_func;    { used to free the internal state }
+    opaque : voidpf;      { private data object passed to zalloc and zfree }
+
+    data_type : int;      { best guess about the data type: ascii or binary }
+    adler : uLong;        { adler32 value of the uncompressed data }
+    reserved : uLong;     { reserved for future use }
+  end;
+
+
+{  The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step). }
+
+const  { constants }
+   Z_NO_FLUSH      = 0;
+   Z_PARTIAL_FLUSH = 1;
+   Z_SYNC_FLUSH    = 2;
+   Z_FULL_FLUSH    = 3;
+   Z_FINISH        = 4;
+{ Allowed flush values; see deflate() below for details }
+
+   Z_OK            = 0;
+   Z_STREAM_END    = 1;
+   Z_NEED_DICT     = 2;
+   Z_ERRNO         = (-1);
+   Z_STREAM_ERROR  = (-2);
+   Z_DATA_ERROR    = (-3);
+   Z_MEM_ERROR     = (-4);
+   Z_BUF_ERROR     = (-5);
+   Z_VERSION_ERROR = (-6);
+{ Return codes for the compression/decompression functions. Negative
+  values are errors, positive values are used for special but normal events.}
+
+   Z_NO_COMPRESSION         = 0;
+   Z_BEST_SPEED             = 1;
+   Z_BEST_COMPRESSION       = 9;
+   Z_DEFAULT_COMPRESSION    = (-1);
+{ compression levels }
+
+   Z_FILTERED            = 1;
+   Z_HUFFMAN_ONLY        = 2;
+   Z_DEFAULT_STRATEGY    = 0;
+{ compression strategy; see deflateInit2() below for details }
+
+   Z_BINARY   = 0;
+   Z_ASCII    = 1;
+   Z_UNKNOWN  = 2;
+{ Possible values of the data_type field }
+
+   Z_DEFLATED   = 8;
+{ The deflate compression method (the only one supported in this version) }
+
+   Z_NULL  = NIL;  { for initializing zalloc, zfree, opaque }
+
+  {$IFDEF GZIO}
+var
+  errno : int;
+  {$ENDIF}
+
+        { common constants }
+
+
+{ The three kinds of block type }
+const
+  STORED_BLOCK = 0;
+  STATIC_TREES = 1;
+  DYN_TREES = 2;
+{ The minimum and maximum match lengths }
+const
+  MIN_MATCH = 3;
+  MAX_MATCH = 258;
+
+const
+  PRESET_DICT = $20; { preset dictionary flag in zlib header }
+
+
+  {$IFDEF DEBUG}
+  procedure Assert(cond : boolean; msg : AnsiString);
+  {$ENDIF}
+
+  procedure Trace(x : AnsiString);
+  procedure Tracev(x : AnsiString);
+  procedure Tracevv(x : AnsiString);
+  procedure Tracevvv(x : AnsiString);
+  procedure Tracec(c : boolean; x : AnsiString);
+  procedure Tracecv(c : boolean; x : AnsiString);
+
+function zlibVersion : AnsiString;
+{ The application can compare zlibVersion and ZLIB_VERSION for consistency.
+  If the first character differs, the library code actually used is
+  not compatible with the zlib.h header file used by the application.
+  This check is automatically made by deflateInit and inflateInit. }
+
+function zError(err : int) : AnsiString;
+function ZALLOC (var strm : z_stream; items : uInt; size : uInt) : voidpf;
+procedure ZFREE (var strm : z_stream; ptr : voidpf);
+procedure TRY_FREE (var strm : z_stream; ptr : voidpf);
+
+const
+  ZLIB_VERSION : string[10] = '1.1.2';
+
+const
+  z_errbase = Z_NEED_DICT;
+  z_errmsg : Array[0..9] of string[21] = { indexed by 2-zlib_error }
+           ('need dictionary',     { Z_NEED_DICT       2  }
+            'stream end',          { Z_STREAM_END      1  }
+            '',                    { Z_OK              0  }
+            'file error',          { Z_ERRNO         (-1) }
+            'stream error',        { Z_STREAM_ERROR  (-2) }
+            'data error',          { Z_DATA_ERROR    (-3) }
+            'insufficient memory', { Z_MEM_ERROR     (-4) }
+            'buffer error',        { Z_BUF_ERROR     (-5) }
+            'incompatible version',{ Z_VERSION_ERROR (-6) }
+            '');
+const
+  z_verbose : int = 1;
+
+function deflateInit_(var Stream: z_stream; Level: LongInt; const Version: AnsiString;
+  Stream_size: LongInt): LongInt;
+function inflateInit_(var Stream: z_stream; const Version: AnsiString;
+  Stream_size: Longint): LongInt;
+
+{$IFDEF DEBUG}
+procedure z_error (m : string);
+{$ENDIF}
+
+implementation
+
+uses
+  imzdeflate, imzinflate;
+
+function deflateInit_(var Stream: z_stream; Level: LongInt; const Version: AnsiString;
+  Stream_size: LongInt): LongInt;
+begin
+  Result := imzdeflate.deflateInit_(@Stream, Level, Version, Stream_size);
+end;
+
+function inflateInit_(var Stream: z_stream; const Version: AnsiString;
+  Stream_size: Longint): LongInt;
+begin
+  Result := imzinflate.inflateInit_(@Stream, Version, Stream_size);
+end;
+
+function zError(err : int) : AnsiString;
+begin
+  zError := z_errmsg[Z_NEED_DICT-err];
+end;
+
+function zlibVersion : AnsiString;
+begin
+  zlibVersion := ZLIB_VERSION;
+end;
+
+procedure z_error (m : AnsiString);
+begin
+  WriteLn(output, m);
+  Write('Zlib - Halt...');
+  ReadLn;
+  Halt(1);
+end;
+
+procedure Assert(cond : boolean; msg : AnsiString);
+begin
+  if not cond then
+    z_error(msg);
+end;
+
+procedure Trace(x : AnsiString);
+begin
+  WriteLn(x);
+end;
+
+procedure Tracev(x : AnsiString);
+begin
+ if (z_verbose>0) then
+   WriteLn(x);
+end;
+
+procedure Tracevv(x : AnsiString);
+begin
+  if (z_verbose>1) then
+    WriteLn(x);
+end;
+
+procedure Tracevvv(x : AnsiString);
+begin
+  if (z_verbose>2) then
+    WriteLn(x);
+end;
+
+procedure Tracec(c : boolean; x : AnsiString);
+begin
+  if (z_verbose>0) and (c) then
+    WriteLn(x);
+end;
+
+procedure Tracecv(c : boolean; x : AnsiString);
+begin
+  if (z_verbose>1) and c then
+    WriteLn(x);
+end;
+
+function ZALLOC (var strm : z_stream; items : uInt; size : uInt) : voidpf;
+begin
+  ZALLOC := strm.zalloc(strm.opaque, items, size);
+end;
+
+procedure ZFREE (var strm : z_stream; ptr : voidpf);
+begin
+  strm.zfree(strm.opaque, ptr);
+end;
+
+procedure TRY_FREE (var strm : z_stream; ptr : voidpf);
+begin
+  {if @strm <> Z_NULL then}
+    strm.zfree(strm.opaque, ptr);
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/imtrees.pas b/src/lib/vampimg/ZLib/imtrees.pas
new file mode 100644 (file)
index 0000000..8f1f559
--- /dev/null
@@ -0,0 +1,2249 @@
+Unit imtrees;
+
+{$T-}
+{$define ORG_DEBUG}
+{
+  trees.c -- output deflated data using Huffman coding
+  Copyright (C) 1995-1998 Jean-loup Gailly
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+{
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ }
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  {$ifdef DEBUG}
+  SysUtils, strutils,
+  {$ENDIF}
+  imzutil, impaszlib;
+
+{ ===========================================================================
+  Internal compression state. }
+
+const
+  LENGTH_CODES = 29;
+{ number of length codes, not counting the special END_BLOCK code }
+
+  LITERALS = 256;
+{ number of literal bytes 0..255 }
+
+  L_CODES = (LITERALS+1+LENGTH_CODES);
+{ number of Literal or Length codes, including the END_BLOCK code }
+
+  D_CODES = 30;
+{ number of distance codes }
+
+  BL_CODES = 19;
+{ number of codes used to transfer the bit lengths }
+
+  HEAP_SIZE = (2*L_CODES+1);
+{ maximum heap size }
+
+  MAX_BITS = 15;
+{ All codes must not exceed MAX_BITS bits }
+
+const
+  INIT_STATE =  42;
+  BUSY_STATE =  113;
+  FINISH_STATE = 666;
+{ Stream status }
+
+
+{ Data structure describing a single value and its code string. }
+type
+  ct_data_ptr = ^ct_data;
+  ct_data = record
+    fc : record
+      case byte of
+      0:(freq : ush);       { frequency count }
+      1:(code : ush);       { bit string }
+    end;
+    dl : record
+      case byte of
+      0:(dad : ush);        { father node in Huffman tree }
+      1:(len : ush);        { length of bit string }
+    end;
+  end;
+
+{ Freq = fc.freq
+ Code = fc.code
+ Dad = dl.dad
+ Len = dl.len }
+
+type
+  ltree_type = array[0..HEAP_SIZE-1] of ct_data;    { literal and length tree }
+  dtree_type = array[0..2*D_CODES+1-1] of ct_data;  { distance tree }
+  htree_type = array[0..2*BL_CODES+1-1] of ct_data;  { Huffman tree for bit lengths }
+  { generic tree type }
+  tree_type = array[0..(MaxInt div SizeOf(ct_data))-1] of ct_data;
+
+  tree_ptr = ^tree_type;
+  ltree_ptr = ^ltree_type;
+  dtree_ptr = ^dtree_type;
+  htree_ptr = ^htree_type;
+
+
+type
+  static_tree_desc_ptr = ^static_tree_desc;
+  static_tree_desc =
+         record
+    {const} static_tree : tree_ptr;     { static tree or NIL }
+    {const} extra_bits : pzIntfArray;   { extra bits for each code or NIL }
+            extra_base : int;           { base index for extra_bits }
+            elems : int;                { max number of elements in the tree }
+            max_length : int;           { max bit length for the codes }
+          end;
+
+  tree_desc_ptr = ^tree_desc;
+  tree_desc = record
+    dyn_tree : tree_ptr;    { the dynamic tree }
+    max_code : int;            { largest code with non zero frequency }
+    stat_desc : static_tree_desc_ptr; { the corresponding static tree }
+  end;
+
+type
+  Pos = ush;
+  Posf = Pos; {FAR}
+  IPos = uInt;
+
+  pPosf = ^Posf;
+
+  zPosfArray = array[0..(MaxInt div SizeOf(Posf))-1] of Posf;
+  pzPosfArray = ^zPosfArray;
+
+{ A Pos is an index in the character window. We use short instead of int to
+  save space in the various tables. IPos is used only for parameter passing.}
+
+type
+  deflate_state_ptr = ^deflate_state;
+  deflate_state = record
+    strm : z_streamp;          { pointer back to this zlib stream }
+    status : int;              { as the name implies }
+    pending_buf : pzByteArray; { output still pending }
+    pending_buf_size : ulg;    { size of pending_buf }
+    pending_out : pBytef;      { next pending byte to output to the stream }
+    pending : int;             { nb of bytes in the pending buffer }
+    noheader : int;            { suppress zlib header and adler32 }
+    data_type : Byte;          { UNKNOWN, BINARY or ASCII }
+    method : Byte;             { STORED (for zip only) or DEFLATED }
+    last_flush : int;          { value of flush param for previous deflate call }
+
+                { used by deflate.pas: }
+
+    w_size : uInt;             { LZ77 window size (32K by default) }
+    w_bits : uInt;             { log2(w_size)  (8..16) }
+    w_mask : uInt;             { w_size - 1 }
+
+    window : pzByteArray;
+    { Sliding window. Input bytes are read into the second half of the window,
+      and move to the first half later to keep a dictionary of at least wSize
+      bytes. With this organization, matches are limited to a distance of
+      wSize-MAX_MATCH bytes, but this ensures that IO is always
+      performed with a length multiple of the block size. Also, it limits
+      the window size to 64K, which is quite useful on MSDOS.
+      To do: use the user input buffer as sliding window. }
+
+    window_size : ulg;
+    { Actual size of window: 2*wSize, except when the user input buffer
+      is directly used as sliding window. }
+
+    prev : pzPosfArray;
+    { Link to older string with same hash index. To limit the size of this
+      array to 64K, this link is maintained only for the last 32K strings.
+      An index in this array is thus a window index modulo 32K. }
+
+    head : pzPosfArray;    { Heads of the hash chains or NIL. }
+
+    ins_h : uInt;          { hash index of string to be inserted }
+    hash_size : uInt;      { number of elements in hash table }
+    hash_bits : uInt;      { log2(hash_size) }
+    hash_mask : uInt;      { hash_size-1 }
+
+    hash_shift : uInt;
+    { Number of bits by which ins_h must be shifted at each input
+      step. It must be such that after MIN_MATCH steps, the oldest
+      byte no longer takes part in the hash key, that is:
+        hash_shift * MIN_MATCH >= hash_bits     }
+
+    block_start : long;
+    { Window position at the beginning of the current output block. Gets
+      negative when the window is moved backwards. }
+
+    match_length : uInt;           { length of best match }
+    prev_match : IPos;             { previous match }
+    match_available : boolean;     { set if previous match exists }
+    strstart : uInt;               { start of string to insert }
+    match_start : uInt;            { start of matching string }
+    lookahead : uInt;              { number of valid bytes ahead in window }
+
+    prev_length : uInt;
+    { Length of the best match at previous step. Matches not greater than this
+      are discarded. This is used in the lazy match evaluation. }
+
+    max_chain_length : uInt;
+    { To speed up deflation, hash chains are never searched beyond this
+      length.  A higher limit improves compression ratio but degrades the
+      speed. }
+
+    { moved to the end because Borland Pascal won't accept the following:
+    max_lazy_match : uInt;
+    max_insert_length : uInt absolute max_lazy_match;
+    }
+
+    level : int;    { compression level (1..9) }
+    strategy : int; { favor or force Huffman coding}
+
+    good_match : uInt;
+    { Use a faster search when the previous match is longer than this }
+
+    nice_match : int; { Stop searching when current match exceeds this }
+
+                { used by trees.pas: }
+    { Didn't use ct_data typedef below to supress compiler warning }
+    dyn_ltree : ltree_type;    { literal and length tree }
+    dyn_dtree : dtree_type;  { distance tree }
+    bl_tree : htree_type;   { Huffman tree for bit lengths }
+
+    l_desc : tree_desc;                { desc. for literal tree }
+    d_desc : tree_desc;                { desc. for distance tree }
+    bl_desc : tree_desc;               { desc. for bit length tree }
+
+    bl_count : array[0..MAX_BITS+1-1] of ush;
+    { number of codes at each bit length for an optimal tree }
+
+    heap : array[0..2*L_CODES+1-1] of int; { heap used to build the Huffman trees }
+    heap_len : int;                   { number of elements in the heap }
+    heap_max : int;                   { element of largest frequency }
+    { The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+      The same heap array is used to build all trees. }
+
+    depth : array[0..2*L_CODES+1-1] of uch;
+    { Depth of each subtree used as tie breaker for trees of equal frequency }
+
+
+    l_buf : puchfArray;       { buffer for literals or lengths }
+
+    lit_bufsize : uInt;
+    { Size of match buffer for literals/lengths.  There are 4 reasons for
+      limiting lit_bufsize to 64K:
+        - frequencies can be kept in 16 bit counters
+        - if compression is not successful for the first block, all input
+          data is still in the window so we can still emit a stored block even
+          when input comes from standard input.  (This can also be done for
+          all blocks if lit_bufsize is not greater than 32K.)
+        - if compression is not successful for a file smaller than 64K, we can
+          even emit a stored file instead of a stored block (saving 5 bytes).
+          This is applicable only for zip (not gzip or zlib).
+        - creating new Huffman trees less frequently may not provide fast
+          adaptation to changes in the input data statistics. (Take for
+          example a binary file with poorly compressible code followed by
+          a highly compressible string table.) Smaller buffer sizes give
+          fast adaptation but have of course the overhead of transmitting
+          trees more frequently.
+        - I can't count above 4 }
+
+
+    last_lit : uInt;      { running index in l_buf }
+
+    d_buf : pushfArray;
+    { Buffer for distances. To simplify the code, d_buf and l_buf have
+      the same number of elements. To use different lengths, an extra flag
+      array would be necessary. }
+
+    opt_len : ulg;        { bit length of current block with optimal trees }
+    static_len : ulg;     { bit length of current block with static trees }
+    compressed_len : ulg; { total bit length of compressed file }
+    matches : uInt;       { number of string matches in current block }
+    last_eob_len : int;   { bit length of EOB code for last block }
+
+{$ifdef DEBUG}
+    bits_sent : ulg;    { bit length of the compressed data }
+{$endif}
+
+    bi_buf : ush;
+    { Output buffer. bits are inserted starting at the bottom (least
+      significant bits). }
+
+    bi_valid : int;
+    { Number of valid bits in bi_buf.  All bits above the last valid bit
+      are always zero. }
+
+    case byte of
+    0:(max_lazy_match : uInt);
+    { Attempt to find a better match only when the current match is strictly
+      smaller than this value. This mechanism is used only for compression
+      levels >= 4. }
+
+    1:(max_insert_length : uInt);
+    { Insert new strings in the hash table only if the match length is not
+      greater than this length. This saves time but degrades compression.
+      max_insert_length is used only for compression levels <= 3. }
+  end;
+
+procedure _tr_init (var s : deflate_state);
+
+function _tr_tally (var s : deflate_state;
+                    dist : unsigned;
+                    lc : unsigned) : boolean;
+
+function _tr_flush_block (var s : deflate_state;
+                          buf : pcharf;
+                          stored_len : ulg;
+        eof : boolean) : ulg;
+
+procedure _tr_align(var s : deflate_state);
+
+procedure _tr_stored_block(var s : deflate_state;
+                           buf : pcharf;
+                           stored_len : ulg;
+                           eof : boolean);
+
+implementation
+
+{ #define GEN_TREES_H }
+
+{$ifndef GEN_TREES_H}
+{ header created automatically with -DGEN_TREES_H }
+
+const
+  DIST_CODE_LEN = 512; { see definition of array dist_code below }
+
+{ The static literal tree. Since the bit lengths are imposed, there is no
+  need for the L_CODES extra codes used during heap construction. However
+  The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+  below). }
+var
+  static_ltree : array[0..L_CODES+2-1] of ct_data = (
+{ fc:(freq, code) dl:(dad,len) }
+(fc:(freq: 12);dl:(len: 8)), (fc:(freq:140);dl:(len: 8)), (fc:(freq: 76);dl:(len: 8)),
+(fc:(freq:204);dl:(len: 8)), (fc:(freq: 44);dl:(len: 8)), (fc:(freq:172);dl:(len: 8)),
+(fc:(freq:108);dl:(len: 8)), (fc:(freq:236);dl:(len: 8)), (fc:(freq: 28);dl:(len: 8)),
+(fc:(freq:156);dl:(len: 8)), (fc:(freq: 92);dl:(len: 8)), (fc:(freq:220);dl:(len: 8)),
+(fc:(freq: 60);dl:(len: 8)), (fc:(freq:188);dl:(len: 8)), (fc:(freq:124);dl:(len: 8)),
+(fc:(freq:252);dl:(len: 8)), (fc:(freq:  2);dl:(len: 8)), (fc:(freq:130);dl:(len: 8)),
+(fc:(freq: 66);dl:(len: 8)), (fc:(freq:194);dl:(len: 8)), (fc:(freq: 34);dl:(len: 8)),
+(fc:(freq:162);dl:(len: 8)), (fc:(freq: 98);dl:(len: 8)), (fc:(freq:226);dl:(len: 8)),
+(fc:(freq: 18);dl:(len: 8)), (fc:(freq:146);dl:(len: 8)), (fc:(freq: 82);dl:(len: 8)),
+(fc:(freq:210);dl:(len: 8)), (fc:(freq: 50);dl:(len: 8)), (fc:(freq:178);dl:(len: 8)),
+(fc:(freq:114);dl:(len: 8)), (fc:(freq:242);dl:(len: 8)), (fc:(freq: 10);dl:(len: 8)),
+(fc:(freq:138);dl:(len: 8)), (fc:(freq: 74);dl:(len: 8)), (fc:(freq:202);dl:(len: 8)),
+(fc:(freq: 42);dl:(len: 8)), (fc:(freq:170);dl:(len: 8)), (fc:(freq:106);dl:(len: 8)),
+(fc:(freq:234);dl:(len: 8)), (fc:(freq: 26);dl:(len: 8)), (fc:(freq:154);dl:(len: 8)),
+(fc:(freq: 90);dl:(len: 8)), (fc:(freq:218);dl:(len: 8)), (fc:(freq: 58);dl:(len: 8)),
+(fc:(freq:186);dl:(len: 8)), (fc:(freq:122);dl:(len: 8)), (fc:(freq:250);dl:(len: 8)),
+(fc:(freq:  6);dl:(len: 8)), (fc:(freq:134);dl:(len: 8)), (fc:(freq: 70);dl:(len: 8)),
+(fc:(freq:198);dl:(len: 8)), (fc:(freq: 38);dl:(len: 8)), (fc:(freq:166);dl:(len: 8)),
+(fc:(freq:102);dl:(len: 8)), (fc:(freq:230);dl:(len: 8)), (fc:(freq: 22);dl:(len: 8)),
+(fc:(freq:150);dl:(len: 8)), (fc:(freq: 86);dl:(len: 8)), (fc:(freq:214);dl:(len: 8)),
+(fc:(freq: 54);dl:(len: 8)), (fc:(freq:182);dl:(len: 8)), (fc:(freq:118);dl:(len: 8)),
+(fc:(freq:246);dl:(len: 8)), (fc:(freq: 14);dl:(len: 8)), (fc:(freq:142);dl:(len: 8)),
+(fc:(freq: 78);dl:(len: 8)), (fc:(freq:206);dl:(len: 8)), (fc:(freq: 46);dl:(len: 8)),
+(fc:(freq:174);dl:(len: 8)), (fc:(freq:110);dl:(len: 8)), (fc:(freq:238);dl:(len: 8)),
+(fc:(freq: 30);dl:(len: 8)), (fc:(freq:158);dl:(len: 8)), (fc:(freq: 94);dl:(len: 8)),
+(fc:(freq:222);dl:(len: 8)), (fc:(freq: 62);dl:(len: 8)), (fc:(freq:190);dl:(len: 8)),
+(fc:(freq:126);dl:(len: 8)), (fc:(freq:254);dl:(len: 8)), (fc:(freq:  1);dl:(len: 8)),
+(fc:(freq:129);dl:(len: 8)), (fc:(freq: 65);dl:(len: 8)), (fc:(freq:193);dl:(len: 8)),
+(fc:(freq: 33);dl:(len: 8)), (fc:(freq:161);dl:(len: 8)), (fc:(freq: 97);dl:(len: 8)),
+(fc:(freq:225);dl:(len: 8)), (fc:(freq: 17);dl:(len: 8)), (fc:(freq:145);dl:(len: 8)),
+(fc:(freq: 81);dl:(len: 8)), (fc:(freq:209);dl:(len: 8)), (fc:(freq: 49);dl:(len: 8)),
+(fc:(freq:177);dl:(len: 8)), (fc:(freq:113);dl:(len: 8)), (fc:(freq:241);dl:(len: 8)),
+(fc:(freq:  9);dl:(len: 8)), (fc:(freq:137);dl:(len: 8)), (fc:(freq: 73);dl:(len: 8)),
+(fc:(freq:201);dl:(len: 8)), (fc:(freq: 41);dl:(len: 8)), (fc:(freq:169);dl:(len: 8)),
+(fc:(freq:105);dl:(len: 8)), (fc:(freq:233);dl:(len: 8)), (fc:(freq: 25);dl:(len: 8)),
+(fc:(freq:153);dl:(len: 8)), (fc:(freq: 89);dl:(len: 8)), (fc:(freq:217);dl:(len: 8)),
+(fc:(freq: 57);dl:(len: 8)), (fc:(freq:185);dl:(len: 8)), (fc:(freq:121);dl:(len: 8)),
+(fc:(freq:249);dl:(len: 8)), (fc:(freq:  5);dl:(len: 8)), (fc:(freq:133);dl:(len: 8)),
+(fc:(freq: 69);dl:(len: 8)), (fc:(freq:197);dl:(len: 8)), (fc:(freq: 37);dl:(len: 8)),
+(fc:(freq:165);dl:(len: 8)), (fc:(freq:101);dl:(len: 8)), (fc:(freq:229);dl:(len: 8)),
+(fc:(freq: 21);dl:(len: 8)), (fc:(freq:149);dl:(len: 8)), (fc:(freq: 85);dl:(len: 8)),
+(fc:(freq:213);dl:(len: 8)), (fc:(freq: 53);dl:(len: 8)), (fc:(freq:181);dl:(len: 8)),
+(fc:(freq:117);dl:(len: 8)), (fc:(freq:245);dl:(len: 8)), (fc:(freq: 13);dl:(len: 8)),
+(fc:(freq:141);dl:(len: 8)), (fc:(freq: 77);dl:(len: 8)), (fc:(freq:205);dl:(len: 8)),
+(fc:(freq: 45);dl:(len: 8)), (fc:(freq:173);dl:(len: 8)), (fc:(freq:109);dl:(len: 8)),
+(fc:(freq:237);dl:(len: 8)), (fc:(freq: 29);dl:(len: 8)), (fc:(freq:157);dl:(len: 8)),
+(fc:(freq: 93);dl:(len: 8)), (fc:(freq:221);dl:(len: 8)), (fc:(freq: 61);dl:(len: 8)),
+(fc:(freq:189);dl:(len: 8)), (fc:(freq:125);dl:(len: 8)), (fc:(freq:253);dl:(len: 8)),
+(fc:(freq: 19);dl:(len: 9)), (fc:(freq:275);dl:(len: 9)), (fc:(freq:147);dl:(len: 9)),
+(fc:(freq:403);dl:(len: 9)), (fc:(freq: 83);dl:(len: 9)), (fc:(freq:339);dl:(len: 9)),
+(fc:(freq:211);dl:(len: 9)), (fc:(freq:467);dl:(len: 9)), (fc:(freq: 51);dl:(len: 9)),
+(fc:(freq:307);dl:(len: 9)), (fc:(freq:179);dl:(len: 9)), (fc:(freq:435);dl:(len: 9)),
+(fc:(freq:115);dl:(len: 9)), (fc:(freq:371);dl:(len: 9)), (fc:(freq:243);dl:(len: 9)),
+(fc:(freq:499);dl:(len: 9)), (fc:(freq: 11);dl:(len: 9)), (fc:(freq:267);dl:(len: 9)),
+(fc:(freq:139);dl:(len: 9)), (fc:(freq:395);dl:(len: 9)), (fc:(freq: 75);dl:(len: 9)),
+(fc:(freq:331);dl:(len: 9)), (fc:(freq:203);dl:(len: 9)), (fc:(freq:459);dl:(len: 9)),
+(fc:(freq: 43);dl:(len: 9)), (fc:(freq:299);dl:(len: 9)), (fc:(freq:171);dl:(len: 9)),
+(fc:(freq:427);dl:(len: 9)), (fc:(freq:107);dl:(len: 9)), (fc:(freq:363);dl:(len: 9)),
+(fc:(freq:235);dl:(len: 9)), (fc:(freq:491);dl:(len: 9)), (fc:(freq: 27);dl:(len: 9)),
+(fc:(freq:283);dl:(len: 9)), (fc:(freq:155);dl:(len: 9)), (fc:(freq:411);dl:(len: 9)),
+(fc:(freq: 91);dl:(len: 9)), (fc:(freq:347);dl:(len: 9)), (fc:(freq:219);dl:(len: 9)),
+(fc:(freq:475);dl:(len: 9)), (fc:(freq: 59);dl:(len: 9)), (fc:(freq:315);dl:(len: 9)),
+(fc:(freq:187);dl:(len: 9)), (fc:(freq:443);dl:(len: 9)), (fc:(freq:123);dl:(len: 9)),
+(fc:(freq:379);dl:(len: 9)), (fc:(freq:251);dl:(len: 9)), (fc:(freq:507);dl:(len: 9)),
+(fc:(freq:  7);dl:(len: 9)), (fc:(freq:263);dl:(len: 9)), (fc:(freq:135);dl:(len: 9)),
+(fc:(freq:391);dl:(len: 9)), (fc:(freq: 71);dl:(len: 9)), (fc:(freq:327);dl:(len: 9)),
+(fc:(freq:199);dl:(len: 9)), (fc:(freq:455);dl:(len: 9)), (fc:(freq: 39);dl:(len: 9)),
+(fc:(freq:295);dl:(len: 9)), (fc:(freq:167);dl:(len: 9)), (fc:(freq:423);dl:(len: 9)),
+(fc:(freq:103);dl:(len: 9)), (fc:(freq:359);dl:(len: 9)), (fc:(freq:231);dl:(len: 9)),
+(fc:(freq:487);dl:(len: 9)), (fc:(freq: 23);dl:(len: 9)), (fc:(freq:279);dl:(len: 9)),
+(fc:(freq:151);dl:(len: 9)), (fc:(freq:407);dl:(len: 9)), (fc:(freq: 87);dl:(len: 9)),
+(fc:(freq:343);dl:(len: 9)), (fc:(freq:215);dl:(len: 9)), (fc:(freq:471);dl:(len: 9)),
+(fc:(freq: 55);dl:(len: 9)), (fc:(freq:311);dl:(len: 9)), (fc:(freq:183);dl:(len: 9)),
+(fc:(freq:439);dl:(len: 9)), (fc:(freq:119);dl:(len: 9)), (fc:(freq:375);dl:(len: 9)),
+(fc:(freq:247);dl:(len: 9)), (fc:(freq:503);dl:(len: 9)), (fc:(freq: 15);dl:(len: 9)),
+(fc:(freq:271);dl:(len: 9)), (fc:(freq:143);dl:(len: 9)), (fc:(freq:399);dl:(len: 9)),
+(fc:(freq: 79);dl:(len: 9)), (fc:(freq:335);dl:(len: 9)), (fc:(freq:207);dl:(len: 9)),
+(fc:(freq:463);dl:(len: 9)), (fc:(freq: 47);dl:(len: 9)), (fc:(freq:303);dl:(len: 9)),
+(fc:(freq:175);dl:(len: 9)), (fc:(freq:431);dl:(len: 9)), (fc:(freq:111);dl:(len: 9)),
+(fc:(freq:367);dl:(len: 9)), (fc:(freq:239);dl:(len: 9)), (fc:(freq:495);dl:(len: 9)),
+(fc:(freq: 31);dl:(len: 9)), (fc:(freq:287);dl:(len: 9)), (fc:(freq:159);dl:(len: 9)),
+(fc:(freq:415);dl:(len: 9)), (fc:(freq: 95);dl:(len: 9)), (fc:(freq:351);dl:(len: 9)),
+(fc:(freq:223);dl:(len: 9)), (fc:(freq:479);dl:(len: 9)), (fc:(freq: 63);dl:(len: 9)),
+(fc:(freq:319);dl:(len: 9)), (fc:(freq:191);dl:(len: 9)), (fc:(freq:447);dl:(len: 9)),
+(fc:(freq:127);dl:(len: 9)), (fc:(freq:383);dl:(len: 9)), (fc:(freq:255);dl:(len: 9)),
+(fc:(freq:511);dl:(len: 9)), (fc:(freq:  0);dl:(len: 7)), (fc:(freq: 64);dl:(len: 7)),
+(fc:(freq: 32);dl:(len: 7)), (fc:(freq: 96);dl:(len: 7)), (fc:(freq: 16);dl:(len: 7)),
+(fc:(freq: 80);dl:(len: 7)), (fc:(freq: 48);dl:(len: 7)), (fc:(freq:112);dl:(len: 7)),
+(fc:(freq:  8);dl:(len: 7)), (fc:(freq: 72);dl:(len: 7)), (fc:(freq: 40);dl:(len: 7)),
+(fc:(freq:104);dl:(len: 7)), (fc:(freq: 24);dl:(len: 7)), (fc:(freq: 88);dl:(len: 7)),
+(fc:(freq: 56);dl:(len: 7)), (fc:(freq:120);dl:(len: 7)), (fc:(freq:  4);dl:(len: 7)),
+(fc:(freq: 68);dl:(len: 7)), (fc:(freq: 36);dl:(len: 7)), (fc:(freq:100);dl:(len: 7)),
+(fc:(freq: 20);dl:(len: 7)), (fc:(freq: 84);dl:(len: 7)), (fc:(freq: 52);dl:(len: 7)),
+(fc:(freq:116);dl:(len: 7)), (fc:(freq:  3);dl:(len: 8)), (fc:(freq:131);dl:(len: 8)),
+(fc:(freq: 67);dl:(len: 8)), (fc:(freq:195);dl:(len: 8)), (fc:(freq: 35);dl:(len: 8)),
+(fc:(freq:163);dl:(len: 8)), (fc:(freq: 99);dl:(len: 8)), (fc:(freq:227);dl:(len: 8))
+);
+
+
+{ The static distance tree. (Actually a trivial tree since all lens use
+  5 bits.) }
+  static_dtree : array[0..D_CODES-1] of ct_data = (
+(fc:(freq: 0); dl:(len:5)), (fc:(freq:16); dl:(len:5)), (fc:(freq: 8); dl:(len:5)),
+(fc:(freq:24); dl:(len:5)), (fc:(freq: 4); dl:(len:5)), (fc:(freq:20); dl:(len:5)),
+(fc:(freq:12); dl:(len:5)), (fc:(freq:28); dl:(len:5)), (fc:(freq: 2); dl:(len:5)),
+(fc:(freq:18); dl:(len:5)), (fc:(freq:10); dl:(len:5)), (fc:(freq:26); dl:(len:5)),
+(fc:(freq: 6); dl:(len:5)), (fc:(freq:22); dl:(len:5)), (fc:(freq:14); dl:(len:5)),
+(fc:(freq:30); dl:(len:5)), (fc:(freq: 1); dl:(len:5)), (fc:(freq:17); dl:(len:5)),
+(fc:(freq: 9); dl:(len:5)), (fc:(freq:25); dl:(len:5)), (fc:(freq: 5); dl:(len:5)),
+(fc:(freq:21); dl:(len:5)), (fc:(freq:13); dl:(len:5)), (fc:(freq:29); dl:(len:5)),
+(fc:(freq: 3); dl:(len:5)), (fc:(freq:19); dl:(len:5)), (fc:(freq:11); dl:(len:5)),
+(fc:(freq:27); dl:(len:5)), (fc:(freq: 7); dl:(len:5)), (fc:(freq:23); dl:(len:5))
+);
+
+{ Distance codes. The first 256 values correspond to the distances
+  3 .. 258, the last 256 values correspond to the top 8 bits of
+  the 15 bit distances. }
+  _dist_code : array[0..DIST_CODE_LEN-1] of uch = (
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+);
+
+{ length code for each normalized match length (0 == MIN_MATCH) }
+  _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of uch = (
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+);
+
+
+{ First normalized length for each code (0 = MIN_MATCH) }
+  base_length : array[0..LENGTH_CODES-1] of int = (
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+);
+
+
+{ First normalized distance for each code (0 = distance of 1) }
+  base_dist : array[0..D_CODES-1] of int = (
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+);
+{$endif}
+
+{ Output a byte on the stream.
+  IN assertion: there is enough room in pending_buf.
+macro put_byte(s, c)
+begin
+  s^.pending_buf^[s^.pending] := (c);
+  Inc(s^.pending);
+end
+}
+
+const
+  MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1);
+{ Minimum amount of lookahead, except at the end of the input file.
+  See deflate.c for comments about the MIN_MATCH+1. }
+
+{macro d_code(dist)
+   if (dist) < 256 then
+     := _dist_code[dist]
+   else
+     := _dist_code[256+((dist) shr 7)]);
+  Mapping from a distance to a distance code. dist is the distance - 1 and
+  must not have side effects. _dist_code[256] and _dist_code[257] are never
+  used. }
+
+{$ifndef ORG_DEBUG}
+{ Inline versions of _tr_tally for speed: }
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch _length_code[];
+  extern uch _dist_code[];
+#else
+  extern const uch _length_code[];
+  extern const uch _dist_code[];
+#endif
+
+macro _tr_tally_lit(s, c, flush)
+var
+  cc : uch;
+begin
+    cc := (c);
+    s^.d_buf[s^.last_lit] := 0;
+    s^.l_buf[s^.last_lit] := cc;
+    Inc(s^.last_lit);
+    Inc(s^.dyn_ltree[cc].fc.Freq);
+    flush := (s^.last_lit = s^.lit_bufsize-1);
+end;
+
+macro _tr_tally_dist(s, distance, length, flush) \
+var
+  len : uch;
+  dist : ush;
+begin
+    len := (length);
+    dist := (distance);
+    s^.d_buf[s^.last_lit] := dist;
+    s^.l_buf[s^.last_lit] = len;
+    Inc(s^.last_lit);
+    Dec(dist);
+    Inc(s^.dyn_ltree[_length_code[len]+LITERALS+1].fc.Freq);
+    Inc(s^.dyn_dtree[d_code(dist)].Freq);
+    flush := (s^.last_lit = s^.lit_bufsize-1);
+end;
+
+{$endif}
+
+{ ===========================================================================
+  Constants }
+
+const
+  MAX_BL_BITS = 7;
+{ Bit length codes must not exceed MAX_BL_BITS bits }
+
+const
+  END_BLOCK = 256;
+{ end of block literal code }
+
+const
+  REP_3_6 = 16;
+{ repeat previous bit length 3-6 times (2 bits of repeat count) }
+
+const
+  REPZ_3_10 = 17;
+{ repeat a zero length 3-10 times  (3 bits of repeat count) }
+
+const
+  REPZ_11_138 = 18;
+{ repeat a zero length 11-138 times  (7 bits of repeat count) }
+
+{local}
+const
+  extra_lbits : array[0..LENGTH_CODES-1] of int
+    { extra bits for each length code }
+   = (0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0);
+
+{local}
+const
+  extra_dbits : array[0..D_CODES-1] of int
+    { extra bits for each distance code }
+   = (0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13);
+
+{local}
+const
+  extra_blbits : array[0..BL_CODES-1] of int { extra bits for each bit length code }
+   = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7);
+
+{local}
+const
+  bl_order : array[0..BL_CODES-1] of uch
+   = (16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15);
+{ The lengths of the bit length codes are sent in order of decreasing
+  probability, to avoid transmitting the lengths for unused bit length codes.
+ }
+
+const
+  Buf_size = (8 * 2*sizeof(uch));
+{ Number of bits used within bi_buf. (bi_buf might be implemented on
+  more than 16 bits on some systems.) }
+
+{ ===========================================================================
+  Local data. These are initialized only once. }
+
+
+{$ifdef GEN_TREES_H)}
+{ non ANSI compilers may not accept trees.h }
+
+const
+  DIST_CODE_LEN = 512; { see definition of array dist_code below }
+
+{local}
+var
+  static_ltree : array[0..L_CODES+2-1] of ct_data;
+{ The static literal tree. Since the bit lengths are imposed, there is no
+  need for the L_CODES extra codes used during heap construction. However
+  The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+  below). }
+
+{local}
+  static_dtree : array[0..D_CODES-1] of ct_data;
+{ The static distance tree. (Actually a trivial tree since all codes use
+  5 bits.) }
+
+  _dist_code : array[0..DIST_CODE_LEN-1] of uch;
+{ Distance codes. The first 256 values correspond to the distances
+  3 .. 258, the last 256 values correspond to the top 8 bits of
+  the 15 bit distances. }
+
+  _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of uch;
+{ length code for each normalized match length (0 == MIN_MATCH) }
+
+{local}
+  base_length : array[0..LENGTH_CODES-1] of int;
+{ First normalized length for each code (0 = MIN_MATCH) }
+
+{local}
+  base_dist : array[0..D_CODES-1] of int;
+{ First normalized distance for each code (0 = distance of 1) }
+
+{$endif} { GEN_TREES_H }
+
+{local}
+const
+  static_l_desc :  static_tree_desc  =
+      (static_tree: {tree_ptr}(@(static_ltree));  { pointer to array of ct_data }
+       extra_bits: {pzIntfArray}(@(extra_lbits)); { pointer to array of int }
+       extra_base: LITERALS+1;
+       elems: L_CODES;
+       max_length: MAX_BITS);
+
+{local}
+const
+  static_d_desc : static_tree_desc  =
+      (static_tree: {tree_ptr}(@(static_dtree));
+       extra_bits: {pzIntfArray}(@(extra_dbits));
+       extra_base : 0;
+       elems: D_CODES;
+       max_length: MAX_BITS);
+
+{local}
+const
+  static_bl_desc : static_tree_desc =
+      (static_tree: {tree_ptr}(NIL);
+       extra_bits: {pzIntfArray}@(extra_blbits);
+       extra_base : 0;
+       elems: BL_CODES;
+       max_length: MAX_BL_BITS);
+
+(* ===========================================================================
+  Local (static) routines in this file. }
+
+procedure tr_static_init;
+procedure init_block(var deflate_state);
+procedure pqdownheap(var s : deflate_state;
+                     var tree : ct_data;
+                     k : int);
+procedure gen_bitlen(var s : deflate_state;
+                     var desc : tree_desc);
+procedure gen_codes(var tree : ct_data;
+                    max_code : int;
+                    bl_count : pushf);
+procedure build_tree(var s : deflate_state;
+                     var desc : tree_desc);
+procedure scan_tree(var s : deflate_state;
+                    var tree : ct_data;
+                    max_code : int);
+procedure send_tree(var s : deflate_state;
+                    var tree : ct_data;
+                    max_code : int);
+function build_bl_tree(var deflate_state) : int;
+procedure send_all_trees(var deflate_state;
+                         lcodes : int;
+                         dcodes : int;
+                         blcodes : int);
+procedure compress_block(var s : deflate_state;
+                         var ltree : ct_data;
+                         var dtree : ct_data);
+procedure set_data_type(var s : deflate_state);
+function bi_reverse(value : unsigned;
+                    length : int) : unsigned;
+procedure bi_windup(var deflate_state);
+procedure bi_flush(var deflate_state);
+procedure copy_block(var deflate_state;
+                     buf : pcharf;
+                     len : unsigned;
+                     header : int);
+*)
+
+{$ifdef GEN_TREES_H}
+{local}
+procedure gen_trees_header;
+{$endif}
+
+(*
+{ ===========================================================================
+  Output a short LSB first on the stream.
+  IN assertion: there is enough room in pendingBuf. }
+
+macro put_short(s, w)
+begin
+    {put_byte(s, (uch)((w) & 0xff));}
+    s.pending_buf^[s.pending] := uch((w) and $ff);
+    Inc(s.pending);
+
+    {put_byte(s, (uch)((ush)(w) >> 8));}
+    s.pending_buf^[s.pending] := uch(ush(w) shr 8);;
+    Inc(s.pending);
+end
+*)
+
+{ ===========================================================================
+  Send a value on a given number of bits.
+  IN assertion: length <= 16 and value fits in length bits. }
+
+{$ifdef ORG_DEBUG}
+
+{local}
+procedure send_bits(var s : deflate_state;
+                    value : int;   { value to send }
+                    length : int); { number of bits }
+begin
+  {$ifdef DEBUG}
+  Tracevv(' l '+IntToStr(length)+ ' v '+IntToStr(value));
+  Assert((length > 0) and (length <= 15), 'invalid length');
+  Inc(s.bits_sent, ulg(length));
+  {$ENDIF}
+
+  { If not enough room in bi_buf, use (valid) bits from bi_buf and
+    (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+    unused bits in value. }
+  {$IFOPT Q+} {$Q-} {$DEFINE NoOverflowCheck} {$ENDIF}
+  {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+  if (s.bi_valid > int(Buf_size) - length) then
+  begin
+    s.bi_buf := s.bi_buf or int(value shl s.bi_valid);
+    {put_short(s, s.bi_buf);}
+    s.pending_buf^[s.pending] := uch(s.bi_buf and $ff);
+    Inc(s.pending);
+    s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);;
+    Inc(s.pending);
+
+    s.bi_buf := ush(value) shr (Buf_size - s.bi_valid);
+    Inc(s.bi_valid, length - Buf_size);
+  end
+  else
+  begin
+    s.bi_buf := s.bi_buf or int(value shl s.bi_valid);
+    Inc(s.bi_valid, length);
+  end;
+  {$IFDEF NoOverflowCheck} {$Q+} {$UNDEF NoOverflowCheck} {$ENDIF}
+  {$IFDEF NoRangeCheck} {$Q+} {$UNDEF NoRangeCheck} {$ENDIF}
+end;
+
+{$else} { !DEBUG }
+
+
+macro send_code(s, c, tree)
+begin
+  send_bits(s, tree[c].Code, tree[c].Len);
+  { Send a code of the given tree. c and tree must not have side effects }
+end
+
+macro send_bits(s, value, length) \
+begin int len := length;\
+  if (s^.bi_valid > (int)Buf_size - len) begin\
+    int val := value;\
+    s^.bi_buf |= (val << s^.bi_valid);\
+    {put_short(s, s.bi_buf);}
+    s.pending_buf^[s.pending] := uch(s.bi_buf and $ff);
+    Inc(s.pending);
+    s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);;
+    Inc(s.pending);
+
+    s^.bi_buf := (ush)val >> (Buf_size - s^.bi_valid);\
+    s^.bi_valid += len - Buf_size;\
+  end else begin\
+    s^.bi_buf |= (value) << s^.bi_valid;\
+    s^.bi_valid += len;\
+  end\
+end;
+{$endif} { DEBUG }
+
+{ ===========================================================================
+  Reverse the first len bits of a code, using straightforward code (a faster
+  method would use a table)
+  IN assertion: 1 <= len <= 15 }
+
+{local}
+function bi_reverse(code : unsigned;         { the value to invert }
+                    len : int) : unsigned;   { its bit length }
+
+var
+  res : unsigned; {register}
+begin
+  res := 0;
+  repeat
+    res := res or (code and 1);
+    code := code shr 1;
+    res := res shl 1;
+    Dec(len);
+  until (len <= 0);
+  bi_reverse := res shr 1;
+end;
+
+{ ===========================================================================
+  Generate the codes for a given tree and bit counts (which need not be
+  optimal).
+  IN assertion: the array bl_count contains the bit length statistics for
+  the given tree and the field len is set for all tree elements.
+  OUT assertion: the field code is set for all tree elements of non
+      zero code length. }
+
+{local}
+procedure gen_codes(tree : tree_ptr;  { the tree to decorate }
+                    max_code : int;   { largest code with non zero frequency }
+                    var bl_count : array of ushf);  { number of codes at each bit length }
+
+var
+  next_code : array[0..MAX_BITS+1-1] of ush; { next code value for each bit length }
+  code : ush;              { running code value }
+  bits : int;                  { bit index }
+  n : int;                     { code index }
+var
+  len : int;
+begin
+  code := 0;
+
+  { The distribution counts are first used to generate the code values
+    without bit reversal. }
+
+  for bits := 1 to MAX_BITS do
+  begin
+    code := ((code + bl_count[bits-1]) shl 1);
+    next_code[bits] := code;
+  end;
+  { Check that the bit counts in bl_count are consistent. The last code
+    must be all ones. }
+
+  {$IFDEF DEBUG}
+  Assert (code + bl_count[MAX_BITS]-1 = (1 shl MAX_BITS)-1,
+          'inconsistent bit counts');
+  Tracev(#13'gen_codes: max_code '+IntToStr(max_code));
+  {$ENDIF}
+
+  for n := 0 to max_code do
+  begin
+    len := tree^[n].dl.Len;
+    if (len = 0) then
+      continue;
+    { Now reverse the bits }
+    tree^[n].fc.Code := bi_reverse(next_code[len], len);
+    Inc(next_code[len]);
+    {$ifdef DEBUG}
+    if (n>31) and (n<128) then
+      Tracecv(tree <> tree_ptr(@static_ltree),
+       (^M'n #'+IntToStr(n)+' '+AnsiChar(n)+' l '+IntToStr(len)+' c '+
+         IntToStr(tree^[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')'))
+    else
+      Tracecv(tree <> tree_ptr(@static_ltree),
+      (^M'n #'+IntToStr(n)+'   l '+IntToStr(len)+' c '+
+         IntToStr(tree^[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')'));
+    {$ENDIF}
+  end;
+end;
+
+{ ===========================================================================
+  Genererate the file trees.h describing the static trees. }
+{$ifdef GEN_TREES_H}
+
+macro SEPARATOR(i, last, width)
+  if (i) = (last) then
+    ( ^M');'^M^M
+  else    \
+    if (i) mod (width) = (width)-1 then
+       ','^M
+     else
+       ', '
+
+procedure gen_trees_header;
+var
+  header : system.text;
+  i : int;
+begin
+  system.assign(header, 'trees.inc');
+  {$I-}
+  ReWrite(header);
+  {$I+}
+  Assert (IOresult <> 0, 'Can''t open trees.h');
+  WriteLn(header,
+    '{ header created automatically with -DGEN_TREES_H }'^M);
+
+  WriteLn(header, 'local const ct_data static_ltree[L_CODES+2] := (');
+  for i := 0 to L_CODES+2-1 do
+  begin
+    WriteLn(header, '((%3u),(%3u))%s', static_ltree[i].Code,
+    static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+  end;
+
+  WriteLn(header, 'local const ct_data static_dtree[D_CODES] := (');
+  for i := 0 to D_CODES-1 do
+  begin
+    WriteLn(header, '((%2u),(%2u))%s', static_dtree[i].Code,
+    static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+  end;
+
+  WriteLn(header, 'const uch _dist_code[DIST_CODE_LEN] := (');
+  for i := 0 to DIST_CODE_LEN-1 do
+  begin
+    WriteLn(header, '%2u%s', _dist_code[i],
+    SEPARATOR(i, DIST_CODE_LEN-1, 20));
+  end;
+
+  WriteLn(header, 'const uch _length_code[MAX_MATCH-MIN_MATCH+1]= (');
+  for i := 0 to MAX_MATCH-MIN_MATCH+1-1 do
+  begin
+    WriteLn(header, '%2u%s', _length_code[i],
+    SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+  end;
+
+  WriteLn(header, 'local const int base_length[LENGTH_CODES] := (');
+  for i := 0 to LENGTH_CODES-1 do
+  begin
+    WriteLn(header, '%1u%s', base_length[i],
+    SEPARATOR(i, LENGTH_CODES-1, 20));
+  end;
+
+  WriteLn(header, 'local const int base_dist[D_CODES] := (');
+  for i := 0 to D_CODES-1 do
+  begin
+    WriteLn(header, '%5u%s', base_dist[i],
+    SEPARATOR(i, D_CODES-1, 10));
+  end;
+
+  close(header);
+end;
+{$endif} { GEN_TREES_H }
+
+
+{ ===========================================================================
+  Initialize the various 'constant' tables. }
+
+{local}
+procedure tr_static_init;
+
+{$ifdef GEN_TREES_H}
+const
+  static_init_done : boolean = FALSE;
+var
+  n : int;        { iterates over tree elements }
+  bits : int;     { bit counter }
+  length : int;   { length value }
+  code : int;     { code value }
+  dist : int;     { distance index }
+  bl_count : array[0..MAX_BITS+1-1] of ush;
+    { number of codes at each bit length for an optimal tree }
+begin
+    if (static_init_done) then
+      exit;
+
+    { Initialize the mapping length (0..255) -> length code (0..28) }
+    length := 0;
+    for code := 0 to LENGTH_CODES-1-1 do
+    begin
+      base_length[code] := length;
+      for n := 0 to (1 shl extra_lbits[code])-1 do
+      begin
+        _length_code[length] := uch(code);
+        Inc(length);
+      end;
+    end;
+    Assert (length = 256, 'tr_static_init: length <> 256');
+    { Note that the length 255 (match length 258) can be represented
+      in two different ways: code 284 + 5 bits or code 285, so we
+      overwrite length_code[255] to use the best encoding: }
+
+    _length_code[length-1] := uch(code);
+
+    { Initialize the mapping dist (0..32K) -> dist code (0..29) }
+    dist := 0;
+    for code := 0 to 16-1 do
+    begin
+      base_dist[code] := dist;
+      for n := 0 to (1 shl extra_dbits[code])-1 do
+      begin
+        _dist_code[dist] := uch(code);
+        Inc(dist);
+      end;
+    end;
+    Assert (dist = 256, 'tr_static_init: dist <> 256');
+    dist := dist shr 7; { from now on, all distances are divided by 128 }
+    for code := 16 to D_CODES-1 do
+    begin
+      base_dist[code] := dist shl 7;
+      for n := 0 to (1 shl (extra_dbits[code]-7))-1 do
+      begin
+        _dist_code[256 + dist] := uch(code);
+        Inc(dist);
+      end;
+    end;
+    Assert (dist = 256, 'tr_static_init: 256+dist <> 512');
+
+    { Construct the codes of the static literal tree }
+    for bits := 0 to MAX_BITS do
+      bl_count[bits] := 0;
+    n := 0;
+    while (n <= 143) do
+    begin
+      static_ltree[n].dl.Len := 8;
+      Inc(n);
+      Inc(bl_count[8]);
+    end;
+    while (n <= 255) do
+    begin
+      static_ltree[n].dl.Len := 9;
+      Inc(n);
+      Inc(bl_count[9]);
+    end;
+    while (n <= 279) do
+    begin
+      static_ltree[n].dl.Len := 7;
+      Inc(n);
+      Inc(bl_count[7]);
+    end;
+    while (n <= 287) do
+    begin
+      static_ltree[n].dl.Len := 8;
+      Inc(n);
+      Inc(bl_count[8]);
+    end;
+
+    { Codes 286 and 287 do not exist, but we must include them in the
+      tree construction to get a canonical Huffman tree (longest code
+      all ones)  }
+
+    gen_codes(tree_ptr(@static_ltree), L_CODES+1, bl_count);
+
+    { The static distance tree is trivial: }
+    for n := 0 to D_CODES-1 do
+    begin
+      static_dtree[n].dl.Len := 5;
+      static_dtree[n].fc.Code := bi_reverse(unsigned(n), 5);
+    end;
+    static_init_done := TRUE;
+
+    gen_trees_header;  { save to include file }
+{$else}
+begin
+{$endif} { GEN_TREES_H) }
+end;
+
+{ ===========================================================================
+  Initialize a new block. }
+{local}
+
+procedure init_block(var s : deflate_state);
+var
+  n : int; { iterates over tree elements }
+begin
+  { Initialize the trees. }
+  for n := 0 to L_CODES-1 do
+    s.dyn_ltree[n].fc.Freq := 0;
+  for n := 0 to D_CODES-1 do
+    s.dyn_dtree[n].fc.Freq := 0;
+  for n := 0 to BL_CODES-1 do
+    s.bl_tree[n].fc.Freq := 0;
+
+  s.dyn_ltree[END_BLOCK].fc.Freq := 1;
+  s.static_len := Long(0);
+  s.opt_len := Long(0);
+  s.matches := 0;
+  s.last_lit := 0;
+end;
+
+const
+  SMALLEST = 1;
+{ Index within the heap array of least frequent node in the Huffman tree }
+
+{ ===========================================================================
+  Initialize the tree data structures for a new zlib stream. }
+procedure _tr_init(var s : deflate_state);
+begin
+  tr_static_init;
+
+  s.compressed_len := Long(0);
+
+  s.l_desc.dyn_tree := tree_ptr(@s.dyn_ltree);
+  s.l_desc.stat_desc := @static_l_desc;
+
+  s.d_desc.dyn_tree := tree_ptr(@s.dyn_dtree);
+  s.d_desc.stat_desc := @static_d_desc;
+
+  s.bl_desc.dyn_tree := tree_ptr(@s.bl_tree);
+  s.bl_desc.stat_desc := @static_bl_desc;
+
+  s.bi_buf := 0;
+  s.bi_valid := 0;
+  s.last_eob_len := 8; { enough lookahead for inflate }
+{$ifdef DEBUG}
+  s.bits_sent := Long(0);
+{$endif}
+
+  { Initialize the first block of the first file: }
+  init_block(s);
+end;
+
+{ ===========================================================================
+  Remove the smallest element from the heap and recreate the heap with
+  one less element. Updates heap and heap_len.
+
+macro pqremove(s, tree, top)
+begin
+    top := s.heap[SMALLEST];
+    s.heap[SMALLEST] := s.heap[s.heap_len];
+    Dec(s.heap_len);
+    pqdownheap(s, tree, SMALLEST);
+end
+}
+
+{ ===========================================================================
+  Compares to subtrees, using the tree depth as tie breaker when
+  the subtrees have equal frequency. This minimizes the worst case length.
+
+macro smaller(tree, n, m, depth)
+   ( (tree[n].Freq < tree[m].Freq) or
+     ((tree[n].Freq = tree[m].Freq) and (depth[n] <= depth[m])) )
+}
+
+{ ===========================================================================
+  Restore the heap property by moving down the tree starting at node k,
+  exchanging a node with the smallest of its two sons if necessary, stopping
+  when the heap property is re-established (each father smaller than its
+  two sons). }
+{local}
+
+procedure pqdownheap(var s : deflate_state;
+                     var tree : tree_type;   { the tree to restore }
+                     k : int);          { node to move down }
+var
+  v : int;
+  j : int;
+begin
+  v := s.heap[k];
+  j := k shl 1;  { left son of k }
+  while (j <= s.heap_len) do
+  begin
+    { Set j to the smallest of the two sons: }
+    if (j < s.heap_len) and
+       {smaller(tree, s.heap[j+1], s.heap[j], s.depth)}
+      ( (tree[s.heap[j+1]].fc.Freq < tree[s.heap[j]].fc.Freq) or
+        ((tree[s.heap[j+1]].fc.Freq = tree[s.heap[j]].fc.Freq) and
+         (s.depth[s.heap[j+1]] <= s.depth[s.heap[j]])) ) then
+    begin
+      Inc(j);
+    end;
+    { Exit if v is smaller than both sons }
+    if {(smaller(tree, v, s.heap[j], s.depth))}
+     ( (tree[v].fc.Freq < tree[s.heap[j]].fc.Freq) or
+       ((tree[v].fc.Freq = tree[s.heap[j]].fc.Freq) and
+        (s.depth[v] <= s.depth[s.heap[j]])) ) then
+      break;
+    { Exchange v with the smallest son }
+    s.heap[k] := s.heap[j];
+    k := j;
+
+    { And continue down the tree, setting j to the left son of k }
+    j := j shl 1;
+  end;
+  s.heap[k] := v;
+end;
+
+{ ===========================================================================
+  Compute the optimal bit lengths for a tree and update the total bit length
+  for the current block.
+  IN assertion: the fields freq and dad are set, heap[heap_max] and
+     above are the tree nodes sorted by increasing frequency.
+  OUT assertions: the field len is set to the optimal bit length, the
+      array bl_count contains the frequencies for each bit length.
+      The length opt_len is updated; static_len is also updated if stree is
+      not null. }
+
+{local}
+procedure gen_bitlen(var s : deflate_state;
+                     var desc : tree_desc);   { the tree descriptor }
+var
+  tree : tree_ptr;
+  max_code : int;
+  stree : tree_ptr; {const}
+  extra : pzIntfArray; {const}
+  base : int;
+  max_length : int;
+  h : int;              { heap index }
+  n, m : int;           { iterate over the tree elements }
+  bits : int;           { bit length }
+  xbits : int;          { extra bits }
+  f : ush;              { frequency }
+  overflow : int;   { number of elements with bit length too large }
+begin
+  tree := desc.dyn_tree;
+  max_code := desc.max_code;
+  stree := desc.stat_desc^.static_tree;
+  extra := desc.stat_desc^.extra_bits;
+  base := desc.stat_desc^.extra_base;
+  max_length := desc.stat_desc^.max_length;
+  overflow := 0;
+
+  for bits := 0 to MAX_BITS do
+    s.bl_count[bits] := 0;
+
+  { In a first pass, compute the optimal bit lengths (which may
+    overflow in the case of the bit length tree). }
+
+  tree^[s.heap[s.heap_max]].dl.Len := 0; { root of the heap }
+
+  for h := s.heap_max+1 to HEAP_SIZE-1 do
+  begin
+    n := s.heap[h];
+    bits := tree^[tree^[n].dl.Dad].dl.Len + 1;
+    if (bits > max_length) then
+    begin
+      bits := max_length;
+      Inc(overflow);
+    end;
+    tree^[n].dl.Len := ush(bits);
+    { We overwrite tree[n].dl.Dad which is no longer needed }
+
+    if (n > max_code) then
+      continue; { not a leaf node }
+
+    Inc(s.bl_count[bits]);
+    xbits := 0;
+    if (n >= base) then
+      xbits := extra^[n-base];
+    f := tree^[n].fc.Freq;
+    Inc(s.opt_len, ulg(f) * (bits + xbits));
+    if (stree <> NIL) then
+      Inc(s.static_len, ulg(f) * (stree^[n].dl.Len + xbits));
+  end;
+  if (overflow = 0) then
+    exit;
+  {$ifdef DEBUG}
+  Tracev(^M'bit length overflow');
+  {$endif}
+  { This happens for example on obj2 and pic of the Calgary corpus }
+
+  { Find the first bit length which could increase: }
+  repeat
+    bits := max_length-1;
+    while (s.bl_count[bits] = 0) do
+      Dec(bits);
+    Dec(s.bl_count[bits]);      { move one leaf down the tree }
+    Inc(s.bl_count[bits+1], 2); { move one overflow item as its brother }
+    Dec(s.bl_count[max_length]);
+    { The brother of the overflow item also moves one step up,
+      but this does not affect bl_count[max_length] }
+
+    Dec(overflow, 2);
+  until (overflow <= 0);
+
+  { Now recompute all bit lengths, scanning in increasing frequency.
+    h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+    lengths instead of fixing only the wrong ones. This idea is taken
+    from 'ar' written by Haruhiko Okumura.) }
+  h := HEAP_SIZE;  { Delphi3: compiler warning w/o this }
+  for bits := max_length downto 1 do
+  begin
+    n := s.bl_count[bits];
+    while (n <> 0) do
+    begin
+      Dec(h);
+      m := s.heap[h];
+      if (m > max_code) then
+        continue;
+      if (tree^[m].dl.Len <> unsigned(bits)) then
+      begin
+        {$ifdef DEBUG}
+        Trace('code '+IntToStr(m)+' bits '+IntToStr(tree^[m].dl.Len)
+              +'.'+IntToStr(bits));
+        {$ENDIF}
+        Inc(s.opt_len, (long(bits) - long(tree^[m].dl.Len))
+                        * long(tree^[m].fc.Freq) );
+        tree^[m].dl.Len := ush(bits);
+      end;
+      Dec(n);
+    end;
+  end;
+end;
+
+{ ===========================================================================
+  Construct one Huffman tree and assigns the code bit strings and lengths.
+  Update the total bit length for the current block.
+  IN assertion: the field freq is set for all tree elements.
+  OUT assertions: the fields len and code are set to the optimal bit length
+      and corresponding code. The length opt_len is updated; static_len is
+      also updated if stree is not null. The field max_code is set. }
+
+{local}
+procedure build_tree(var s : deflate_state;
+                     var desc : tree_desc); { the tree descriptor }
+
+var
+  tree : tree_ptr;
+  stree : tree_ptr; {const}
+  elems : int;
+  n, m : int;          { iterate over heap elements }
+  max_code : int;      { largest code with non zero frequency }
+  node : int;          { new node being created }
+begin
+  tree := desc.dyn_tree;
+  stree := desc.stat_desc^.static_tree;
+  elems := desc.stat_desc^.elems;
+  max_code := -1;
+
+  { Construct the initial heap, with least frequent element in
+    heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+    heap[0] is not used. }
+  s.heap_len := 0;
+  s.heap_max := HEAP_SIZE;
+
+  for n := 0 to elems-1 do
+  begin
+    if (tree^[n].fc.Freq <> 0) then
+    begin
+      max_code := n;
+      Inc(s.heap_len);
+      s.heap[s.heap_len] := n;
+      s.depth[n] := 0;
+    end
+    else
+    begin
+      tree^[n].dl.Len := 0;
+    end;
+  end;
+
+  { The pkzip format requires that at least one distance code exists,
+    and that at least one bit should be sent even if there is only one
+    possible code. So to avoid special checks later on we force at least
+    two codes of non zero frequency. }
+
+  while (s.heap_len < 2) do
+  begin
+    Inc(s.heap_len);
+    if (max_code < 2) then
+    begin
+      Inc(max_code);
+      s.heap[s.heap_len] := max_code;
+      node := max_code;
+    end
+    else
+    begin
+      s.heap[s.heap_len] := 0;
+      node := 0;
+    end;
+    tree^[node].fc.Freq := 1;
+    s.depth[node] := 0;
+    Dec(s.opt_len);
+    if (stree <> NIL) then
+      Dec(s.static_len, stree^[node].dl.Len);
+    { node is 0 or 1 so it does not have extra bits }
+  end;
+  desc.max_code := max_code;
+
+  { The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+    establish sub-heaps of increasing lengths: }
+
+  for n := s.heap_len div 2 downto 1 do
+    pqdownheap(s, tree^, n);
+
+  { Construct the Huffman tree by repeatedly combining the least two
+    frequent nodes. }
+
+  node := elems;              { next internal node of the tree }
+  repeat
+    {pqremove(s, tree, n);}  { n := node of least frequency }
+    n := s.heap[SMALLEST];
+    s.heap[SMALLEST] := s.heap[s.heap_len];
+    Dec(s.heap_len);
+    pqdownheap(s, tree^, SMALLEST);
+
+    m := s.heap[SMALLEST]; { m := node of next least frequency }
+
+    Dec(s.heap_max);
+    s.heap[s.heap_max] := n; { keep the nodes sorted by frequency }
+    Dec(s.heap_max);
+    s.heap[s.heap_max] := m;
+
+    { Create a new node father of n and m }
+    tree^[node].fc.Freq := tree^[n].fc.Freq + tree^[m].fc.Freq;
+    { maximum }
+    if (s.depth[n] >= s.depth[m]) then
+      s.depth[node] := uch (s.depth[n] + 1)
+    else
+      s.depth[node] := uch (s.depth[m] + 1);
+
+    tree^[m].dl.Dad := ush(node);
+    tree^[n].dl.Dad := ush(node);
+{$ifdef DUMP_BL_TREE}
+    if (tree = tree_ptr(@s.bl_tree)) then
+    begin
+      WriteLn(#13'node ',node,'(',tree^[node].fc.Freq,') sons ',n,
+              '(',tree^[n].fc.Freq,') ', m, '(',tree^[m].fc.Freq,')');
+    end;
+{$endif}
+    { and insert the new node in the heap }
+    s.heap[SMALLEST] := node;
+    Inc(node);
+    pqdownheap(s, tree^, SMALLEST);
+
+  until (s.heap_len < 2);
+
+  Dec(s.heap_max);
+  s.heap[s.heap_max] := s.heap[SMALLEST];
+
+  { At this point, the fields freq and dad are set. We can now
+    generate the bit lengths. }
+
+  gen_bitlen(s, desc);
+
+  { The field len is now set, we can generate the bit codes }
+  gen_codes (tree, max_code, s.bl_count);
+end;
+
+{ ===========================================================================
+  Scan a literal or distance tree to determine the frequencies of the codes
+  in the bit length tree. }
+
+{local}
+procedure scan_tree(var s : deflate_state;
+                    var tree : array of ct_data;    { the tree to be scanned }
+                    max_code : int);    { and its largest code of non zero frequency }
+var
+  n : int;                 { iterates over all tree elements }
+  prevlen : int;           { last emitted length }
+  curlen : int;            { length of current code }
+  nextlen : int;           { length of next code }
+  count : int;             { repeat count of the current code }
+  max_count : int;         { max repeat count }
+  min_count : int;         { min repeat count }
+begin
+  prevlen := -1;
+  nextlen := tree[0].dl.Len;
+  count := 0;
+  max_count := 7;
+  min_count := 4;
+
+  if (nextlen = 0) then
+  begin
+    max_count := 138;
+    min_count := 3;
+  end;
+  tree[max_code+1].dl.Len := ush($ffff); { guard }
+
+  for n := 0 to max_code do
+  begin
+    curlen := nextlen;
+    nextlen := tree[n+1].dl.Len;
+    Inc(count);
+    if (count < max_count) and (curlen = nextlen) then
+      continue
+    else
+      if (count < min_count) then
+        Inc(s.bl_tree[curlen].fc.Freq, count)
+      else
+        if (curlen <> 0) then
+        begin
+          if (curlen <> prevlen) then
+            Inc(s.bl_tree[curlen].fc.Freq);
+          Inc(s.bl_tree[REP_3_6].fc.Freq);
+        end
+        else
+          if (count <= 10) then
+            Inc(s.bl_tree[REPZ_3_10].fc.Freq)
+          else
+            Inc(s.bl_tree[REPZ_11_138].fc.Freq);
+
+    count := 0;
+    prevlen := curlen;
+    if (nextlen = 0) then
+    begin
+      max_count := 138;
+      min_count := 3;
+    end
+    else
+      if (curlen = nextlen) then
+      begin
+        max_count := 6;
+        min_count := 3;
+      end
+      else
+      begin
+        max_count := 7;
+        min_count := 4;
+      end;
+  end;
+end;
+
+{ ===========================================================================
+  Send a literal or distance tree in compressed form, using the codes in
+  bl_tree. }
+
+{local}
+procedure send_tree(var s : deflate_state;
+                    var tree : array of ct_data;    { the tree to be scanned }
+                    max_code : int);    { and its largest code of non zero frequency }
+
+var
+  n : int;                { iterates over all tree elements }
+  prevlen : int;          { last emitted length }
+  curlen : int;           { length of current code }
+  nextlen : int;          { length of next code }
+  count : int;            { repeat count of the current code }
+  max_count : int;        { max repeat count }
+  min_count : int;        { min repeat count }
+begin
+  prevlen := -1;
+  nextlen := tree[0].dl.Len;
+  count := 0;
+  max_count := 7;
+  min_count := 4;
+
+  { tree[max_code+1].dl.Len := -1; }  { guard already set }
+  if (nextlen = 0) then
+  begin
+    max_count := 138;
+    min_count := 3;
+  end;
+
+  for n := 0 to max_code do
+  begin
+    curlen := nextlen;
+    nextlen := tree[n+1].dl.Len;
+    Inc(count);
+    if (count < max_count) and (curlen = nextlen) then
+      continue
+    else
+      if (count < min_count) then
+      begin
+        repeat
+          {$ifdef DEBUG}
+          Tracevvv(#13'cd '+IntToStr(curlen));
+          {$ENDIF}
+          send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len);
+          Dec(count);
+        until (count = 0);
+      end
+      else
+        if (curlen <> 0) then
+        begin
+          if (curlen <> prevlen) then
+          begin
+            {$ifdef DEBUG}
+            Tracevvv(#13'cd '+IntToStr(curlen));
+            {$ENDIF}
+            send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len);
+            Dec(count);
+          end;
+          {$IFDEF DEBUG}
+          Assert((count >= 3) and (count <= 6), ' 3_6?');
+          {$ENDIF}
+          {$ifdef DEBUG}
+          Tracevvv(#13'cd '+IntToStr(REP_3_6));
+          {$ENDIF}
+          send_bits(s, s.bl_tree[REP_3_6].fc.Code, s.bl_tree[REP_3_6].dl.Len);
+          send_bits(s, count-3, 2);
+        end
+        else
+          if (count <= 10) then
+          begin
+            {$ifdef DEBUG}
+            Tracevvv(#13'cd '+IntToStr(REPZ_3_10));
+            {$ENDIF}
+            send_bits(s, s.bl_tree[REPZ_3_10].fc.Code, s.bl_tree[REPZ_3_10].dl.Len);
+            send_bits(s, count-3, 3);
+          end
+          else
+          begin
+            {$ifdef DEBUG}
+            Tracevvv(#13'cd '+IntToStr(REPZ_11_138));
+            {$ENDIF}
+            send_bits(s, s.bl_tree[REPZ_11_138].fc.Code, s.bl_tree[REPZ_11_138].dl.Len);
+            send_bits(s, count-11, 7);
+          end;
+    count := 0;
+    prevlen := curlen;
+    if (nextlen = 0) then
+    begin
+      max_count := 138;
+      min_count := 3;
+    end
+    else
+      if (curlen = nextlen) then
+      begin
+        max_count := 6;
+        min_count := 3;
+      end
+      else
+      begin
+        max_count := 7;
+        min_count := 4;
+      end;
+  end;
+end;
+
+{ ===========================================================================
+  Construct the Huffman tree for the bit lengths and return the index in
+  bl_order of the last bit length code to send. }
+
+{local}
+function build_bl_tree(var s : deflate_state) : int;
+var
+  max_blindex : int;  { index of last bit length code of non zero freq }
+begin
+  { Determine the bit length frequencies for literal and distance trees }
+  scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
+  scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
+
+  { Build the bit length tree: }
+  build_tree(s, s.bl_desc);
+  { opt_len now includes the length of the tree representations, except
+    the lengths of the bit lengths codes and the 5+5+4 bits for the counts. }
+
+  { Determine the number of bit length codes to send. The pkzip format
+    requires that at least 4 bit length codes be sent. (appnote.txt says
+    3 but the actual value used is 4.) }
+
+  for max_blindex := BL_CODES-1 downto 3 do
+  begin
+    if (s.bl_tree[bl_order[max_blindex]].dl.Len <> 0) then
+      break;
+  end;
+  { Update opt_len to include the bit length tree and counts }
+  Inc(s.opt_len, 3*(max_blindex+1) + 5+5+4);
+  {$ifdef DEBUG}
+  Tracev(^M'dyn trees: dyn %ld, stat %ld {s.opt_len, s.static_len}');
+  {$ENDIF}
+
+  build_bl_tree := max_blindex;
+end;
+
+{ ===========================================================================
+  Send the header for a block using dynamic Huffman trees: the counts, the
+  lengths of the bit length codes, the literal tree and the distance tree.
+  IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. }
+
+{local}
+procedure send_all_trees(var s : deflate_state;
+                         lcodes : int;
+                         dcodes : int;
+                         blcodes : int); { number of codes for each tree }
+var
+  rank : int;                    { index in bl_order }
+begin
+  {$IFDEF DEBUG}
+  Assert ((lcodes >= 257) and (dcodes >= 1) and (blcodes >= 4),
+          'not enough codes');
+  Assert ((lcodes <= L_CODES) and (dcodes <= D_CODES)
+          and (blcodes <= BL_CODES), 'too many codes');
+  Tracev(^M'bl counts: ');
+  {$ENDIF}
+  send_bits(s, lcodes-257, 5); { not +255 as stated in appnote.txt }
+  send_bits(s, dcodes-1,   5);
+  send_bits(s, blcodes-4,  4); { not -3 as stated in appnote.txt }
+  for rank := 0 to blcodes-1 do
+  begin
+    {$ifdef DEBUG}
+    Tracev(^M'bl code '+IntToStr(bl_order[rank]));
+    {$ENDIF}
+    send_bits(s, s.bl_tree[bl_order[rank]].dl.Len, 3);
+  end;
+  {$ifdef DEBUG}
+  Tracev(^M'bl tree: sent '+IntToStr(s.bits_sent));
+  {$ENDIF}
+
+  send_tree(s, s.dyn_ltree, lcodes-1); { literal tree }
+  {$ifdef DEBUG}
+  Tracev(^M'lit tree: sent '+IntToStr(s.bits_sent));
+  {$ENDIF}
+
+  send_tree(s, s.dyn_dtree, dcodes-1); { distance tree }
+  {$ifdef DEBUG}
+  Tracev(^M'dist tree: sent '+IntToStr(s.bits_sent));
+  {$ENDIF}
+end;
+
+{ ===========================================================================
+  Flush the bit buffer and align the output on a byte boundary }
+
+{local}
+procedure bi_windup(var s : deflate_state);
+begin
+  if (s.bi_valid > 8) then
+  begin
+    {put_short(s, s.bi_buf);}
+    s.pending_buf^[s.pending] := uch(s.bi_buf and $ff);
+    Inc(s.pending);
+    s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);;
+    Inc(s.pending);
+  end
+  else
+    if (s.bi_valid > 0) then
+    begin
+      {put_byte(s, (Byte)s^.bi_buf);}
+      s.pending_buf^[s.pending] := Byte(s.bi_buf);
+      Inc(s.pending);
+    end;
+  s.bi_buf := 0;
+  s.bi_valid := 0;
+{$ifdef DEBUG}
+  s.bits_sent := (s.bits_sent+7) and (not 7);
+{$endif}
+end;
+
+{ ===========================================================================
+  Copy a stored block, storing first the length and its
+  one's complement if requested. }
+
+{local}
+procedure copy_block(var s : deflate_state;
+                     buf : pcharf;      { the input data }
+                     len : unsigned;    { its length }
+                     header : boolean); { true if block header must be written }
+begin
+  bi_windup(s);        { align on byte boundary }
+  s.last_eob_len := 8; { enough lookahead for inflate }
+
+  if (header) then
+  begin
+    {put_short(s, (ush)len);}
+    s.pending_buf^[s.pending] := uch(ush(len) and $ff);
+    Inc(s.pending);
+    s.pending_buf^[s.pending] := uch(ush(len) shr 8);;
+    Inc(s.pending);
+    {put_short(s, (ush)~len);}
+    s.pending_buf^[s.pending] := uch(ush(not len) and $ff);
+    Inc(s.pending);
+    s.pending_buf^[s.pending] := uch(ush(not len) shr 8);;
+    Inc(s.pending);
+
+{$ifdef DEBUG}
+    Inc(s.bits_sent, 2*16);
+{$endif}
+  end;
+{$ifdef DEBUG}
+  Inc(s.bits_sent, ulg(len shl 3));
+{$endif}
+  while (len <> 0) do
+  begin
+    Dec(len);
+    {put_byte(s, *buf++);}
+    s.pending_buf^[s.pending] := buf^;
+    Inc(buf);
+    Inc(s.pending);
+  end;
+end;
+
+
+{ ===========================================================================
+  Send a stored block }
+
+procedure _tr_stored_block(var s : deflate_state;
+                           buf : pcharf;     { input block }
+                           stored_len : ulg; { length of input block }
+                           eof : boolean);   { true if this is the last block for a file }
+
+begin
+  send_bits(s, (STORED_BLOCK shl 1)+ord(eof), 3);  { send block type }
+  s.compressed_len := (s.compressed_len + 3 + 7) and ulg(not Long(7));
+  Inc(s.compressed_len, (stored_len + 4) shl 3);
+
+  copy_block(s, buf, unsigned(stored_len), TRUE); { with header }
+end;
+
+{ ===========================================================================
+  Flush the bit buffer, keeping at most 7 bits in it. }
+
+{local}
+procedure bi_flush(var s : deflate_state);
+begin
+  if (s.bi_valid = 16) then
+  begin
+    {put_short(s, s.bi_buf);}
+    s.pending_buf^[s.pending] := uch(s.bi_buf and $ff);
+    Inc(s.pending);
+    s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);;
+    Inc(s.pending);
+
+    s.bi_buf := 0;
+    s.bi_valid := 0;
+  end
+  else
+   if (s.bi_valid >= 8) then
+   begin
+     {put_byte(s, (Byte)s^.bi_buf);}
+     s.pending_buf^[s.pending] := Byte(s.bi_buf);
+     Inc(s.pending);
+
+     s.bi_buf := s.bi_buf shr 8;
+     Dec(s.bi_valid, 8);
+   end;
+end;
+
+
+{ ===========================================================================
+  Send one empty static block to give enough lookahead for inflate.
+  This takes 10 bits, of which 7 may remain in the bit buffer.
+  The current inflate code requires 9 bits of lookahead. If the
+  last two codes for the previous block (real code plus EOB) were coded
+  on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+  the last real code. In this case we send two empty static blocks instead
+  of one. (There are no problems if the previous block is stored or fixed.)
+  To simplify the code, we assume the worst case of last real code encoded
+  on one bit only. }
+
+procedure _tr_align(var s : deflate_state);
+begin
+  send_bits(s, STATIC_TREES shl 1, 3);
+  {$ifdef DEBUG}
+  Tracevvv(#13'cd '+IntToStr(END_BLOCK));
+  {$ENDIF}
+  send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len);
+  Inc(s.compressed_len, Long(10)); { 3 for block type, 7 for EOB }
+  bi_flush(s);
+  { Of the 10 bits for the empty block, we have already sent
+    (10 - bi_valid) bits. The lookahead for the last real code (before
+    the EOB of the previous block) was thus at least one plus the length
+    of the EOB plus what we have just sent of the empty static block. }
+  if (1 + s.last_eob_len + 10 - s.bi_valid < 9) then
+  begin
+    send_bits(s, STATIC_TREES shl 1, 3);
+    {$ifdef DEBUG}
+    Tracevvv(#13'cd '+IntToStr(END_BLOCK));
+    {$ENDIF}
+    send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len);
+    Inc(s.compressed_len, Long(10));
+    bi_flush(s);
+  end;
+  s.last_eob_len := 7;
+end;
+
+{ ===========================================================================
+  Set the data type to ASCII or BINARY, using a crude approximation:
+  binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+  IN assertion: the fields freq of dyn_ltree are set and the total of all
+  frequencies does not exceed 64K (to fit in an int on 16 bit machines). }
+
+{local}
+procedure set_data_type(var s : deflate_state);
+var
+  n : int;
+  ascii_freq : unsigned;
+  bin_freq : unsigned;
+begin
+  n := 0;
+  ascii_freq := 0;
+  bin_freq := 0;
+
+  while (n < 7) do
+  begin
+    Inc(bin_freq, s.dyn_ltree[n].fc.Freq);
+    Inc(n);
+  end;
+  while (n < 128) do
+  begin
+    Inc(ascii_freq, s.dyn_ltree[n].fc.Freq);
+    Inc(n);
+  end;
+  while (n < LITERALS) do
+  begin
+    Inc(bin_freq, s.dyn_ltree[n].fc.Freq);
+    Inc(n);
+  end;
+  if (bin_freq > (ascii_freq shr 2)) then
+    s.data_type := Byte(Z_BINARY)
+  else
+    s.data_type := Byte(Z_ASCII);
+end;
+
+{ ===========================================================================
+  Send the block data compressed using the given Huffman trees }
+
+{local}
+procedure compress_block(var s : deflate_state;
+                         var ltree : array of ct_data;   { literal tree }
+                         var dtree : array of ct_data);  { distance tree }
+var
+  dist : unsigned;      { distance of matched string }
+  lc : int;             { match length or unmatched char (if dist == 0) }
+  lx : unsigned;        { running index in l_buf }
+  code : unsigned;      { the code to send }
+  extra : int;          { number of extra bits to send }
+begin
+  lx := 0;
+  if (s.last_lit <> 0) then
+  repeat
+    dist := s.d_buf^[lx];
+    lc := s.l_buf^[lx];
+    Inc(lx);
+    if (dist = 0) then
+    begin
+      { send a literal byte }
+      {$ifdef DEBUG}
+      Tracevvv(#13'cd '+IntToStr(lc));
+      Tracecv((lc > 31) and (lc < 128), ' '+AnsiChar(lc)+' ');
+      {$ENDIF}
+      send_bits(s, ltree[lc].fc.Code, ltree[lc].dl.Len);
+    end
+    else
+    begin
+      { Here, lc is the match length - MIN_MATCH }
+      code := _length_code[lc];
+      { send the length code }
+      {$ifdef DEBUG}
+      Tracevvv(#13'cd '+IntToStr(code+LITERALS+1));
+      {$ENDIF}
+      send_bits(s, ltree[code+LITERALS+1].fc.Code, ltree[code+LITERALS+1].dl.Len);
+      extra := extra_lbits[code];
+      if (extra <> 0) then
+      begin
+        Dec(lc, base_length[code]);
+        send_bits(s, lc, extra);       { send the extra length bits }
+      end;
+      Dec(dist); { dist is now the match distance - 1 }
+      {code := d_code(dist);}
+      if (dist < 256) then
+        code := _dist_code[dist]
+      else
+        code := _dist_code[256+(dist shr 7)];
+
+      {$IFDEF DEBUG}
+      Assert (code < D_CODES, 'bad d_code');
+      {$ENDIF}
+
+      { send the distance code }
+      {$ifdef DEBUG}
+      Tracevvv(#13'cd '+IntToStr(code));
+      {$ENDIF}
+      send_bits(s, dtree[code].fc.Code, dtree[code].dl.Len);
+      extra := extra_dbits[code];
+      if (extra <> 0) then
+      begin
+        Dec(dist, base_dist[code]);
+        send_bits(s, dist, extra);   { send the extra distance bits }
+      end;
+    end; { literal or match pair ? }
+
+    { Check that the overlay between pending_buf and d_buf+l_buf is ok: }
+    {$IFDEF DEBUG}
+    Assert(s.pending < s.lit_bufsize + 2*lx, 'pendingBuf overflow');
+    {$ENDIF}
+  until (lx >= s.last_lit);
+
+  {$ifdef DEBUG}
+  Tracevvv(#13'cd '+IntToStr(END_BLOCK));
+  {$ENDIF}
+  send_bits(s, ltree[END_BLOCK].fc.Code, ltree[END_BLOCK].dl.Len);
+  s.last_eob_len := ltree[END_BLOCK].dl.Len;
+end;
+
+
+{ ===========================================================================
+  Determine the best encoding for the current block: dynamic trees, static
+  trees or store, and output the encoded block to the zip file. This function
+  returns the total compressed length for the file so far. }
+
+function _tr_flush_block (var s : deflate_state;
+         buf : pcharf;         { input block, or NULL if too old }
+         stored_len : ulg;     { length of input block }
+         eof : boolean) : ulg; { true if this is the last block for a file }
+var
+  opt_lenb, static_lenb : ulg; { opt_len and static_len in bytes }
+  max_blindex : int;  { index of last bit length code of non zero freq }
+begin
+  max_blindex := 0;
+
+  { Build the Huffman trees unless a stored block is forced }
+  if (s.level > 0) then
+  begin
+    { Check if the file is ascii or binary }
+    if (s.data_type = Z_UNKNOWN) then
+      set_data_type(s);
+
+    { Construct the literal and distance trees }
+    build_tree(s, s.l_desc);
+    {$ifdef DEBUG}
+    Tracev(^M'lit data: dyn %ld, stat %ld {s.opt_len, s.static_len}');
+    {$ENDIF}
+
+    build_tree(s, s.d_desc);
+    {$ifdef DEBUG}
+    Tracev(^M'dist data: dyn %ld, stat %ld {s.opt_len, s.static_len}');
+    {$ENDIF}
+    { At this point, opt_len and static_len are the total bit lengths of
+      the compressed block data, excluding the tree representations. }
+
+    { Build the bit length tree for the above two trees, and get the index
+      in bl_order of the last bit length code to send. }
+    max_blindex := build_bl_tree(s);
+
+    { Determine the best encoding. Compute first the block length in bytes}
+    opt_lenb := (s.opt_len+3+7) shr 3;
+    static_lenb := (s.static_len+3+7) shr 3;
+
+    {$ifdef DEBUG}
+    Tracev(^M'opt %lu(%lu) stat %lu(%lu) stored %lu lit %u '+
+      '{opt_lenb, s.opt_len, static_lenb, s.static_len, stored_len,'+
+      's.last_lit}');
+    {$ENDIF}
+
+    if (static_lenb <= opt_lenb) then
+      opt_lenb := static_lenb;
+
+  end
+  else
+  begin
+    {$IFDEF DEBUG}
+    Assert(buf <> pcharf(NIL), 'lost buf');
+    {$ENDIF}
+    static_lenb := stored_len + 5;
+    opt_lenb := static_lenb;        { force a stored block }
+  end;
+
+  { If compression failed and this is the first and last block,
+    and if the .zip file can be seeked (to rewrite the local header),
+    the whole file is transformed into a stored file:  }
+
+{$ifdef STORED_FILE_OK}
+{$ifdef FORCE_STORED_FILE}
+  if eof and (s.compressed_len = Long(0)) then
+  begin { force stored file }
+{$else}
+  if (stored_len <= opt_lenb) and eof and (s.compressed_len=Long(0))
+     and seekable()) do
+  begin
+{$endif}
+    { Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: }
+    if (buf = pcharf(0)) then
+      error ('block vanished');
+
+    copy_block(buf, unsigned(stored_len), 0); { without header }
+    s.compressed_len := stored_len shl 3;
+    s.method := STORED;
+  end
+  else
+{$endif} { STORED_FILE_OK }
+
+{$ifdef FORCE_STORED}
+  if (buf <> pcharf(0)) then
+  begin { force stored block }
+{$else}
+  if (stored_len+4 <= opt_lenb) and (buf <> pcharf(0)) then
+  begin
+                     { 4: two words for the lengths }
+{$endif}
+    { The test buf <> NULL is only necessary if LIT_BUFSIZE > WSIZE.
+      Otherwise we can't have processed more than WSIZE input bytes since
+      the last block flush, because compression would have been
+      successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+      transform a block into a stored block. }
+
+    _tr_stored_block(s, buf, stored_len, eof);
+
+{$ifdef FORCE_STATIC}
+  end
+  else
+    if (static_lenb >= 0) then
+    begin { force static trees }
+{$else}
+  end
+  else
+    if (static_lenb = opt_lenb) then
+    begin
+{$endif}
+      send_bits(s, (STATIC_TREES shl 1)+ord(eof), 3);
+      compress_block(s, static_ltree, static_dtree);
+      Inc(s.compressed_len, 3 + s.static_len);
+    end
+    else
+    begin
+      send_bits(s, (DYN_TREES shl 1)+ord(eof), 3);
+      send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1,
+                     max_blindex+1);
+      compress_block(s, s.dyn_ltree, s.dyn_dtree);
+      Inc(s.compressed_len, 3 + s.opt_len);
+    end;
+  {$ifdef DEBUG}
+  Assert (s.compressed_len = s.bits_sent, 'bad compressed size');
+  {$ENDIF}
+  init_block(s);
+
+  if (eof) then
+  begin
+    bi_windup(s);
+    Inc(s.compressed_len, 7);  { align on byte boundary }
+  end;
+  {$ifdef DEBUG}
+  Tracev(#13'comprlen %lu(%lu) {s.compressed_len shr 3,'+
+         's.compressed_len-7*ord(eof)}');
+  {$ENDIF}
+
+  _tr_flush_block := s.compressed_len shr 3;
+end;
+
+
+{ ===========================================================================
+  Save the match info and tally the frequency counts. Return true if
+  the current block must be flushed. }
+
+function _tr_tally (var s : deflate_state;
+   dist : unsigned;          { distance of matched string }
+   lc : unsigned) : boolean; { match length-MIN_MATCH or unmatched char (if dist=0) }
+var
+  {$IFDEF DEBUG}
+  MAX_DIST : ush;
+  {$ENDIF}
+  code : ush;
+{$ifdef TRUNCATE_BLOCK}
+var
+  out_length : ulg;
+  in_length : ulg;
+  dcode : int;
+{$endif}
+begin
+  s.d_buf^[s.last_lit] := ush(dist);
+  s.l_buf^[s.last_lit] := uch(lc);
+  Inc(s.last_lit);
+  if (dist = 0) then
+  begin
+    { lc is the unmatched char }
+    Inc(s.dyn_ltree[lc].fc.Freq);
+  end
+  else
+  begin
+    Inc(s.matches);
+    { Here, lc is the match length - MIN_MATCH }
+    Dec(dist);             { dist := match distance - 1 }
+
+    {macro d_code(dist)}
+    if (dist) < 256 then
+      code := _dist_code[dist]
+    else
+      code := _dist_code[256+(dist shr 7)];
+    {$IFDEF DEBUG}
+{macro  MAX_DIST(s) <=> ((s)^.w_size-MIN_LOOKAHEAD)
+   In order to simplify the code, particularly on 16 bit machines, match
+   distances are limited to MAX_DIST instead of WSIZE. }
+    MAX_DIST := ush(s.w_size-MIN_LOOKAHEAD);
+    Assert((dist < ush(MAX_DIST)) and
+           (ush(lc) <= ush(MAX_MATCH-MIN_MATCH)) and
+           (ush(code) < ush(D_CODES)),  '_tr_tally: bad match');
+    {$ENDIF}
+    Inc(s.dyn_ltree[_length_code[lc]+LITERALS+1].fc.Freq);
+    {s.dyn_dtree[d_code(dist)].Freq++;}
+    Inc(s.dyn_dtree[code].fc.Freq);
+  end;
+
+{$ifdef TRUNCATE_BLOCK}
+  { Try to guess if it is profitable to stop the current block here }
+  if (s.last_lit and $1fff = 0) and (s.level > 2) then
+  begin
+    { Compute an upper bound for the compressed length }
+    out_length := ulg(s.last_lit)*Long(8);
+    in_length := ulg(long(s.strstart) - s.block_start);
+    for dcode := 0 to D_CODES-1 do
+    begin
+      Inc(out_length, ulg(s.dyn_dtree[dcode].fc.Freq *
+            (Long(5)+extra_dbits[dcode])) );
+    end;
+    out_length := out_length shr 3;
+    {$ifdef DEBUG}
+    Tracev(^M'last_lit %u, in %ld, out ~%ld(%ld%%) ');
+          { s.last_lit, in_length, out_length,
+           Long(100) - out_length*Long(100) div in_length)); }
+    {$ENDIF}
+    if (s.matches < s.last_lit div 2) and (out_length < in_length div 2) then
+    begin
+      _tr_tally := TRUE;
+      exit;
+    end;
+  end;
+{$endif}
+  _tr_tally := (s.last_lit = s.lit_bufsize-1);
+  { We avoid equality with lit_bufsize because of wraparound at 64K
+    on 16 bit machines and because stored blocks are restricted to
+    64K-1 bytes. }
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/imzconf.inc b/src/lib/vampimg/ZLib/imzconf.inc
new file mode 100644 (file)
index 0000000..ffb585d
--- /dev/null
@@ -0,0 +1,23 @@
+{ -------------------------------------------------------------------- }
+
+{$DEFINE MAX_MATCH_IS_258}
+
+{ Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+  than 64k bytes at a time (needed on systems with 16-bit int). }
+
+{$UNDEF MAXSEG_64K}
+{$DEFINE UNALIGNED_OK}    { requires SizeOf(ush) = 2 ! }
+{$UNDEF DYNAMIC_CRC_TABLE}
+{$UNDEF FASTEST}
+{$DEFINE Use32}
+{$DEFINE patch112}        { apply patch from the zlib home page }
+
+{$IFDEF FPC}
+  {$MODE DELPHI}
+{$ENDIF}
+
+{$UNDEF DEBUG} // for Delphi 2007 in DEBUG mode
+
+{$RANGECHECKS OFF}
+{$OVERFLOWCHECKS OFF}
+{ -------------------------------------------------------------------- }
diff --git a/src/lib/vampimg/ZLib/imzdeflate.pas b/src/lib/vampimg/ZLib/imzdeflate.pas
new file mode 100644 (file)
index 0000000..e0d8218
--- /dev/null
@@ -0,0 +1,2129 @@
+Unit imzdeflate;
+
+{ Orginal: deflate.h -- internal compression state
+           deflate.c -- compress data using the deflation algorithm
+  Copyright (C) 1995-1996 Jean-loup Gailly.
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+
+{  ALGORITHM
+
+       The "deflation" process depends on being able to identify portions
+       of the input text which are identical to earlier input (within a
+       sliding window trailing behind the input currently being processed).
+
+       The most straightforward technique turns out to be the fastest for
+       most input files: try all possible matches and select the longest.
+       The key feature of this algorithm is that insertions into the string
+       dictionary are very simple and thus fast, and deletions are avoided
+       completely. Insertions are performed at each input character, whereas
+       string matches are performed only when the previous match ends. So it
+       is preferable to spend more time in matches to allow very fast string
+       insertions and avoid deletions. The matching algorithm for small
+       strings is inspired from that of Rabin & Karp. A brute force approach
+       is used to find longer strings when a small match has been found.
+       A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+       (by Leonid Broukhis).
+          A previous version of this file used a more sophisticated algorithm
+       (by Fiala and Greene) which is guaranteed to run in linear amortized
+       time, but has a larger average cost, uses more memory and is patented.
+       However the F&G algorithm may be faster for some highly redundant
+       files if the parameter max_chain_length (described below) is too large.
+
+   ACKNOWLEDGEMENTS
+
+       The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+       I found it in 'freeze' written by Leonid Broukhis.
+       Thanks to many people for bug reports and testing.
+
+   REFERENCES
+
+       Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+       Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+
+       A description of the Rabin and Karp algorithm is given in the book
+          "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+
+       Fiala,E.R., and Greene,D.H.
+          Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595}
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  imzutil, impaszlib;
+
+
+function deflateInit_(strm : z_streamp;
+                      level : int;
+                      const version : AnsiString;
+                      stream_size : int) : int;
+
+
+function deflateInit (var strm : z_stream; level : int) : int;
+
+{  Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate(). }
+
+
+{EXPORT}
+function deflate (var strm : z_stream; flush : int) : int;
+
+{ Performs one or both of the following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+  block is terminated and flushed to the output buffer so that the
+  decompressor can get all input data available so far. For method 9, a future
+  variant on method 8, the current block will be flushed but not terminated.
+  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
+  output is byte aligned (the compressor can clear its internal bit buffer)
+  and the current block is always terminated; this can be useful if the
+  compressor has to be restarted from scratch after an interruption (in which
+  case the internal state of the compressor may be lost).
+    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+  special marker is output and the compression dictionary is discarded; this
+  is useful to allow the decompressor to synchronize if one compressed block
+  has been damaged (see inflateSync below).  Flushing degrades compression and
+  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
+  seriously degrade the compression. If deflate returns with avail_out == 0,
+  this function must be called again with the same value of the flush
+  parameter and more output space (updated avail_out), until the flush is
+  complete (deflate returns with non-zero avail_out).
+
+    If the parameter flush is set to Z_FINISH, all pending input is processed,
+  all pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. }
+
+
+function deflateEnd (var strm : z_stream) : int;
+
+{     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated). }
+
+
+
+
+                        { Advanced functions }
+
+{ The following functions are needed only in some special applications. }
+
+
+{EXPORT}
+function deflateInit2 (var strm : z_stream;
+                       level : int;
+                       method : int;
+                       windowBits : int;
+                       memLevel : int;
+                       strategy : int) : int;
+
+{  This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library. (Method 9 will allow a 64K history buffer and
+   partial block flushes.)
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library (the value 16 will be allowed for method 9). Larger
+   values of this parameter result in better compression at the expense of
+   memory usage. The default value is 15 if deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+     If next_in is not null, the library will use this buffer to hold also
+   some history information; the buffer must either hold the entire input
+   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+   is null, the library will allocate its own history buffer (and leave next_in
+   null). next_out need not be provided here but must be provided by the
+   application for the next call of deflate().
+
+     If the history buffer is provided by the application, next_in must
+   must never be changed by the application since the compressor maintains
+   information inside this buffer from call to call; the application
+   must provide more input only by increasing avail_in. next_in is always
+   reset by the library in this case.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   an invalid method). msg is set to null if there is no error message.
+   deflateInit2 does not perform any compression: this will be done by
+   deflate(). }
+
+
+{EXPORT}
+function deflateSetDictionary (var strm : z_stream;
+                               dictionary : pBytef; {const bytes}
+             dictLength : uint) : int;
+
+{    Initializes the compression dictionary (history buffer) from the given
+   byte sequence without producing any compressed output. This function must
+   be called immediately after deflateInit or deflateInit2, before any call
+   of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and
+   can be predicted with good accuracy; the data can then be compressed better
+   than with the default empty dictionary. In this version of the library,
+   only the last 32K bytes of the dictionary are used.
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state
+   is inconsistent (for example if deflate has already been called for this
+   stream). deflateSetDictionary does not perform any compression: this will
+   be done by deflate(). }
+
+{EXPORT}
+function deflateCopy (dest : z_streamp;
+                      source : z_streamp) : int;
+
+{  Sets the destination stream as a complete copy of the source stream.  If
+   the source stream is using an application-supplied history buffer, a new
+   buffer is allocated for the destination stream.  The compressed output
+   buffer is always application-supplied. It's the responsibility of the
+   application to provide the correct values of next_out and avail_out for the
+   next call of deflate.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination. }
+
+{EXPORT}
+function deflateReset (var strm : z_stream) : int;
+
+{   This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NIL). }
+
+
+{EXPORT}
+function deflateParams (var strm : z_stream; level : int; strategy : int) : int;
+
+{    Dynamically update the compression level and compression strategy.
+   This can be used to switch between compression and straight copy of
+   the input data, or to switch to a different kind of input data requiring
+   a different strategy. If the compression level is changed, the input
+   available so far is compressed with the old level (and may be flushed);
+   the new level will take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero. }
+
+
+const
+   deflate_copyright : string = ' deflate 1.1.2 Copyright 1995-1998 Jean-loup Gailly ';
+
+{ If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product. }
+
+implementation
+
+uses
+  imtrees, imadler;
+
+{  ===========================================================================
+   Function prototypes. }
+
+type
+   block_state = (
+    need_more,      { block not completed, need more input or more output }
+    block_done,     { block flush performed }
+    finish_started, { finish started, need only more output at next deflate }
+    finish_done);   { finish done, accept no more input or output }
+
+{ Compression function. Returns the block state after the call. }
+type
+  compress_func = function(var s : deflate_state; flush : int) : block_state;
+
+{local}
+procedure fill_window(var s : deflate_state); forward;
+{local}
+function deflate_stored(var s : deflate_state; flush : int) : block_state;   forward;
+{local}
+function deflate_fast(var s : deflate_state; flush : int) : block_state;   forward;
+{local}
+function deflate_slow(var s : deflate_state; flush : int) : block_state;   forward;
+{local}
+procedure lm_init(var s : deflate_state); forward;
+
+{local}
+procedure putShortMSB(var s : deflate_state; b : uInt); forward;
+{local}
+procedure  flush_pending (var strm : z_stream); forward;
+{local}
+function read_buf(strm : z_streamp;
+                  buf : pBytef;
+                  size : unsigned) : int; forward;
+{$ifdef ASMV}
+procedure match_init; { asm code initialization }
+function longest_match(var deflate_state; cur_match : IPos) : uInt; forward;
+{$else}
+{local}
+function longest_match(var s : deflate_state; cur_match : IPos) : uInt;
+  forward;
+{$endif}
+
+{$ifdef DEBUG}
+{local}
+procedure check_match(var s : deflate_state;
+                      start, match : IPos;
+                      length : int); forward;
+{$endif}
+
+{  ==========================================================================
+  local data }
+
+const
+  ZNIL = 0;
+{ Tail of hash chains }
+
+const
+  TOO_FAR = 4096;
+{ Matches of length 3 are discarded if their distance exceeds TOO_FAR }
+
+const
+  MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1);
+{ Minimum amount of lookahead, except at the end of the input file.
+  See deflate.c for comments about the MIN_MATCH+1. }
+
+{macro MAX_DIST(var s : deflate_state) : uInt;
+begin
+  MAX_DIST := (s.w_size - MIN_LOOKAHEAD);
+end;
+  In order to simplify the code, particularly on 16 bit machines, match
+  distances are limited to MAX_DIST instead of WSIZE. }
+
+
+{ Values for max_lazy_match, good_match and max_chain_length, depending on
+  the desired pack level (0..9). The values given below have been tuned to
+  exclude worst case performance for pathological files. Better values may be
+  found for specific files. }
+
+type
+  config = record
+   good_length : ush; { reduce lazy search above this match length }
+   max_lazy : ush;    { do not perform lazy search above this match length }
+   nice_length : ush; { quit search above this match length }
+   max_chain : ush;
+   func : compress_func;
+  end;
+
+{local}
+const
+  configuration_table : array[0..10-1] of config = (
+{      good lazy nice chain }
+{0} (good_length:0;  max_lazy:0;   nice_length:0;   max_chain:0;    func:deflate_stored),  { store only }
+{1} (good_length:4;  max_lazy:4;   nice_length:8;   max_chain:4;    func:deflate_fast), { maximum speed, no lazy matches }
+{2} (good_length:4;  max_lazy:5;   nice_length:16;  max_chain:8;    func:deflate_fast),
+{3} (good_length:4;  max_lazy:6;   nice_length:32;  max_chain:32;   func:deflate_fast),
+
+{4} (good_length:4;  max_lazy:4;   nice_length:16;  max_chain:16;   func:deflate_slow),  { lazy matches }
+{5} (good_length:8;  max_lazy:16;  nice_length:32;  max_chain:32;   func:deflate_slow),
+{6} (good_length:8;  max_lazy:16;  nice_length:128; max_chain:128;  func:deflate_slow),
+{7} (good_length:8;  max_lazy:32;  nice_length:128; max_chain:256;  func:deflate_slow),
+{8} (good_length:32; max_lazy:128; nice_length:258; max_chain:1024; func:deflate_slow),
+{9} (good_length:32; max_lazy:258; nice_length:258; max_chain:4096; func:deflate_slow)); { maximum compression }
+
+{ Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+  For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+  meaning. }
+
+const
+  EQUAL = 0;
+{ result of memcmp for equal strings }
+
+{ ==========================================================================
+  Update a hash value with the given input byte
+  IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+     input characters, so that a running hash key can be computed from the
+     previous key instead of complete recalculation each time.
+
+macro UPDATE_HASH(s,h,c)
+   h := (( (h) shl s^.hash_shift) xor (c)) and s^.hash_mask;
+}
+
+{ ===========================================================================
+  Insert string str in the dictionary and set match_head to the previous head
+  of the hash chain (the most recent string with same hash key). Return
+  the previous length of the hash chain.
+  If this file is compiled with -DFASTEST, the compression level is forced
+  to 1, and no hash chains are maintained.
+  IN  assertion: all calls to to INSERT_STRING are made with consecutive
+     input characters and the first MIN_MATCH bytes of str are valid
+     (except for the last MIN_MATCH-1 bytes of the input file). }
+
+procedure INSERT_STRING(var s : deflate_state;
+                        str : uInt;
+                        var match_head : IPos);
+begin
+{$ifdef FASTEST}
+   {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])}
+    s.ins_h := ((s.ins_h shl s.hash_shift) xor
+                 (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask;
+    match_head := s.head[s.ins_h]
+    s.head[s.ins_h] := Pos(str);
+{$else}
+   {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])}
+    s.ins_h := ((s.ins_h shl s.hash_shift) xor
+                 (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask;
+
+    match_head := s.head^[s.ins_h];
+    s.prev^[(str) and s.w_mask] := match_head;
+    s.head^[s.ins_h] := Pos(str);
+{$endif}
+end;
+
+{  =========================================================================
+  Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+  prev[] will be initialized on the fly.
+
+macro CLEAR_HASH(s)
+    s^.head[s^.hash_size-1] := ZNIL;
+    zmemzero(pBytef(s^.head), unsigned(s^.hash_size-1)*sizeof(s^.head^[0]));
+}
+
+{  ======================================================================== }
+
+function deflateInit2_(var strm : z_stream;
+                       level : int;
+                       method : int;
+                       windowBits : int;
+                       memLevel : int;
+                       strategy : int;
+                       const version : AnsiString;
+                       stream_size : int) : int;
+var
+  s : deflate_state_ptr;
+  noheader : int;
+
+  overlay : pushfArray;
+  { We overlay pending_buf and d_buf+l_buf. This works since the average
+    output size for (length,distance) codes is <= 24 bits. }
+begin
+  noheader := 0;
+  if (version  =  '') or (version[1] <> ZLIB_VERSION[1]) or
+     (stream_size <> sizeof(z_stream)) then
+  begin
+    deflateInit2_ := Z_VERSION_ERROR;
+    exit;
+  end;
+  {
+  if (strm = Z_NULL) then
+  begin
+    deflateInit2_ := Z_STREAM_ERROR;
+    exit;
+  end;
+  }
+  { SetLength(strm.msg, 255); }
+  strm.msg := '';
+  if not Assigned(strm.zalloc) then
+  begin
+    {$IFDEF FPC}  strm.zalloc := @zcalloc;  {$ELSE}
+    strm.zalloc := zcalloc;
+    {$ENDIF}
+    strm.opaque := voidpf(0);
+  end;
+  if not Assigned(strm.zfree) then
+    {$IFDEF FPC}  strm.zfree := @zcfree;  {$ELSE}
+    strm.zfree := zcfree;
+    {$ENDIF}
+
+  if (level  =  Z_DEFAULT_COMPRESSION) then
+    level := 6;
+{$ifdef FASTEST}
+    level := 1;
+{$endif}
+
+  if (windowBits < 0) then { undocumented feature: suppress zlib header }
+  begin
+    noheader := 1;
+    windowBits := -windowBits;
+  end;
+  if (memLevel < 1) or (memLevel > MAX_MEM_LEVEL) or (method <> Z_DEFLATED)
+    or (windowBits < 8) or (windowBits > 15) or (level < 0)
+    or (level > 9) or (strategy < 0) or (strategy > Z_HUFFMAN_ONLY) then
+  begin
+    deflateInit2_ := Z_STREAM_ERROR;
+    exit;
+  end;
+
+  s := deflate_state_ptr (ZALLOC(strm, 1, sizeof(deflate_state)));
+  if (s = Z_NULL) then
+  begin
+    deflateInit2_ := Z_MEM_ERROR;
+    exit;
+  end;
+  strm.state := pInternal_state(s);
+  s^.strm := @strm;
+
+  s^.noheader := noheader;
+  s^.w_bits := windowBits;
+  s^.w_size := 1 shl s^.w_bits;
+  s^.w_mask := s^.w_size - 1;
+
+  s^.hash_bits := memLevel + 7;
+  s^.hash_size := 1 shl s^.hash_bits;
+  s^.hash_mask := s^.hash_size - 1;
+  s^.hash_shift :=  ((s^.hash_bits+MIN_MATCH-1) div MIN_MATCH);
+
+  s^.window := pzByteArray (ZALLOC(strm, s^.w_size, 2*sizeof(Byte)));
+  s^.prev   := pzPosfArray (ZALLOC(strm, s^.w_size, sizeof(Pos)));
+  s^.head   := pzPosfArray (ZALLOC(strm, s^.hash_size, sizeof(Pos)));
+
+  s^.lit_bufsize := 1 shl (memLevel + 6); { 16K elements by default }
+
+  overlay := pushfArray (ZALLOC(strm, s^.lit_bufsize, sizeof(ush)+2));
+  s^.pending_buf := pzByteArray (overlay);
+  s^.pending_buf_size := ulg(s^.lit_bufsize) * (sizeof(ush)+Long(2));
+
+  if (s^.window = Z_NULL) or (s^.prev = Z_NULL) or (s^.head = Z_NULL)
+   or (s^.pending_buf = Z_NULL) then
+  begin
+    {ERR_MSG(Z_MEM_ERROR);}
+    strm.msg := z_errmsg[z_errbase-Z_MEM_ERROR];
+    deflateEnd (strm);
+    deflateInit2_ := Z_MEM_ERROR;
+    exit;
+  end;
+  s^.d_buf := pushfArray( @overlay^[s^.lit_bufsize div sizeof(ush)] );
+  s^.l_buf := puchfArray( @s^.pending_buf^[(1+sizeof(ush))*s^.lit_bufsize] );
+
+  s^.level := level;
+  s^.strategy := strategy;
+  s^.method := Byte(method);
+
+  deflateInit2_ := deflateReset(strm);
+end;
+
+{  ========================================================================= }
+
+function deflateInit2(var strm : z_stream;
+                      level : int;
+                      method : int;
+                      windowBits : int;
+                      memLevel : int;
+                      strategy : int) : int;
+{ a macro }
+begin
+  deflateInit2 := deflateInit2_(strm, level, method, windowBits,
+                   memLevel, strategy, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+{  ========================================================================= }
+
+function deflateInit_(strm : z_streamp;
+                      level : int;
+                      const version : AnsiString;
+                      stream_size : int) : int;
+begin
+  if (strm = Z_NULL) then
+    deflateInit_ := Z_STREAM_ERROR
+  else
+    deflateInit_ := deflateInit2_(strm^, level, Z_DEFLATED, MAX_WBITS,
+                   DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size);
+  { To do: ignore strm^.next_in if we use it as window }
+end;
+
+{  ========================================================================= }
+
+function deflateInit(var strm : z_stream; level : int) : int;
+{ deflateInit is a macro to allow checking the zlib version
+  and the compiler's view of z_stream: }
+begin
+  deflateInit := deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
+         DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+{  ======================================================================== }
+function deflateSetDictionary (var strm : z_stream;
+                               dictionary : pBytef;
+                               dictLength : uInt) : int;
+var
+  s : deflate_state_ptr;
+  length : uInt;
+  n : uInt;
+  hash_head : IPos;
+var
+  MAX_DIST : uInt;  {macro}
+begin
+  length := dictLength;
+  hash_head := 0;
+
+  if {(@strm  =  Z_NULL) or}
+     (strm.state  =  Z_NULL) or (dictionary  =  Z_NULL)
+    or (deflate_state_ptr(strm.state)^.status <> INIT_STATE) then
+  begin
+    deflateSetDictionary := Z_STREAM_ERROR;
+    exit;
+  end;
+
+  s := deflate_state_ptr(strm.state);
+  strm.adler := adler32(strm.adler, dictionary, dictLength);
+
+  if (length < MIN_MATCH) then
+  begin
+    deflateSetDictionary := Z_OK;
+    exit;
+  end;
+  MAX_DIST := (s^.w_size - MIN_LOOKAHEAD);
+  if (length > MAX_DIST) then
+  begin
+    length := MAX_DIST;
+{$ifndef USE_DICT_HEAD}
+    Inc(dictionary, dictLength - length);  { use the tail of the dictionary }
+{$endif}
+  end;
+
+  zmemcpy( pBytef(s^.window), dictionary, length);
+  s^.strstart := length;
+  s^.block_start := long(length);
+
+  { Insert all strings in the hash table (except for the last two bytes).
+    s^.lookahead stays null, so s^.ins_h will be recomputed at the next
+    call of fill_window. }
+
+  s^.ins_h := s^.window^[0];
+  {UPDATE_HASH(s, s^.ins_h, s^.window[1]);}
+  s^.ins_h := ((s^.ins_h shl s^.hash_shift) xor (s^.window^[1]))
+              and s^.hash_mask;
+
+  for n := 0 to length - MIN_MATCH do
+  begin
+    INSERT_STRING(s^, n, hash_head);
+  end;
+  {if (hash_head <> 0) then
+    hash_head := 0;  - to make compiler happy }
+  deflateSetDictionary := Z_OK;
+end;
+
+{  ======================================================================== }
+function deflateReset (var strm : z_stream) : int;
+var
+  s : deflate_state_ptr;
+begin
+  if {(@strm = Z_NULL) or}
+   (strm.state = Z_NULL)
+   or (not Assigned(strm.zalloc)) or (not Assigned(strm.zfree)) then
+  begin
+    deflateReset := Z_STREAM_ERROR;
+    exit;
+  end;
+
+  strm.total_out := 0;
+  strm.total_in := 0;
+  strm.msg := '';      { use zfree if we ever allocate msg dynamically }
+  strm.data_type := Z_UNKNOWN;
+
+  s := deflate_state_ptr(strm.state);
+  s^.pending := 0;
+  s^.pending_out := pBytef(s^.pending_buf);
+
+  if (s^.noheader < 0) then
+  begin
+    s^.noheader := 0; { was set to -1 by deflate(..., Z_FINISH); }
+  end;
+  if s^.noheader <> 0 then
+    s^.status := BUSY_STATE
+  else
+    s^.status := INIT_STATE;
+  strm.adler := 1;
+  s^.last_flush := Z_NO_FLUSH;
+
+  _tr_init(s^);
+  lm_init(s^);
+
+  deflateReset := Z_OK;
+end;
+
+{  ======================================================================== }
+function deflateParams(var strm : z_stream;
+                       level : int;
+                       strategy : int) : int;
+var
+  s : deflate_state_ptr;
+  func : compress_func;
+  err : int;
+begin
+  err := Z_OK;
+  if {(@strm  =  Z_NULL) or} (strm.state  =  Z_NULL) then
+  begin
+    deflateParams := Z_STREAM_ERROR;
+    exit;
+  end;
+
+  s := deflate_state_ptr(strm.state);
+
+  if (level = Z_DEFAULT_COMPRESSION) then
+  begin
+    level := 6;
+  end;
+  if (level < 0) or (level > 9) or (strategy < 0)
+  or (strategy > Z_HUFFMAN_ONLY) then
+  begin
+    deflateParams := Z_STREAM_ERROR;
+    exit;
+  end;
+  func := configuration_table[s^.level].func;
+
+  if (@func <> @configuration_table[level].func)
+    and (strm.total_in <> 0) then
+  begin
+      { Flush the last buffer: }
+      err := deflate(strm, Z_PARTIAL_FLUSH);
+  end;
+  if (s^.level <> level) then
+  begin
+    s^.level := level;
+    s^.max_lazy_match   := configuration_table[level].max_lazy;
+    s^.good_match       := configuration_table[level].good_length;
+    s^.nice_match       := configuration_table[level].nice_length;
+    s^.max_chain_length := configuration_table[level].max_chain;
+  end;
+  s^.strategy := strategy;
+  deflateParams := err;
+end;
+
+{ =========================================================================
+  Put a short in the pending buffer. The 16-bit value is put in MSB order.
+  IN assertion: the stream state is correct and there is enough room in
+  pending_buf. }
+
+{local}
+procedure putShortMSB (var s : deflate_state; b : uInt);
+begin
+  s.pending_buf^[s.pending] := Byte(b shr 8);
+  Inc(s.pending);
+  s.pending_buf^[s.pending] := Byte(b and $ff);
+  Inc(s.pending);
+end;
+
+{ =========================================================================
+  Flush as much pending output as possible. All deflate() output goes
+  through this function so some applications may wish to modify it
+  to avoid allocating a large strm^.next_out buffer and copying into it.
+  (See also read_buf()). }
+
+{local}
+procedure flush_pending(var strm : z_stream);
+var
+  len : unsigned;
+  s : deflate_state_ptr;
+begin
+  s := deflate_state_ptr(strm.state);
+  len := s^.pending;
+
+  if (len > strm.avail_out) then
+    len := strm.avail_out;
+  if (len = 0) then
+    exit;
+
+  zmemcpy(strm.next_out, s^.pending_out, len);
+  Inc(strm.next_out, len);
+  Inc(s^.pending_out, len);
+  Inc(strm.total_out, len);
+  Dec(strm.avail_out, len);
+  Dec(s^.pending, len);
+  if (s^.pending = 0) then
+  begin
+    s^.pending_out := pBytef(s^.pending_buf);
+  end;
+end;
+
+{ ========================================================================= }
+function deflate (var strm : z_stream; flush : int) : int;
+var
+  old_flush : int; { value of flush param for previous deflate call }
+  s : deflate_state_ptr;
+var
+  header : uInt;
+  level_flags : uInt;
+var
+  bstate : block_state;
+begin
+  if {(@strm = Z_NULL) or} (strm.state = Z_NULL)
+    or (flush > Z_FINISH) or (flush < 0) then
+  begin
+    deflate := Z_STREAM_ERROR;
+    exit;
+  end;
+  s := deflate_state_ptr(strm.state);
+
+  if (strm.next_out = Z_NULL) or
+     ((strm.next_in = Z_NULL) and (strm.avail_in <> 0)) or
+     ((s^.status = FINISH_STATE) and (flush <> Z_FINISH)) then
+  begin
+    {ERR_RETURN(strm^, Z_STREAM_ERROR);}
+    strm.msg := z_errmsg[z_errbase - Z_STREAM_ERROR];
+    deflate := Z_STREAM_ERROR;
+    exit;
+  end;
+  if (strm.avail_out = 0) then
+  begin
+    {ERR_RETURN(strm^, Z_BUF_ERROR);}
+    strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR];
+    deflate := Z_BUF_ERROR;
+    exit;
+  end;
+
+  s^.strm := @strm; { just in case }
+  old_flush := s^.last_flush;
+  s^.last_flush := flush;
+
+  { Write the zlib header }
+  if (s^.status = INIT_STATE) then
+  begin
+
+    header := (Z_DEFLATED + ((s^.w_bits-8) shl 4)) shl 8;
+    level_flags := (s^.level-1) shr 1;
+
+    if (level_flags > 3) then
+      level_flags := 3;
+    header := header or (level_flags shl 6);
+    if (s^.strstart <> 0) then
+      header := header or PRESET_DICT;
+    Inc(header, 31 - (header mod 31));
+
+    s^.status := BUSY_STATE;
+    putShortMSB(s^, header);
+
+    { Save the adler32 of the preset dictionary: }
+    if (s^.strstart <> 0) then
+    begin
+      putShortMSB(s^, uInt(strm.adler shr 16));
+      putShortMSB(s^, uInt(strm.adler and $ffff));
+    end;
+    strm.adler := long(1);
+  end;
+
+  { Flush as much pending output as possible }
+  if (s^.pending <> 0) then
+  begin
+    flush_pending(strm);
+    if (strm.avail_out = 0) then
+    begin
+      { Since avail_out is 0, deflate will be called again with
+  more output space, but possibly with both pending and
+  avail_in equal to zero. There won't be anything to do,
+  but this is not an error situation so make sure we
+  return OK instead of BUF_ERROR at next call of deflate: }
+
+      s^.last_flush := -1;
+      deflate := Z_OK;
+      exit;
+    end;
+
+  { Make sure there is something to do and avoid duplicate consecutive
+    flushes. For repeated and useless calls with Z_FINISH, we keep
+    returning Z_STREAM_END instead of Z_BUFF_ERROR. }
+
+  end
+  else
+    if (strm.avail_in = 0) and (flush <= old_flush)
+      and (flush <> Z_FINISH) then
+    begin
+      {ERR_RETURN(strm^, Z_BUF_ERROR);}
+      strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR];
+      deflate := Z_BUF_ERROR;
+      exit;
+    end;
+
+  { User must not provide more input after the first FINISH: }
+  if (s^.status = FINISH_STATE) and (strm.avail_in <> 0) then
+  begin
+    {ERR_RETURN(strm^, Z_BUF_ERROR);}
+    strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR];
+    deflate := Z_BUF_ERROR;
+    exit;
+  end;
+
+  { Start a new block or continue the current one. }
+  if (strm.avail_in <> 0) or (s^.lookahead <> 0)
+    or ((flush <> Z_NO_FLUSH) and (s^.status <> FINISH_STATE)) then
+  begin
+    bstate := configuration_table[s^.level].func(s^, flush);
+
+    if (bstate = finish_started) or (bstate = finish_done) then
+      s^.status := FINISH_STATE;
+
+    if (bstate = need_more) or (bstate = finish_started) then
+    begin
+      if (strm.avail_out = 0) then
+        s^.last_flush := -1; { avoid BUF_ERROR next call, see above }
+
+      deflate := Z_OK;
+      exit;
+      { If flush != Z_NO_FLUSH && avail_out == 0, the next call
+  of deflate should use the same flush parameter to make sure
+  that the flush is complete. So we don't have to output an
+  empty block here, this will be done at next call. This also
+  ensures that for a very small output buffer, we emit at most
+   one empty block. }
+    end;
+    if (bstate = block_done) then
+    begin
+      if (flush = Z_PARTIAL_FLUSH) then
+        _tr_align(s^)
+      else
+      begin  { FULL_FLUSH or SYNC_FLUSH }
+        _tr_stored_block(s^, pcharf(NIL), Long(0), FALSE);
+        { For a full flush, this empty block will be recognized
+          as a special marker by inflate_sync(). }
+
+        if (flush = Z_FULL_FLUSH) then
+        begin
+          {macro CLEAR_HASH(s);}             { forget history }
+          s^.head^[s^.hash_size-1] := ZNIL;
+          zmemzero(pBytef(s^.head), unsigned(s^.hash_size-1)*sizeof(s^.head^[0]));
+        end;
+      end;
+
+      flush_pending(strm);
+      if (strm.avail_out = 0) then
+      begin
+        s^.last_flush := -1; { avoid BUF_ERROR at next call, see above }
+  deflate := Z_OK;
+        exit;
+      end;
+
+    end;
+  end;
+  {$IFDEF DEBUG}
+  Assert(strm.avail_out > 0, 'bug2');
+  {$ENDIF}
+  if (flush <> Z_FINISH) then
+  begin
+    deflate := Z_OK;
+    exit;
+  end;
+
+  if (s^.noheader <> 0) then
+  begin
+    deflate := Z_STREAM_END;
+    exit;
+  end;
+
+  { Write the zlib trailer (adler32) }
+  putShortMSB(s^, uInt(strm.adler shr 16));
+  putShortMSB(s^, uInt(strm.adler and $ffff));
+  flush_pending(strm);
+  { If avail_out is zero, the application will call deflate again
+    to flush the rest. }
+
+  s^.noheader := -1; { write the trailer only once! }
+  if s^.pending <> 0 then
+    deflate := Z_OK
+  else
+    deflate := Z_STREAM_END;
+end;
+
+{ ========================================================================= }
+function deflateEnd (var strm : z_stream) : int;
+var
+  status : int;
+  s : deflate_state_ptr;
+begin
+  if {(@strm = Z_NULL) or} (strm.state = Z_NULL) then
+  begin
+    deflateEnd := Z_STREAM_ERROR;
+    exit;
+  end;
+
+  s := deflate_state_ptr(strm.state);
+  status := s^.status;
+  if (status <> INIT_STATE) and (status <> BUSY_STATE) and
+     (status <> FINISH_STATE) then
+  begin
+    deflateEnd := Z_STREAM_ERROR;
+    exit;
+  end;
+
+  { Deallocate in reverse order of allocations: }
+  TRY_FREE(strm, s^.pending_buf);
+  TRY_FREE(strm, s^.head);
+  TRY_FREE(strm, s^.prev);
+  TRY_FREE(strm, s^.window);
+
+  ZFREE(strm, s);
+  strm.state := Z_NULL;
+
+  if status = BUSY_STATE then
+    deflateEnd := Z_DATA_ERROR
+  else
+    deflateEnd := Z_OK;
+end;
+
+{ =========================================================================
+  Copy the source state to the destination state.
+  To simplify the source, this is not supported for 16-bit MSDOS (which
+  doesn't have enough memory anyway to duplicate compression states). }
+
+
+{ ========================================================================= }
+function deflateCopy (dest, source : z_streamp) : int;
+{$ifndef MAXSEG_64K}
+var
+  ds : deflate_state_ptr;
+  ss : deflate_state_ptr;
+  overlay : pushfArray;
+{$endif}
+begin
+{$ifdef MAXSEG_64K}
+  deflateCopy := Z_STREAM_ERROR;
+  exit;
+{$else}
+
+  if (source = Z_NULL) or (dest = Z_NULL) or (source^.state = Z_NULL) then
+  begin
+    deflateCopy := Z_STREAM_ERROR;
+    exit;
+  end;
+  ss := deflate_state_ptr(source^.state);
+  dest^ := source^;
+
+  ds := deflate_state_ptr( ZALLOC(dest^, 1, sizeof(deflate_state)) );
+  if (ds = Z_NULL) then
+  begin
+    deflateCopy := Z_MEM_ERROR;
+    exit;
+  end;
+  dest^.state := pInternal_state(ds);
+  ds^ := ss^;
+  ds^.strm := dest;
+
+  ds^.window := pzByteArray ( ZALLOC(dest^, ds^.w_size, 2*sizeof(Byte)) );
+  ds^.prev   := pzPosfArray ( ZALLOC(dest^, ds^.w_size, sizeof(Pos)) );
+  ds^.head   := pzPosfArray ( ZALLOC(dest^, ds^.hash_size, sizeof(Pos)) );
+  overlay := pushfArray ( ZALLOC(dest^, ds^.lit_bufsize, sizeof(ush)+2) );
+  ds^.pending_buf := pzByteArray ( overlay );
+
+  if (ds^.window = Z_NULL) or (ds^.prev = Z_NULL) or (ds^.head = Z_NULL)
+     or (ds^.pending_buf = Z_NULL) then
+  begin
+    deflateEnd (dest^);
+    deflateCopy := Z_MEM_ERROR;
+    exit;
+  end;
+  { following zmemcpy do not work for 16-bit MSDOS }
+  zmemcpy(pBytef(ds^.window), pBytef(ss^.window), ds^.w_size * 2 * sizeof(Byte));
+  zmemcpy(pBytef(ds^.prev), pBytef(ss^.prev), ds^.w_size * sizeof(Pos));
+  zmemcpy(pBytef(ds^.head), pBytef(ss^.head), ds^.hash_size * sizeof(Pos));
+  zmemcpy(pBytef(ds^.pending_buf), pBytef(ss^.pending_buf), uInt(ds^.pending_buf_size));
+
+  ds^.pending_out := @ds^.pending_buf^[ptr2int(ss^.pending_out) - ptr2int(ss^.pending_buf)];
+  ds^.d_buf := pushfArray (@overlay^[ds^.lit_bufsize div sizeof(ush)] );
+  ds^.l_buf := puchfArray (@ds^.pending_buf^[(1+sizeof(ush))*ds^.lit_bufsize]);
+
+  ds^.l_desc.dyn_tree := tree_ptr(@ds^.dyn_ltree);
+  ds^.d_desc.dyn_tree := tree_ptr(@ds^.dyn_dtree);
+  ds^.bl_desc.dyn_tree := tree_ptr(@ds^.bl_tree);
+
+  deflateCopy := Z_OK;
+{$endif}
+end;
+
+
+{ ===========================================================================
+  Read a new buffer from the current input stream, update the adler32
+  and total number of bytes read.  All deflate() input goes through
+  this function so some applications may wish to modify it to avoid
+  allocating a large strm^.next_in buffer and copying from it.
+  (See also flush_pending()). }
+
+{local}
+function read_buf(strm : z_streamp; buf : pBytef; size : unsigned) : int;
+var
+  len : unsigned;
+begin
+  len := strm^.avail_in;
+
+  if (len > size) then
+    len := size;
+  if (len = 0) then
+  begin
+    read_buf := 0;
+    exit;
+  end;
+
+  Dec(strm^.avail_in, len);
+
+  if deflate_state_ptr(strm^.state)^.noheader = 0 then
+  begin
+    strm^.adler := adler32(strm^.adler, strm^.next_in, len);
+  end;
+  zmemcpy(buf, strm^.next_in, len);
+  Inc(strm^.next_in, len);
+  Inc(strm^.total_in, len);
+
+  read_buf := int(len);
+end;
+
+{ ===========================================================================
+  Initialize the "longest match" routines for a new zlib stream }
+
+{local}
+procedure lm_init (var s : deflate_state);
+begin
+  s.window_size := ulg( uLong(2)*s.w_size);
+
+  {macro CLEAR_HASH(s);}
+  s.head^[s.hash_size-1] := ZNIL;
+  zmemzero(pBytef(s.head), unsigned(s.hash_size-1)*sizeof(s.head^[0]));
+
+  { Set the default configuration parameters: }
+
+  s.max_lazy_match   := configuration_table[s.level].max_lazy;
+  s.good_match       := configuration_table[s.level].good_length;
+  s.nice_match       := configuration_table[s.level].nice_length;
+  s.max_chain_length := configuration_table[s.level].max_chain;
+
+  s.strstart := 0;
+  s.block_start := long(0);
+  s.lookahead := 0;
+  s.prev_length := MIN_MATCH-1;
+  s.match_length := MIN_MATCH-1;
+  s.match_available := FALSE;
+  s.ins_h := 0;
+{$ifdef ASMV}
+  match_init; { initialize the asm code }
+{$endif}
+end;
+
+{ ===========================================================================
+  Set match_start to the longest match starting at the given string and
+  return its length. Matches shorter or equal to prev_length are discarded,
+  in which case the result is equal to prev_length and match_start is
+  garbage.
+  IN assertions: cur_match is the head of the hash chain for the current
+    string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+  OUT assertion: the match length is not greater than s^.lookahead. }
+
+
+{$ifndef ASMV}
+{ For 80x86 and 680x0, an optimized version will be provided in match.asm or
+  match.S. The code will be functionally equivalent. }
+
+{$ifndef FASTEST}
+
+{local}
+function longest_match(var s : deflate_state;
+                       cur_match : IPos  { current match }
+                       ) : uInt;
+label
+  nextstep;
+var
+  chain_length : unsigned;    { max hash chain length }
+  {register} scan : pBytef;   { current string }
+  {register} match : pBytef;  { matched string }
+  {register} len : int;       { length of current match }
+  best_len : int;             { best match length so far }
+  nice_match : int;           { stop if match long enough }
+  limit : IPos;
+
+  prev : pzPosfArray;
+  wmask : uInt;
+{$ifdef UNALIGNED_OK}
+  {register} strend : pBytef;
+  {register} scan_start : ush;
+  {register} scan_end : ush;
+{$else}
+  {register} strend : pBytef;
+  {register} scan_end1 : Byte;
+  {register} scan_end : Byte;
+{$endif}
+var
+  MAX_DIST : uInt;
+begin
+  chain_length := s.max_chain_length; { max hash chain length }
+  scan := @(s.window^[s.strstart]);
+  best_len := s.prev_length;              { best match length so far }
+  nice_match := s.nice_match;             { stop if match long enough }
+
+
+  MAX_DIST := s.w_size - MIN_LOOKAHEAD;
+{In order to simplify the code, particularly on 16 bit machines, match
+distances are limited to MAX_DIST instead of WSIZE. }
+
+  if s.strstart > IPos(MAX_DIST) then
+    limit := s.strstart - IPos(MAX_DIST)
+  else
+    limit := ZNIL;
+  { Stop when cur_match becomes <= limit. To simplify the code,
+    we prevent matches with the string of window index 0. }
+
+  prev := s.prev;
+  wmask := s.w_mask;
+
+{$ifdef UNALIGNED_OK}
+  { Compare two bytes at a time. Note: this is not always beneficial.
+    Try with and without -DUNALIGNED_OK to check. }
+
+  strend := pBytef(@(s.window^[s.strstart + MAX_MATCH - 1]));
+  scan_start := pushf(scan)^;
+  scan_end   := pushfArray(scan)^[best_len-1];   { fix }
+{$else}
+  strend := pBytef(@(s.window^[s.strstart + MAX_MATCH]));
+  {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+  scan_end1  := pzByteArray(scan)^[best_len-1];
+  {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+  scan_end   := pzByteArray(scan)^[best_len];
+{$endif}
+
+    { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+      It is easy to get rid of this optimization if necessary. }
+    {$IFDEF DEBUG}
+    Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever');
+    {$ENDIF}
+    { Do not waste too much time if we already have a good match: }
+    if (s.prev_length >= s.good_match) then
+    begin
+      chain_length := chain_length shr 2;
+    end;
+
+    { Do not look for matches beyond the end of the input. This is necessary
+      to make deflate deterministic. }
+
+    if (uInt(nice_match) > s.lookahead) then
+      nice_match := s.lookahead;
+    {$IFDEF DEBUG}
+    Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead');
+    {$ENDIF}
+    repeat
+        {$IFDEF DEBUG}
+        Assert(cur_match < s.strstart, 'no future');
+        {$ENDIF}
+        match := @(s.window^[cur_match]);
+
+        { Skip to next match if the match length cannot increase
+          or if the match length is less than 2: }
+
+{$undef DO_UNALIGNED_OK}
+{$ifdef UNALIGNED_OK}
+  {$ifdef MAX_MATCH_IS_258}
+    {$define DO_UNALIGNED_OK}
+  {$endif}
+{$endif}
+
+{$ifdef DO_UNALIGNED_OK}
+        { This code assumes sizeof(unsigned short) = 2. Do not use
+          UNALIGNED_OK if your compiler uses a different size. }
+  {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+        if (pushfArray(match)^[best_len-1] <> scan_end) or
+           (pushf(match)^ <> scan_start) then
+          goto nextstep; {continue;}
+  {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+
+        { It is not necessary to compare scan[2] and match[2] since they are
+          always equal when the other bytes match, given that the hash keys
+          are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+          strstart+3, +5, ... up to strstart+257. We check for insufficient
+          lookahead only every 4th comparison; the 128th check will be made
+          at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+          necessary to put more guard bytes at the end of the window, or
+          to check more often for insufficient lookahead. }
+        {$IFDEF DEBUG}
+        Assert(pzByteArray(scan)^[2] = pzByteArray(match)^[2], 'scan[2]?');
+        {$ENDIF}
+        Inc(scan);
+        Inc(match);
+
+        repeat
+          Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
+          Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
+          Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
+          Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
+        until (ptr2int(scan) >= ptr2int(strend));
+        { The funny "do while" generates better code on most compilers }
+
+        { Here, scan <= window+strstart+257 }
+        {$IFDEF DEBUG}
+        {$ifopt R+} {$define RangeCheck} {$endif} {$R-}
+        Assert(ptr2int(scan) <=
+               ptr2int(@(s.window^[unsigned(s.window_size-1)])),
+               'wild scan');
+        {$ifdef RangeCheck} {$R+} {$undef RangeCheck} {$endif}
+        {$ENDIF}
+        if (scan^ = match^) then
+          Inc(scan);
+
+        len := (MAX_MATCH - 1) - int(ptr2int(strend)) + int(ptr2int(scan));
+        scan := strend;
+        Dec(scan, (MAX_MATCH-1));
+
+{$else} { UNALIGNED_OK }
+
+  {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+        if (pzByteArray(match)^[best_len]   <> scan_end) or
+           (pzByteArray(match)^[best_len-1] <> scan_end1) or
+           (match^ <> scan^) then
+          goto nextstep; {continue;}
+  {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+        Inc(match);
+        if (match^ <> pzByteArray(scan)^[1]) then
+          goto nextstep; {continue;}
+
+        { The check at best_len-1 can be removed because it will be made
+          again later. (This heuristic is not always a win.)
+          It is not necessary to compare scan[2] and match[2] since they
+          are always equal when the other bytes match, given that
+          the hash keys are equal and that HASH_BITS >= 8. }
+
+        Inc(scan, 2);
+        Inc(match);
+        {$IFDEF DEBUG}
+        Assert( scan^ = match^, 'match[2]?');
+        {$ENDIF}
+        { We check for insufficient lookahead only every 8th comparison;
+          the 256th check will be made at strstart+258. }
+
+        repeat
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+          Inc(scan); Inc(match); if (scan^ <> match^) then break;
+        until (ptr2int(scan) >= ptr2int(strend));
+
+        {$IFDEF DEBUG}
+        Assert(ptr2int(scan) <=
+               ptr2int(@(s.window^[unsigned(s.window_size-1)])),
+               'wild scan');
+        {$ENDIF}
+
+        len := MAX_MATCH - int(ptr2int(strend) - ptr2int(scan));
+        scan := strend;
+        Dec(scan, MAX_MATCH);
+
+{$endif} { UNALIGNED_OK }
+
+        if (len > best_len) then
+        begin
+            s.match_start := cur_match;
+            best_len := len;
+            if (len >= nice_match) then
+              break;
+  {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
+{$ifdef UNALIGNED_OK}
+            scan_end   := pzByteArray(scan)^[best_len-1];
+{$else}
+            scan_end1  := pzByteArray(scan)^[best_len-1];
+            scan_end   := pzByteArray(scan)^[best_len];
+{$endif}
+  {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
+        end;
+    nextstep:
+      cur_match := prev^[cur_match and wmask];
+      Dec(chain_length);
+    until (cur_match <= limit) or (chain_length = 0);
+
+    if (uInt(best_len) <= s.lookahead) then
+      longest_match := uInt(best_len)
+    else
+      longest_match := s.lookahead;
+end;
+{$endif} { ASMV }
+
+{$else} { FASTEST }
+{ ---------------------------------------------------------------------------
+  Optimized version for level = 1 only }
+
+{local}
+function longest_match(var s : deflate_state;
+                       cur_match : IPos  { current match }
+                       ) : uInt;
+var
+  {register} scan : pBytef;   { current string }
+  {register} match : pBytef;  { matched string }
+  {register} len : int;       { length of current match }
+  {register} strend : pBytef;
+begin
+  scan := @s.window^[s.strstart];
+  strend := @s.window^[s.strstart + MAX_MATCH];
+
+
+    { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+      It is easy to get rid of this optimization if necessary. }
+    {$IFDEF DEBUG}
+    Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever');
+
+    Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead');
+
+    Assert(cur_match < s.strstart, 'no future');
+    {$ENDIF}
+    match := s.window + cur_match;
+
+    { Return failure if the match length is less than 2: }
+
+    if (match[0] <> scan[0]) or (match[1] <> scan[1]) then
+    begin
+      longest_match := MIN_MATCH-1;
+      exit;
+    end;
+
+    { The check at best_len-1 can be removed because it will be made
+      again later. (This heuristic is not always a win.)
+      It is not necessary to compare scan[2] and match[2] since they
+      are always equal when the other bytes match, given that
+      the hash keys are equal and that HASH_BITS >= 8. }
+
+    scan += 2, match += 2;
+    Assert(scan^ = match^, 'match[2]?');
+
+    { We check for insufficient lookahead only every 8th comparison;
+      the 256th check will be made at strstart+258. }
+
+    repeat
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+      Inc(scan); Inc(match); if scan^<>match^ then break;
+    until (ptr2int(scan) >= ptr2int(strend));
+
+    Assert(scan <= s.window+unsigned(s.window_size-1), 'wild scan');
+
+    len := MAX_MATCH - int(strend - scan);
+
+    if (len < MIN_MATCH) then
+    begin
+      return := MIN_MATCH - 1;
+      exit;
+    end;
+
+    s.match_start := cur_match;
+    if len <= s.lookahead then
+      longest_match := len
+    else
+      longest_match := s.lookahead;
+end;
+{$endif} { FASTEST }
+
+{$ifdef DEBUG}
+{ ===========================================================================
+  Check that the match at match_start is indeed a match. }
+
+{local}
+procedure check_match(var s : deflate_state;
+                      start, match : IPos;
+                      length : int);
+begin
+  exit;
+  { check that the match is indeed a match }
+  if (zmemcmp(pBytef(@s.window^[match]),
+              pBytef(@s.window^[start]), length) <> EQUAL) then
+  begin
+    WriteLn(' start ',start,', match ',match ,' length ', length);
+    repeat
+      Write(AnsiChar(s.window^[match]), AnsiChar(s.window^[start]));
+      Inc(match);
+      Inc(start);
+      Dec(length);
+    Until (length = 0);
+    z_error('invalid match');
+  end;
+  if (z_verbose > 1) then
+  begin
+    Write('\\[',start-match,',',length,']');
+    repeat
+       Write(AnsiChar(s.window^[start]));
+       Inc(start);
+       Dec(length);
+    Until (length = 0);
+  end;
+end;
+{$endif}
+
+{ ===========================================================================
+  Fill the window when the lookahead becomes insufficient.
+  Updates strstart and lookahead.
+
+  IN assertion: lookahead < MIN_LOOKAHEAD
+  OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+     At least one byte has been read, or avail_in = 0; reads are
+     performed for at least two bytes (required for the zip translate_eol
+     option -- not supported here). }
+
+{local}
+procedure fill_window(var s : deflate_state);
+var
+  {register} n, m : unsigned;
+  {register} p : pPosf;
+  more : unsigned;    { Amount of free space at the end of the window. }
+  wsize : uInt;
+begin
+   wsize := s.w_size;
+   repeat
+     more := unsigned(s.window_size -ulg(s.lookahead) -ulg(s.strstart));
+
+     { Deal with !@#$% 64K limit: }
+     if (more = 0) and (s.strstart = 0) and (s.lookahead = 0) then
+       more := wsize
+     else
+     if (more = unsigned(-1)) then
+     begin
+       { Very unlikely, but possible on 16 bit machine if strstart = 0
+         and lookahead = 1 (input done one byte at time) }
+       Dec(more);
+
+       { If the window is almost full and there is insufficient lookahead,
+         move the upper half to the lower one to make room in the upper half.}
+     end
+     else
+       if (s.strstart >= wsize+ {MAX_DIST}(wsize-MIN_LOOKAHEAD)) then
+       begin
+         zmemcpy( pBytef(s.window), pBytef(@(s.window^[wsize])),
+                 unsigned(wsize));
+         Dec(s.match_start, wsize);
+         Dec(s.strstart, wsize); { we now have strstart >= MAX_DIST }
+         Dec(s.block_start, long(wsize));
+
+         { Slide the hash table (could be avoided with 32 bit values
+           at the expense of memory usage). We slide even when level = 0
+           to keep the hash table consistent if we switch back to level > 0
+           later. (Using level 0 permanently is not an optimal usage of
+           zlib, so we don't care about this pathological case.) }
+
+         n := s.hash_size;
+         p := @s.head^[n];
+         repeat
+           Dec(p);
+           m := p^;
+           if (m >= wsize) then
+             p^ := Pos(m-wsize)
+           else
+             p^ := Pos(ZNIL);
+           Dec(n);
+         Until (n=0);
+
+         n := wsize;
+{$ifndef FASTEST}
+         p := @s.prev^[n];
+         repeat
+           Dec(p);
+           m := p^;
+           if (m >= wsize) then
+             p^ := Pos(m-wsize)
+           else
+             p^:= Pos(ZNIL);
+             { If n is not on any hash chain, prev^[n] is garbage but
+               its value will never be used. }
+           Dec(n);
+         Until (n=0);
+{$endif}
+         Inc(more, wsize);
+     end;
+     if (s.strm^.avail_in = 0) then
+       exit;
+
+     {* If there was no sliding:
+      *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+      *    more == window_size - lookahead - strstart
+      * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+      * => more >= window_size - 2*WSIZE + 2
+      * In the BIG_MEM or MMAP case (not yet supported),
+      *   window_size == input_size + MIN_LOOKAHEAD  &&
+      *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+      * Otherwise, window_size == 2*WSIZE so more >= 2.
+      * If there was sliding, more >= WSIZE. So in all cases, more >= 2. }
+
+     {$IFDEF DEBUG}
+     Assert(more >= 2, 'more < 2');
+     {$ENDIF}
+
+     n := read_buf(s.strm, pBytef(@(s.window^[s.strstart + s.lookahead])),
+                  more);
+     Inc(s.lookahead, n);
+
+     { Initialize the hash value now that we have some input: }
+     if (s.lookahead >= MIN_MATCH) then
+     begin
+       s.ins_h := s.window^[s.strstart];
+       {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);}
+       s.ins_h := ((s.ins_h shl s.hash_shift) xor s.window^[s.strstart+1])
+                     and s.hash_mask;
+{$ifdef MIN_MATCH <> 3}
+       Call UPDATE_HASH() MIN_MATCH-3 more times
+{$endif}
+     end;
+     { If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+       but this is not important since only literal bytes will be emitted. }
+
+   until (s.lookahead >= MIN_LOOKAHEAD) or (s.strm^.avail_in = 0);
+end;
+
+{ ===========================================================================
+  Flush the current block, with given end-of-file flag.
+  IN assertion: strstart is set to the end of the current match. }
+
+procedure FLUSH_BLOCK_ONLY(var s : deflate_state; eof : boolean); {macro}
+begin
+  if (s.block_start >= Long(0)) then
+    _tr_flush_block(s, pcharf(@s.window^[unsigned(s.block_start)]),
+                    ulg(long(s.strstart) - s.block_start), eof)
+  else
+    _tr_flush_block(s, pcharf(Z_NULL),
+                    ulg(long(s.strstart) - s.block_start), eof);
+
+  s.block_start := s.strstart;
+  flush_pending(s.strm^);
+  {$IFDEF DEBUG}
+  Tracev('[FLUSH]');
+  {$ENDIF}
+end;
+
+{ Same but force premature exit if necessary.
+macro FLUSH_BLOCK(var s : deflate_state; eof : boolean) : boolean;
+var
+  result : block_state;
+begin
+ FLUSH_BLOCK_ONLY(s, eof);
+ if (s.strm^.avail_out = 0) then
+ begin
+   if eof then
+     result := finish_started
+   else
+     result := need_more;
+   exit;
+ end;
+end;
+}
+
+{ ===========================================================================
+  Copy without compression as much as possible from the input stream, return
+  the current block state.
+  This function does not insert new strings in the dictionary since
+  uncompressible data is probably not useful. This function is used
+  only for the level=0 compression option.
+  NOTE: this function should be optimized to avoid extra copying from
+  window to pending_buf. }
+
+
+{local}
+function deflate_stored(var s : deflate_state; flush : int) : block_state;
+{ Stored blocks are limited to 0xffff bytes, pending_buf is limited
+  to pending_buf_size, and each stored block has a 5 byte header: }
+var
+  max_block_size : ulg;
+  max_start : ulg;
+begin
+  max_block_size := $ffff;
+  if (max_block_size > s.pending_buf_size - 5) then
+    max_block_size := s.pending_buf_size - 5;
+
+  { Copy as much as possible from input to output: }
+  while TRUE do
+  begin
+    { Fill the window as much as possible: }
+    if (s.lookahead <= 1) then
+    begin
+      {$IFDEF DEBUG}
+      Assert( (s.strstart < s.w_size + {MAX_DIST}s.w_size-MIN_LOOKAHEAD) or
+              (s.block_start >= long(s.w_size)), 'slide too late');
+      {$ENDIF}
+      fill_window(s);
+      if (s.lookahead = 0) and (flush = Z_NO_FLUSH) then
+      begin
+        deflate_stored := need_more;
+        exit;
+      end;
+
+      if (s.lookahead = 0) then
+        break; { flush the current block }
+    end;
+    {$IFDEF DEBUG}
+    Assert(s.block_start >= long(0), 'block gone');
+    {$ENDIF}
+    Inc(s.strstart, s.lookahead);
+    s.lookahead := 0;
+
+    { Emit a stored block if pending_buf will be full: }
+    max_start := s.block_start + max_block_size;
+    if (s.strstart = 0) or (ulg(s.strstart) >= max_start) then
+    begin
+      { strstart = 0 is possible when wraparound on 16-bit machine }
+      s.lookahead := s.strstart - uInt(max_start);
+      s.strstart := uInt(max_start);
+      {FLUSH_BLOCK(s, FALSE);}
+      FLUSH_BLOCK_ONLY(s, FALSE);
+      if (s.strm^.avail_out = 0) then
+      begin
+        deflate_stored := need_more;
+        exit;
+      end;
+    end;
+
+    { Flush if we may have to slide, otherwise block_start may become
+      negative and the data will be gone: }
+
+    if (s.strstart - uInt(s.block_start) >= {MAX_DIST}
+        s.w_size-MIN_LOOKAHEAD) then
+    begin
+      {FLUSH_BLOCK(s, FALSE);}
+      FLUSH_BLOCK_ONLY(s, FALSE);
+      if (s.strm^.avail_out = 0) then
+      begin
+        deflate_stored := need_more;
+        exit;
+      end;
+    end;
+  end;
+
+  {FLUSH_BLOCK(s, flush = Z_FINISH);}
+  FLUSH_BLOCK_ONLY(s, flush = Z_FINISH);
+  if (s.strm^.avail_out = 0) then
+  begin
+    if flush = Z_FINISH then
+      deflate_stored := finish_started
+    else
+      deflate_stored := need_more;
+    exit;
+  end;
+
+  if flush = Z_FINISH then
+    deflate_stored := finish_done
+  else
+    deflate_stored := block_done;
+end;
+
+{ ===========================================================================
+  Compress as much as possible from the input stream, return the current
+  block state.
+  This function does not perform lazy evaluation of matches and inserts
+  new strings in the dictionary only for unmatched strings or for short
+  matches. It is used only for the fast compression options. }
+
+{local}
+function deflate_fast(var s : deflate_state; flush : int) : block_state;
+var
+  hash_head : IPos;     { head of the hash chain }
+  bflush : boolean;     { set if current block must be flushed }
+begin
+  hash_head := ZNIL;
+  while TRUE do
+  begin
+  { Make sure that we always have enough lookahead, except
+    at the end of the input file. We need MAX_MATCH bytes
+    for the next match, plus MIN_MATCH bytes to insert the
+    string following the next match. }
+
+    if (s.lookahead < MIN_LOOKAHEAD) then
+    begin
+      fill_window(s);
+      if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then
+      begin
+        deflate_fast := need_more;
+        exit;
+      end;
+
+      if (s.lookahead = 0) then
+        break; { flush the current block }
+    end;
+
+
+    { Insert the string window[strstart .. strstart+2] in the
+      dictionary, and set hash_head to the head of the hash chain: }
+
+    if (s.lookahead >= MIN_MATCH) then
+    begin
+      INSERT_STRING(s, s.strstart, hash_head);
+    end;
+
+    { Find the longest match, discarding those <= prev_length.
+      At this point we have always match_length < MIN_MATCH }
+    if (hash_head <> ZNIL) and
+       (s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD){MAX_DIST}) then
+    begin
+      { To simplify the code, we prevent matches with the string
+        of window index 0 (in particular we have to avoid a match
+        of the string with itself at the start of the input file). }
+      if (s.strategy <> Z_HUFFMAN_ONLY) then
+      begin
+        s.match_length := longest_match (s, hash_head);
+      end;
+      { longest_match() sets match_start }
+    end;
+    if (s.match_length >= MIN_MATCH) then
+    begin
+      {$IFDEF DEBUG}
+      check_match(s, s.strstart, s.match_start, s.match_length);
+      {$ENDIF}
+
+      {_tr_tally_dist(s, s.strstart - s.match_start,
+                        s.match_length - MIN_MATCH, bflush);}
+      bflush := _tr_tally(s, s.strstart - s.match_start,
+                        s.match_length - MIN_MATCH);
+
+      Dec(s.lookahead, s.match_length);
+
+      { Insert new strings in the hash table only if the match length
+        is not too large. This saves time but degrades compression. }
+
+{$ifndef FASTEST}
+      if (s.match_length <= s.max_insert_length)
+       and (s.lookahead >= MIN_MATCH) then
+      begin
+        Dec(s.match_length); { string at strstart already in hash table }
+        repeat
+          Inc(s.strstart);
+          INSERT_STRING(s, s.strstart, hash_head);
+          { strstart never exceeds WSIZE-MAX_MATCH, so there are
+            always MIN_MATCH bytes ahead. }
+          Dec(s.match_length);
+        until (s.match_length = 0);
+        Inc(s.strstart);
+      end
+      else
+{$endif}
+
+      begin
+        Inc(s.strstart, s.match_length);
+        s.match_length := 0;
+        s.ins_h := s.window^[s.strstart];
+        {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);}
+        s.ins_h := (( s.ins_h shl s.hash_shift) xor
+                     s.window^[s.strstart+1]) and s.hash_mask;
+if MIN_MATCH <> 3 then   { the linker removes this }
+begin
+          {Call UPDATE_HASH() MIN_MATCH-3 more times}
+end;
+
+        { If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+          matter since it will be recomputed at next deflate call. }
+
+      end;
+    end
+    else
+    begin
+      { No match, output a literal byte }
+      {$IFDEF DEBUG}
+      Tracevv(AnsiChar(s.window^[s.strstart]));
+      {$ENDIF}
+      {_tr_tally_lit (s, 0, s.window^[s.strstart], bflush);}
+      bflush := _tr_tally (s, 0, s.window^[s.strstart]);
+
+      Dec(s.lookahead);
+      Inc(s.strstart);
+    end;
+    if bflush then
+    begin  {FLUSH_BLOCK(s, FALSE);}
+      FLUSH_BLOCK_ONLY(s, FALSE);
+      if (s.strm^.avail_out = 0) then
+      begin
+        deflate_fast := need_more;
+        exit;
+      end;
+    end;
+  end;
+  {FLUSH_BLOCK(s, flush = Z_FINISH);}
+  FLUSH_BLOCK_ONLY(s, flush = Z_FINISH);
+  if (s.strm^.avail_out = 0) then
+  begin
+    if flush = Z_FINISH then
+      deflate_fast := finish_started
+    else
+      deflate_fast := need_more;
+    exit;
+  end;
+
+  if flush = Z_FINISH then
+    deflate_fast := finish_done
+  else
+    deflate_fast := block_done;
+end;
+
+{ ===========================================================================
+  Same as above, but achieves better compression. We use a lazy
+  evaluation for matches: a match is finally adopted only if there is
+  no better match at the next window position. }
+
+{local}
+function deflate_slow(var s : deflate_state; flush : int) : block_state;
+var
+  hash_head : IPos;       { head of hash chain }
+  bflush : boolean;       { set if current block must be flushed }
+var
+  max_insert : uInt;
+begin
+  hash_head := ZNIL;
+
+  { Process the input block. }
+  while TRUE do
+  begin
+    { Make sure that we always have enough lookahead, except
+      at the end of the input file. We need MAX_MATCH bytes
+      for the next match, plus MIN_MATCH bytes to insert the
+      string following the next match. }
+
+    if (s.lookahead < MIN_LOOKAHEAD) then
+    begin
+      fill_window(s);
+      if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then
+      begin
+        deflate_slow := need_more;
+        exit;
+      end;
+
+      if (s.lookahead = 0) then
+        break; { flush the current block }
+    end;
+
+    { Insert the string window[strstart .. strstart+2] in the
+      dictionary, and set hash_head to the head of the hash chain: }
+
+    if (s.lookahead >= MIN_MATCH) then
+    begin
+      INSERT_STRING(s, s.strstart, hash_head);
+    end;
+
+    { Find the longest match, discarding those <= prev_length. }
+
+    s.prev_length := s.match_length;
+    s.prev_match := s.match_start;
+    s.match_length := MIN_MATCH-1;
+
+    if (hash_head <> ZNIL) and (s.prev_length < s.max_lazy_match) and
+       (s.strstart - hash_head <= {MAX_DIST}(s.w_size-MIN_LOOKAHEAD)) then
+    begin
+        { To simplify the code, we prevent matches with the string
+          of window index 0 (in particular we have to avoid a match
+          of the string with itself at the start of the input file). }
+
+        if (s.strategy <> Z_HUFFMAN_ONLY) then
+        begin
+          s.match_length := longest_match (s, hash_head);
+        end;
+        { longest_match() sets match_start }
+
+        if (s.match_length <= 5) and ((s.strategy = Z_FILTERED) or
+             ((s.match_length = MIN_MATCH) and
+              (s.strstart - s.match_start > TOO_FAR))) then
+        begin
+            { If prev_match is also MIN_MATCH, match_start is garbage
+              but we will ignore the current match anyway. }
+
+            s.match_length := MIN_MATCH-1;
+        end;
+    end;
+    { If there was a match at the previous step and the current
+      match is not better, output the previous match: }
+
+    if (s.prev_length >= MIN_MATCH)
+      and (s.match_length <= s.prev_length) then
+    begin
+      max_insert := s.strstart + s.lookahead - MIN_MATCH;
+      { Do not insert strings in hash table beyond this. }
+      {$ifdef DEBUG}
+      check_match(s, s.strstart-1, s.prev_match, s.prev_length);
+      {$endif}
+
+      {_tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                  s->prev_length - MIN_MATCH, bflush);}
+      bflush := _tr_tally(s, s.strstart -1 - s.prev_match,
+                           s.prev_length - MIN_MATCH);
+
+      { Insert in hash table all strings up to the end of the match.
+        strstart-1 and strstart are already inserted. If there is not
+        enough lookahead, the last two strings are not inserted in
+        the hash table. }
+
+      Dec(s.lookahead, s.prev_length-1);
+      Dec(s.prev_length, 2);
+      repeat
+        Inc(s.strstart);
+        if (s.strstart <= max_insert) then
+        begin
+          INSERT_STRING(s, s.strstart, hash_head);
+        end;
+        Dec(s.prev_length);
+      until (s.prev_length = 0);
+      s.match_available := FALSE;
+      s.match_length := MIN_MATCH-1;
+      Inc(s.strstart);
+
+      if (bflush) then  {FLUSH_BLOCK(s, FALSE);}
+      begin
+        FLUSH_BLOCK_ONLY(s, FALSE);
+        if (s.strm^.avail_out = 0) then
+        begin
+          deflate_slow := need_more;
+          exit;
+        end;
+      end;
+    end
+    else
+      if (s.match_available) then
+      begin
+        { If there was no match at the previous position, output a
+          single literal. If there was a match but the current match
+          is longer, truncate the previous match to a single literal. }
+        {$IFDEF DEBUG}
+        Tracevv(AnsiChar(s.window^[s.strstart-1]));
+        {$ENDIF}
+        bflush := _tr_tally (s, 0, s.window^[s.strstart-1]);
+
+        if bflush then
+        begin
+          FLUSH_BLOCK_ONLY(s, FALSE);
+        end;
+        Inc(s.strstart);
+        Dec(s.lookahead);
+        if (s.strm^.avail_out = 0) then
+        begin
+          deflate_slow := need_more;
+          exit;
+        end;
+      end
+      else
+      begin
+        { There is no previous match to compare with, wait for
+          the next step to decide. }
+
+        s.match_available := TRUE;
+        Inc(s.strstart);
+        Dec(s.lookahead);
+      end;
+  end;
+
+  {$IFDEF DEBUG}
+  Assert (flush <> Z_NO_FLUSH, 'no flush?');
+  {$ENDIF}
+  if (s.match_available) then
+  begin
+    {$IFDEF DEBUG}
+    Tracevv(AnsiChar(s.window^[s.strstart-1]));
+    bflush :=
+    {$ENDIF}
+      _tr_tally (s, 0, s.window^[s.strstart-1]);
+    s.match_available := FALSE;
+  end;
+  {FLUSH_BLOCK(s, flush = Z_FINISH);}
+  FLUSH_BLOCK_ONLY(s, flush = Z_FINISH);
+  if (s.strm^.avail_out = 0) then
+  begin
+    if flush = Z_FINISH then
+      deflate_slow := finish_started
+    else
+      deflate_slow := need_more;
+    exit;
+  end;
+  if flush = Z_FINISH then
+    deflate_slow := finish_done
+  else
+    deflate_slow := block_done;
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/imzinflate.pas b/src/lib/vampimg/ZLib/imzinflate.pas
new file mode 100644 (file)
index 0000000..6376510
--- /dev/null
@@ -0,0 +1,750 @@
+Unit  imzinflate;
+
+{  inflate.c -- zlib interface to inflate modules
+   Copyright (C) 1995-1998 Mark Adler
+
+  Pascal tranlastion
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I imzconf.inc}
+
+uses
+  imzutil, impaszlib, iminfblock, iminfutil;
+
+function inflateInit(var z : z_stream) : int;
+
+{    Initializes the internal stream state for decompression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
+   allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
+   with the version assumed by the caller.  msg is set to null if there is no
+   error message. inflateInit does not perform any decompression: this will be
+   done by inflate(). }
+
+
+
+function inflateInit_(z : z_streamp;
+                      const version : AnsiString;
+                      stream_size : int) : int;
+
+
+function inflateInit2_(var z: z_stream;
+                       w : int;
+                       const version : AnsiString;
+                       stream_size : int) : int;
+
+function inflateInit2(var z: z_stream;
+                       windowBits : int) : int;
+
+{
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. If a compressed stream with a larger window size is given as
+   input, inflate() will return with the error code Z_DATA_ERROR instead of
+   trying to allocate a larger window.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+}
+
+
+
+function inflateEnd(var z : z_stream) : int;
+
+{
+   All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+}
+
+function inflateReset(var z : z_stream) : int;
+
+{
+   This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+}
+
+
+function inflate(var z : z_stream;
+                 f : int) : int;
+{
+  inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+}
+
+
+function inflateSetDictionary(var z : z_stream;
+                              dictionary : pBytef; {const array of byte}
+                              dictLength : uInt) : int;
+
+{
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+}
+
+function inflateSync(var z : z_stream) : int;
+
+{
+  Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+}
+
+
+function inflateSyncPoint(var z : z_stream) : int;
+
+
+implementation
+
+uses
+  imadler;
+
+function inflateReset(var z : z_stream) : int;
+begin
+  if (z.state = Z_NULL) then
+  begin
+    inflateReset :=  Z_STREAM_ERROR;
+    exit;
+  end;
+  z.total_out := 0;
+  z.total_in := 0;
+  z.msg := '';
+  if z.state^.nowrap then
+    z.state^.mode := BLOCKS
+  else
+    z.state^.mode := METHOD;
+  inflate_blocks_reset(z.state^.blocks^, z, Z_NULL);
+  {$IFDEF DEBUG}
+  Tracev('inflate: reset');
+  {$ENDIF}
+  inflateReset :=  Z_OK;
+end;
+
+
+function inflateEnd(var z : z_stream) : int;
+begin
+  if (z.state = Z_NULL) or not Assigned(z.zfree) then
+  begin
+    inflateEnd :=  Z_STREAM_ERROR;
+    exit;
+  end;
+  if (z.state^.blocks <> Z_NULL) then
+    inflate_blocks_free(z.state^.blocks, z);
+  ZFREE(z, z.state);
+  z.state := Z_NULL;
+  {$IFDEF DEBUG}
+  Tracev('inflate: end');
+  {$ENDIF}
+  inflateEnd :=  Z_OK;
+end;
+
+
+function inflateInit2_(var z: z_stream;
+                       w : int;
+                       const version : AnsiString;
+                       stream_size : int) : int;
+begin
+  if (version = '') or (version[1] <> ZLIB_VERSION[1]) or
+      (stream_size <> sizeof(z_stream)) then
+  begin
+    inflateInit2_ := Z_VERSION_ERROR;
+    exit;
+  end;
+  { initialize state }
+  { SetLength(strm.msg, 255); }
+  z.msg := '';
+  if not Assigned(z.zalloc) then
+  begin
+    {$IFDEF FPC}  z.zalloc := @zcalloc;  {$ELSE}
+    z.zalloc := zcalloc;
+    {$endif}
+    z.opaque := voidpf(0);
+  end;
+  if not Assigned(z.zfree) then
+    {$IFDEF FPC}  z.zfree := @zcfree;  {$ELSE}
+    z.zfree := zcfree;
+    {$ENDIF}
+
+  z.state := pInternal_state( ZALLOC(z,1,sizeof(internal_state)) );
+  if (z.state = Z_NULL) then
+  begin
+    inflateInit2_ := Z_MEM_ERROR;
+    exit;
+  end;
+
+  z.state^.blocks := Z_NULL;
+
+  { handle undocumented nowrap option (no zlib header or check) }
+  z.state^.nowrap := FALSE;
+  if (w < 0) then
+  begin
+    w := - w;
+    z.state^.nowrap := TRUE;
+  end;
+
+  { set window size }
+  if (w < 8) or (w > 15) then
+  begin
+    inflateEnd(z);
+    inflateInit2_ := Z_STREAM_ERROR;
+    exit;
+  end;
+  z.state^.wbits := uInt(w);
+
+  { create inflate_blocks state }
+  if z.state^.nowrap then
+    z.state^.blocks := inflate_blocks_new(z, NIL, uInt(1) shl w)
+  else
+  {$IFDEF FPC}
+    z.state^.blocks := inflate_blocks_new(z, @adler32, uInt(1) shl w);
+  {$ELSE}
+    z.state^.blocks := inflate_blocks_new(z, adler32, uInt(1) shl w);
+  {$ENDIF}
+  if (z.state^.blocks = Z_NULL) then
+  begin
+    inflateEnd(z);
+    inflateInit2_ := Z_MEM_ERROR;
+    exit;
+  end;
+  {$IFDEF DEBUG}
+  Tracev('inflate: allocated');
+  {$ENDIF}
+  { reset state }
+  inflateReset(z);
+  inflateInit2_ :=  Z_OK;
+end;
+
+function inflateInit2(var z: z_stream; windowBits : int) : int;
+begin
+  inflateInit2 := inflateInit2_(z, windowBits, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+
+function inflateInit(var z : z_stream) : int;
+{ inflateInit is a macro to allow checking the zlib version
+  and the compiler's view of z_stream:  }
+begin
+  inflateInit := inflateInit2_(z, DEF_WBITS, ZLIB_VERSION, sizeof(z_stream));
+end;
+
+function inflateInit_(z : z_streamp;
+                      const version : AnsiString;
+                      stream_size : int) : int;
+begin
+  { initialize state }
+  if (z = Z_NULL) then
+    inflateInit_ := Z_STREAM_ERROR
+  else
+    inflateInit_ := inflateInit2_(z^, DEF_WBITS, version, stream_size);
+end;
+
+function inflate(var z : z_stream;
+                 f : int) : int;
+var
+  r : int;
+  b : uInt;
+begin
+  if (z.state = Z_NULL) or (z.next_in = Z_NULL) then
+  begin
+    inflate := Z_STREAM_ERROR;
+    exit;
+  end;
+  if f = Z_FINISH then
+    f := Z_BUF_ERROR
+  else
+    f := Z_OK;
+  r := Z_BUF_ERROR;
+  while True do
+  case (z.state^.mode) of
+    BLOCKS:
+      begin
+        r := inflate_blocks(z.state^.blocks^, z, r);
+        if (r = Z_DATA_ERROR) then
+        begin
+          z.state^.mode := BAD;
+          z.state^.sub.marker := 0;       { can try inflateSync }
+          continue;            { break C-switch }
+        end;
+        if (r = Z_OK) then
+          r := f;
+        if (r <> Z_STREAM_END) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+        inflate_blocks_reset(z.state^.blocks^, z, @z.state^.sub.check.was);
+        if (z.state^.nowrap) then
+        begin
+          z.state^.mode := DONE;
+          continue;            { break C-switch }
+        end;
+        z.state^.mode := CHECK4;  { falltrough }
+      end;
+    CHECK4:
+      begin
+        {NEEDBYTE}
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+
+        {z.state^.sub.check.need := uLong(NEXTBYTE(z)) shl 24;}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        z.state^.sub.check.need := uLong(z.next_in^) shl 24;
+        Inc(z.next_in);
+
+        z.state^.mode := CHECK3;   { falltrough }
+      end;
+    CHECK3:
+      begin
+        {NEEDBYTE}
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+        {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 16);}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 16);
+        Inc(z.next_in);
+
+        z.state^.mode := CHECK2;   { falltrough }
+      end;
+    CHECK2:
+      begin
+        {NEEDBYTE}
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+
+        {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 8);}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 8);
+        Inc(z.next_in);
+
+        z.state^.mode := CHECK1;   { falltrough }
+      end;
+    CHECK1:
+      begin
+        {NEEDBYTE}
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+        {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) );}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        Inc(z.state^.sub.check.need, uLong(z.next_in^) );
+        Inc(z.next_in);
+
+
+        if (z.state^.sub.check.was <> z.state^.sub.check.need) then
+        begin
+          z.state^.mode := BAD;
+          z.msg := 'incorrect data check';
+          z.state^.sub.marker := 5;       { can't try inflateSync }
+          continue;           { break C-switch }
+        end;
+        {$IFDEF DEBUG}
+        Tracev('inflate: zlib check ok');
+        {$ENDIF}
+        z.state^.mode := DONE; { falltrough }
+      end;
+    DONE:
+      begin
+        inflate := Z_STREAM_END;
+        exit;
+      end;
+    METHOD:
+      begin
+        {NEEDBYTE}
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f; {}
+
+        {z.state^.sub.method := NEXTBYTE(z);}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        z.state^.sub.method := z.next_in^;
+        Inc(z.next_in);
+
+        if ((z.state^.sub.method and $0f) <> Z_DEFLATED) then
+        begin
+          z.state^.mode := BAD;
+          z.msg := 'unknown compression method';
+          z.state^.sub.marker := 5;       { can't try inflateSync }
+          continue;  { break C-switch }
+        end;
+        if ((z.state^.sub.method shr 4) + 8 > z.state^.wbits) then
+        begin
+          z.state^.mode := BAD;
+          z.msg := 'invalid window size';
+          z.state^.sub.marker := 5;       { can't try inflateSync }
+          continue; { break C-switch }
+        end;
+        z.state^.mode := FLAG;
+        { fall trough }
+      end;
+    FLAG:
+      begin
+        {NEEDBYTE}
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f; {}
+        {b := NEXTBYTE(z);}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        b := z.next_in^;
+        Inc(z.next_in);
+
+        if (((z.state^.sub.method shl 8) + b) mod 31) <> 0 then {% mod ?}
+        begin
+          z.state^.mode := BAD;
+          z.msg := 'incorrect header check';
+          z.state^.sub.marker := 5;       { can't try inflateSync }
+          continue;      { break C-switch }
+        end;
+        {$IFDEF DEBUG}
+        Tracev('inflate: zlib header ok');
+        {$ENDIF}
+        if ((b and PRESET_DICT) = 0) then
+        begin
+          z.state^.mode := BLOCKS;
+    continue;      { break C-switch }
+        end;
+        z.state^.mode := DICT4;
+        { falltrough }
+      end;
+    DICT4:
+      begin
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+
+        {z.state^.sub.check.need := uLong(NEXTBYTE(z)) shl 24;}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        z.state^.sub.check.need :=  uLong(z.next_in^) shl 24;
+        Inc(z.next_in);
+
+        z.state^.mode := DICT3;        { falltrough }
+      end;
+    DICT3:
+      begin
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+        {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 16);}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 16);
+        Inc(z.next_in);
+
+        z.state^.mode := DICT2;        { falltrough }
+      end;
+    DICT2:
+      begin
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        r := f;
+
+        {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 8);}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 8);
+        Inc(z.next_in);
+
+        z.state^.mode := DICT1;        { falltrough }
+      end;
+    DICT1:
+      begin
+        if (z.avail_in = 0) then
+        begin
+          inflate := r;
+          exit;
+        end;
+        { r := f;    ---  wird niemals benutzt }
+        {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) );}
+        Dec(z.avail_in);
+        Inc(z.total_in);
+        Inc(z.state^.sub.check.need, uLong(z.next_in^) );
+        Inc(z.next_in);
+
+        z.adler := z.state^.sub.check.need;
+        z.state^.mode := DICT0;
+        inflate := Z_NEED_DICT;
+        exit;
+      end;
+    DICT0:
+      begin
+        z.state^.mode := BAD;
+        z.msg := 'need dictionary';
+        z.state^.sub.marker := 0;         { can try inflateSync }
+        inflate := Z_STREAM_ERROR;
+        exit;
+      end;
+    BAD:
+      begin
+        inflate := Z_DATA_ERROR;
+        exit;
+      end;
+    else
+      begin
+        inflate := Z_STREAM_ERROR;
+        exit;
+      end;
+  end;
+{$ifdef NEED_DUMMY_result}
+  result := Z_STREAM_ERROR;  { Some dumb compilers complain without this }
+{$endif}
+end;
+
+function inflateSetDictionary(var z : z_stream;
+                              dictionary : pBytef; {const array of byte}
+                              dictLength : uInt) : int;
+var
+  length : uInt;
+begin
+  length := dictLength;
+
+  if (z.state = Z_NULL) or (z.state^.mode <> DICT0) then
+  begin
+    inflateSetDictionary := Z_STREAM_ERROR;
+    exit;
+  end;
+  if (adler32(Long(1), dictionary, dictLength) <> z.adler) then
+  begin
+    inflateSetDictionary := Z_DATA_ERROR;
+    exit;
+  end;
+  z.adler := Long(1);
+
+  if (length >= (uInt(1) shl z.state^.wbits)) then
+  begin
+    length := (1 shl z.state^.wbits)-1;
+    Inc( dictionary, dictLength - length);
+  end;
+  inflate_set_dictionary(z.state^.blocks^, dictionary^, length);
+  z.state^.mode := BLOCKS;
+  inflateSetDictionary := Z_OK;
+end;
+
+
+function inflateSync(var z : z_stream) : int;
+const
+  mark : packed array[0..3] of byte = (0, 0, $ff, $ff);
+var
+  n : uInt;       { number of bytes to look at }
+  p : pBytef;     { pointer to bytes }
+  m : uInt;       { number of marker bytes found in a row }
+  r, w : uLong;   { temporaries to save total_in and total_out }
+begin
+  { set up }
+  if (z.state = Z_NULL) then
+  begin
+    inflateSync := Z_STREAM_ERROR;
+    exit;
+  end;
+  if (z.state^.mode <> BAD) then
+  begin
+    z.state^.mode := BAD;
+    z.state^.sub.marker := 0;
+  end;
+  n := z.avail_in;
+  if (n = 0) then
+  begin
+    inflateSync := Z_BUF_ERROR;
+    exit;
+  end;
+  p := z.next_in;
+  m := z.state^.sub.marker;
+
+  { search }
+  while (n <> 0) and (m < 4) do
+  begin
+    if (p^ = mark[m]) then
+      Inc(m)
+    else
+      if (p^ <> 0) then
+        m := 0
+      else
+        m := 4 - m;
+    Inc(p);
+    Dec(n);
+  end;
+
+  { restore }
+  Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in));
+  z.next_in := p;
+  z.avail_in := n;
+  z.state^.sub.marker := m;
+
+
+  { return no joy or set up to restart on a new block }
+  if (m <> 4) then
+  begin
+    inflateSync := Z_DATA_ERROR;
+    exit;
+  end;
+  r := z.total_in;
+  w := z.total_out;
+  inflateReset(z);
+  z.total_in := r;
+  z.total_out := w;
+  z.state^.mode := BLOCKS;
+  inflateSync := Z_OK;
+end;
+
+
+{
+  returns true if inflate is currently at the end of a block generated
+  by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+  implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+  but removes the length bytes of the resulting empty stored block. When
+  decompressing, PPP checks that at the end of input packet, inflate is
+  waiting for these length bytes.
+}
+
+function inflateSyncPoint(var z : z_stream) : int;
+begin
+  if (z.state = Z_NULL) or (z.state^.blocks = Z_NULL) then
+  begin
+    inflateSyncPoint := Z_STREAM_ERROR;
+    exit;
+  end;
+  inflateSyncPoint := inflate_blocks_sync_point(z.state^.blocks^);
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/imzutil.pas b/src/lib/vampimg/ZLib/imzutil.pas
new file mode 100644 (file)
index 0000000..701b5a2
--- /dev/null
@@ -0,0 +1,190 @@
+Unit imzutil;
+
+{
+  Copyright (C) 1998 by Jacques Nomssi Nzali
+  For conditions of distribution and use, see copyright notice in readme.txt
+}
+
+interface
+
+{$I imzconf.inc}
+
+{ Type declarations }
+
+type
+  {Byte   = usigned char;  8 bits}
+  Bytef  = byte;
+  charf  = byte;
+
+  int    = longint;
+  intf   = int;
+  uInt   = cardinal;     { 16 bits or more }
+  uIntf  = uInt;
+
+  Long   = longint;
+  uLong  = Cardinal;
+  uLongf = uLong;
+
+  voidp  = pointer;
+  voidpf = voidp;
+  pBytef = ^Bytef;
+  pIntf  = ^intf;
+  puIntf = ^uIntf;
+  puLong = ^uLongf;
+
+  ptr2int = uInt;
+{ a pointer to integer casting is used to do pointer arithmetic.
+  ptr2int must be an integer type and sizeof(ptr2int) must be less
+  than sizeof(pointer) - Nomssi }
+
+type
+  zByteArray = array[0..(MaxInt div SizeOf(Bytef))-1] of Bytef;
+  pzByteArray = ^zByteArray;
+type
+  zIntfArray = array[0..(MaxInt div SizeOf(Intf))-1] of Intf;
+  pzIntfArray = ^zIntfArray;
+type
+  zuIntArray = array[0..(MaxInt div SizeOf(uInt))-1] of uInt;
+  PuIntArray = ^zuIntArray;
+
+{ Type declarations - only for deflate }
+
+type
+  uch  = Byte;
+  uchf = uch; { FAR }
+  ush  = Word;
+  ushf = ush;
+  ulg  = LongInt;
+
+  unsigned = uInt;
+
+  pcharf = ^charf;
+  puchf = ^uchf;
+  pushf = ^ushf;
+
+type
+  zuchfArray = zByteArray;
+  puchfArray = ^zuchfArray;
+type
+  zushfArray = array[0..(MaxInt div SizeOf(ushf))-1] of ushf;
+  pushfArray = ^zushfArray;
+
+procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt);
+function zmemcmp(s1p, s2p : pBytef; len : uInt) : int;
+procedure zmemzero(destp : pBytef; len : uInt);
+procedure zcfree(opaque : voidpf; ptr : voidpf);
+function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf;
+
+implementation
+
+procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt);
+begin
+  Move(sourcep^, destp^, len);
+end;
+
+function zmemcmp(s1p, s2p : pBytef; len : uInt) : int;
+var
+  j : uInt;
+  source,
+  dest : pBytef;
+begin
+  source := s1p;
+  dest := s2p;
+  for j := 0 to pred(len) do
+  begin
+    if (source^ <> dest^) then
+    begin
+      zmemcmp := 2*Ord(source^ > dest^)-1;
+      exit;
+    end;
+    Inc(source);
+    Inc(dest);
+  end;
+  zmemcmp := 0;
+end;
+
+procedure zmemzero(destp : pBytef; len : uInt);
+begin
+  FillChar(destp^, len, 0);
+end;
+
+procedure zcfree(opaque : voidpf; ptr : voidpf);
+{$ifdef Delphi16}
+var
+  Handle : THandle;
+{$endif}
+{$IFDEF FPC}
+var
+  memsize : uint;
+{$ENDIF}
+begin
+  (*
+  {$IFDEF DPMI}
+  {h :=} GlobalFreePtr(ptr);
+  {$ELSE}
+    {$IFDEF CALL_DOS}
+    dosFree(ptr);
+    {$ELSE}
+      {$ifdef HugeMem}
+      FreeMemHuge(ptr);
+      {$else}
+        {$ifdef Delphi16}
+        Handle := GlobalHandle(LH(ptr).H); { HiWord(LongInt(ptr)) }
+        GlobalUnLock(Handle);
+        GlobalFree(Handle);
+        {$else}
+          {$IFDEF FPC}
+          Dec(puIntf(ptr));
+          memsize := puIntf(ptr)^;
+          FreeMem(ptr, memsize+SizeOf(uInt));
+          {$ELSE}
+          FreeMem(ptr);  { Delphi 2,3,4 }
+          {$ENDIF}
+        {$endif}
+      {$endif}
+    {$ENDIF}
+  {$ENDIF}
+  *)
+  FreeMem(ptr);
+end;
+
+function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf;
+var
+  p : voidpf;
+  memsize : uLong;
+{$ifdef Delphi16}
+  handle : THandle;
+{$endif}
+begin
+  memsize := uLong(items) * size;
+  (*
+  { $IFDEF DPMI}
+  p := GlobalAllocPtr(gmem_moveable, memsize);
+  { $ELSE}
+    { $IFDEF CALLDOS}
+    p := dosAlloc(memsize);
+    { $ELSE}
+      {$ifdef HugeMem}
+      GetMemHuge(p, memsize);
+      { $else}
+        { $ifdef Delphi16}
+        Handle := GlobalAlloc(HeapAllocFlags, memsize);
+        p := GlobalLock(Handle);
+        { $else}
+          { $IFDEF FPC}
+          GetMem(p, memsize+SizeOf(uInt));
+          puIntf(p)^:= memsize;
+          Inc(puIntf(p));
+          { $ELSE}
+          GetMem(p, memsize);  { Delphi: p := AllocMem(memsize); }
+          { $ENDIF}
+        { $endif}
+      { $endif}
+    { $ENDIF}
+  { $ENDIF}
+  *)
+  GetMem(p, memsize);
+  zcalloc := p;
+end;
+
+end.
diff --git a/src/lib/vampimg/ZLib/readme.txt b/src/lib/vampimg/ZLib/readme.txt
new file mode 100644 (file)
index 0000000..ffd4f89
--- /dev/null
@@ -0,0 +1,129 @@
+_____________________________________________________________________________
+
+PASZLIB 1.0                                                   May 11th, 1998
+
+Based on the zlib 1.1.2, a general purpose data compression library.
+
+Copyright (C) 1998,1999,2000 by NOMSSI NZALI Jacques H. C.
+[kn&n DES]         See "Legal issues" for conditions of distribution and use.
+_____________________________________________________________________________
+
+
+Introduction
+============
+
+The 'zlib' compression library provides in-memory compression and
+decompression functions, including integrity checks of the uncompressed
+data.  This version of the library supports only one compression method
+(deflation) but other algorithms will be added later and will have the same
+stream interface.
+
+Compression can be done in a single step if the buffers are large
+enough (for example if an input file is mmap'ed), or can be done by
+repeated calls of the compression function.  In the latter case, the
+application must provide more input and/or consume the output
+(providing more output space) before each call.
+
+The default memory requirements for deflate are 256K plus a few kilobytes
+for small objects. The default memory requirements for inflate are 32K
+plus a few kilobytes for small objects.
+
+Change Log
+==========
+
+March 24th 2000 - minizip code by Gilles Vollant ported to Pascal.
+                  z_stream.msg defined as string[255] to avoid problems
+                  with Delphi 2+ dynamic string handling.
+                  changes to silence Delphi 5 compiler warning. If you
+                  have Delphi 5, defines Delphi5 in zconf.inc
+
+May 7th 1999    - Some changes for FPC
+                  deflateCopy() has new parameters
+                  trees.pas - record constant definition
+June 17th 1998  - Applied official 1.1.2 patch.
+            Memcheck turned off by default.
+                  zutil.pas patch for Delphi 1 memory allocation corrected.
+                  dzlib.txt file added.
+                  compress2() is now exported
+
+June 25th 1998 -  fixed a conversion bug: in inftrees.pas, ZFREE(z, v) was
+                  missing in line 574;
+
+File list
+=========
+
+Here is a road map to the files in the Paszlib distribution.
+
+readme.txt      Introduction, Documentation
+dzlib.txt       Changes to Delphi sources for Paszlib stream classes
+
+include file
+
+zconf.inc       Configuration declarations.
+
+Pascal source code files:
+
+adler.pas      compute the Adler-32 checksum of a data stream
+crc.pas        compute the CRC-32 of a data stream
+gzio.pas       IO on .gz files
+infblock.pas   interpret and process block types to last block
+infcodes.pas   process literals and length/distance pairs
+inffast.pas    process literals and length/distance pairs fast
+inftrees.pas   generate Huffman trees for efficient decoding
+infutil.pas    types and macros common to blocks and codes
+strutils.pas   string utilities
+trees.pas      output deflated data using Huffman coding
+zcompres.pas   compress a memory buffer
+zdeflate.pas   compress data using the deflation algorithm
+zinflate.pas   zlib interface to inflate modules
+zlib.pas       zlib data structures. read the comments there!
+zuncompr.pas   decompress a memory buffer
+zutil.pas
+
+minizip/ziputils.pas data structure and IO on .zip file
+minizip/unzip.pas
+minizip/zip.pas
+
+Test applications
+
+example.pas    usage example of the zlib compression library
+minigzip.pas   simulate gzip using the zlib compression library
+minizip/miniunz.pas  simulates unzip using the zlib compression library
+minizip/minizip.pas  simulates zip using the zlib compression library
+
+Legal issues
+============
+
+Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the author be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+
+Archive Locations:
+==================
+
+Check the Paszlib home page with links
+
+      http://www.tu-chemnitz.de/~nomssi/paszlib.html
+
+The data format used by the zlib library is described by RFCs (Request for
+Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+(zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+These documents are also available in other formats from
+ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html.
+____________________________________________________________________________
+Jacques Nomssi Nzali <mailto:nomssi@physik.tu-chemnitz.de> March 24th, 2000
index b533664d29bb1c60e3ccf11da9131f8a97a123ea..3c6c1a3082fc80c9290ace750a56bc3921b963a0 100644 (file)
@@ -1,12 +1,10 @@
 unit WADEDITOR;
 
-{$MODE Delphi}
-
 {
 -----------------------------------
-WADEDITOR.PAS ВЕРСИЯ ОТ 26.08.08
+WADEDITOR.PAS ÂÅÐÑÈß ÎÒ 26.08.08
 
-Поддержка вадов версии 1
+Ïîääåðæêà âàäîâ âåðñèè 1
 -----------------------------------
 }
 
index 9e2fd06ca524b20f75a1c95c5d6ec1e58f2ea85f..d7d7b06e484aafb55a1884e9a33797b806819899 100644 (file)
@@ -1,15 +1,13 @@
 unit WADSTRUCT;
 
-{$MODE Delphi}
-
 {
 -----------------------------------
-WADSTRUCT.PAS ВЕРСИЯ ОТ 24.09.06
+WADSTRUCT.PAS ÂÅÐÑÈß ÎÒ 24.09.06
 
-Поддержка вадов версии 1
+Ïîääåðæêà âàäîâ âåðñèè 1
 -----------------------------------
 
-Структура DFWAD-файла версии 1:
+Ñòðóêòóðà DFWAD-ôàéëà âåðñèè 1:
  ------------------------------------------
  SIGNATURE  | Byte[5]             | 'DFWAD'
  VERSION    | Byte                | $01
diff --git a/src/shared/mapstructio.inc b/src/shared/mapstructio.inc
new file mode 100644 (file)
index 0000000..ae432b9
--- /dev/null
@@ -0,0 +1,685 @@
+procedure getBytesAt (var dest; const buf; ofs, len: Integer);
+begin
+  Move((PChar(@buf)+ofs)^, dest, len);
+end;
+
+procedure getWordAt (var dest; const buf; ofs: Integer);
+type PWord = ^Word; PByte = ^Byte;
+var
+  p: PByte;
+  d: PWord;
+begin
+  p := PByte(@buf); Inc(p, ofs);
+  d := PWord(@dest);
+  d^ := p^;
+  Inc(p);
+  d^ := (d^) or ((p^) shl 8);
+end;
+
+procedure getIntAt (var dest; const buf; ofs: Integer);
+type PInt = ^LongWord; PByte = ^Byte;
+var
+  p: PByte;
+  d: PInt;
+begin
+  p := PByte(@buf); Inc(p, ofs);
+  d := PInt(@dest);
+  d^ := p^;
+  Inc(p);
+  d^ := (d^) or ((p^) shl 8);
+  Inc(p);
+  d^ := (d^) or ((p^) shl 16);
+  Inc(p);
+  d^ := (d^) or ((p^) shl 24);
+end;
+
+procedure putBytesAt (var buf; ofs: Integer; const src; len: Integer);
+begin
+  Move(src, (PChar(@buf)+ofs)^, len);
+end;
+
+procedure putWordAt (var buf; ofs: Integer; const src);
+type PWord = ^Word; PByte = ^Byte;
+var
+  p: PByte;
+  d: PWord;
+begin
+  p := PByte(PChar(@buf)+ofs);
+  d := PWord(@src);
+  p^ := (d^) and $ff;
+  Inc(p);
+  p^ := ((d^) shr 8) and $ff;
+end;
+
+procedure putIntAt (var buf; ofs: Integer; const src);
+type PInt = ^LongWord; PByte = ^Byte;
+var
+  p: PByte;
+  d: PInt;
+begin
+  p := PByte(PChar(@buf)+ofs);
+  d := PInt(@src);
+  p^ := (d^) and $ff;
+  Inc(p);
+  p^ := ((d^) shr 8) and $ff;
+  Inc(p);
+  p^ := ((d^) shr 16) and $ff;
+  Inc(p);
+  p^ := ((d^) shr 24) and $ff;
+end;
+
+procedure mb_Read_TriggerData (var tr: TTriggerData; ttype: Integer; const buf; bufsize: Integer);
+  procedure xreadExit ();
+  begin
+    getBytesAt(tr.MapName, buf, 0, 16);
+  end;
+
+  procedure xreadTeleport ();
+  begin
+    getIntAt(tr.TargetPoint.x, buf, 0);
+    getIntAt(tr.TargetPoint.y, buf, 4);
+    getBytesAt(tr.d2d_teleport, buf, 8, 1);
+    getBytesAt(tr.silent_teleport, buf, 9, 1);
+    getBytesAt(tr.TlpDir, buf, 10, 1);
+  end;
+
+  procedure xreadOpendoor ();
+  begin
+    getIntAt(tr.PanelID, buf, 0);
+    getBytesAt(tr.NoSound, buf, 4, 1);
+    getBytesAt(tr.d2d_doors, buf, 5, 1);
+  end;
+
+  procedure xreadPress ();
+  begin
+    getIntAt(tr.tX, buf, 0);
+    getIntAt(tr.tY, buf, 4);
+    getWordAt(tr.tWidth, buf, 8);
+    getWordAt(tr.tHeight, buf, 10);
+    getWordAt(tr.Wait, buf, 12);
+    getWordAt(tr.Count, buf, 14);
+    getIntAt(tr.MonsterID, buf, 16);
+    getBytesAt(tr.ExtRandom, buf, 20, 1);
+  end;
+
+  procedure xreadSecret ();
+  begin
+  end;
+
+  procedure xreadTexture ();
+  begin
+    getBytesAt(tr.ActivateOnce, buf, 0, 1);
+    getBytesAt(tr.AnimOnce, buf, 1, 1);
+  end;
+
+  procedure xreadSound ();
+  begin
+    getBytesAt(tr.SoundName, buf, 0, 64);
+    getBytesAt(tr.Volume, buf, 64, 1);
+    getBytesAt(tr.Pan, buf, 65, 1);
+    getBytesAt(tr.Local, buf, 66, 1);
+    getBytesAt(tr.PlayCount, buf, 67, 1);
+    getBytesAt(tr.SoundSwitch, buf, 68, 1);
+  end;
+
+  procedure xreadSpawnmonster ();
+  begin
+    getIntAt(tr.MonPos.x, buf, 0);
+    getIntAt(tr.MonPos.y, buf, 4);
+    getBytesAt(tr.MonType, buf, 8, 1);
+    getIntAt(tr.MonHealth, buf, 12);
+    getBytesAt(tr.MonDir, buf, 16, 1);
+    getBytesAt(tr.MonActive, buf, 17, 1);
+    getIntAt(tr.MonCount, buf, 20);
+    getBytesAt(tr.MonEffect, buf, 24, 1);
+    getWordAt(tr.MonMax, buf, 26);
+    getWordAt(tr.MonDelay, buf, 28);
+    getBytesAt(tr.MonBehav, buf, 30, 1);
+  end;
+
+  procedure xreadSpawnitem ();
+  begin
+    getIntAt(tr.ItemPos.x, buf, 0);
+    getIntAt(tr.ItemPos.y, buf, 4);
+    getBytesAt(tr.ItemType, buf, 8, 1);
+    getBytesAt(tr.ItemFalls, buf, 9, 1);
+    getBytesAt(tr.ItemOnlyDM, buf, 10, 1);
+    getIntAt(tr.ItemCount, buf, 12);
+    getBytesAt(tr.ItemEffect, buf, 16, 1);
+    getWordAt(tr.ItemMax, buf, 18);
+    getWordAt(tr.ItemDelay, buf, 20);
+  end;
+
+  procedure xreadMusic ();
+  begin
+    getBytesAt(tr.MusicName, buf, 0, 64);
+    getBytesAt(tr.MusicAction, buf, 64, 1);
+  end;
+
+  procedure xreadPush ();
+  begin
+    getWordAt(tr.PushAngle, buf, 0);
+    getBytesAt(tr.PushForce, buf, 2, 1);
+    getBytesAt(tr.ResetVel, buf, 3, 1);
+  end;
+
+  procedure xreadScore ();
+  begin
+    getBytesAt(tr.ScoreAction, buf, 0, 1);
+    getBytesAt(tr.ScoreCount, buf, 1, 1);
+    getBytesAt(tr.ScoreTeam, buf, 2, 1);
+    getBytesAt(tr.ScoreCon, buf, 3, 1);
+    getBytesAt(tr.ScoreMsg, buf, 4, 1);
+  end;
+
+  procedure xreadMessage ();
+  begin
+    getBytesAt(tr.MessageKind, buf, 0, 1);
+    getBytesAt(tr.MessageSendTo, buf, 1, 1);
+    getBytesAt(tr.MessageText, buf, 2, 100);
+    getWordAt(tr.MessageTime, buf, 102);
+  end;
+
+  procedure xreadDamage ();
+  begin
+    getWordAt(tr.DamageValue, buf, 0);
+    getWordAt(tr.DamageInterval, buf, 2);
+  end;
+
+  procedure xreadHealth ();
+  begin
+    getWordAt(tr.HealValue, buf, 0);
+    getWordAt(tr.HealInterval, buf, 2);
+    getBytesAt(tr.HealMax, buf, 4, 1);
+    getBytesAt(tr.HealSilent, buf, 5, 1);
+  end;
+
+  procedure xreadShot ();
+  begin
+    getIntAt(tr.ShotPos.x, buf, 0);
+    getIntAt(tr.ShotPos.y, buf, 4);
+    getBytesAt(tr.ShotType, buf, 8, 1);
+    getBytesAt(tr.ShotTarget, buf, 9, 1);
+    getBytesAt(tr.ShotSound, buf, 10, 1);
+    getBytesAt(tr.ShotAllMap, buf, 11, 1);
+    getIntAt(tr.ShotPanelID, buf, 12);
+    getWordAt(tr.ShotIntSight, buf, 16);
+    getWordAt(tr.ShotAngle, buf, 18);
+    getWordAt(tr.ShotWait, buf, 20);
+    getWordAt(tr.ShotAccuracy, buf, 22);
+    getWordAt(tr.ShotAmmo, buf, 24);
+    getWordAt(tr.ShotIntReload, buf, 26);
+  end;
+
+  procedure xreadEffect ();
+  begin
+    getBytesAt(tr.FXCount, buf, 0, 1);
+    getBytesAt(tr.FXType, buf, 1, 1);
+    getBytesAt(tr.FXSubType, buf, 2, 1);
+    getBytesAt(tr.FXColorR, buf, 3, 1);
+    getBytesAt(tr.FXColorG, buf, 4, 1);
+    getBytesAt(tr.FXColorB, buf, 5, 1);
+    getBytesAt(tr.FXPos, buf, 6, 1);
+    getWordAt(tr.FXWait, buf, 8);
+    getBytesAt(tr.FXVelX, buf, 10, 1);
+    getBytesAt(tr.FXVelY, buf, 11, 1);
+    getBytesAt(tr.FXSpreadL, buf, 12, 1);
+    getBytesAt(tr.FXSpreadR, buf, 13, 1);
+    getBytesAt(tr.FXSpreadU, buf, 14, 1);
+    getBytesAt(tr.FXSpreadD, buf, 15, 1);
+  end;
+
+  procedure xreadScript ();
+  begin
+    getBytesAt(tr.SCRProc, buf, 0, 64);
+    getIntAt(tr.SCRArg, buf, 64);
+  end;
+
+begin
+  if (bufsize < 104) then raise Exception.Create('invalid buffer size in mb_Read_TriggerData');
+  if (ttype = TRIGGER_EXIT) then begin xreadExit(); exit; end;
+  if (ttype = TRIGGER_TELEPORT) then begin xreadTeleport(); exit; end;
+  if (ttype = TRIGGER_OPENDOOR) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_CLOSEDOOR) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_DOOR) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_DOOR5) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_CLOSETRAP) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_TRAP) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_LIFTUP) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_LIFTDOWN) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_LIFT) then begin xreadOpendoor(); exit; end;
+  if (ttype = TRIGGER_PRESS) then begin xreadPress(); exit; end;
+  if (ttype = TRIGGER_ON) then begin xreadPress(); exit; end;
+  if (ttype = TRIGGER_OFF) then begin xreadPress(); exit; end;
+  if (ttype = TRIGGER_ONOFF) then begin xreadPress(); exit; end;
+  if (ttype = TRIGGER_SECRET) then begin xreadSecret(); exit; end;
+  if (ttype = TRIGGER_TEXTURE) then begin xreadTexture(); exit; end;
+  if (ttype = TRIGGER_SOUND) then begin xreadSound(); exit; end;
+  if (ttype = TRIGGER_SPAWNMONSTER) then begin xreadSpawnmonster(); exit; end;
+  if (ttype = TRIGGER_SPAWNITEM) then begin xreadSpawnitem(); exit; end;
+  if (ttype = TRIGGER_MUSIC) then begin xreadMusic(); exit; end;
+  if (ttype = TRIGGER_PUSH) then begin xreadPush(); exit; end;
+  if (ttype = TRIGGER_SCORE) then begin xreadScore(); exit; end;
+  if (ttype = TRIGGER_MESSAGE) then begin xreadMessage(); exit; end;
+  if (ttype = TRIGGER_DAMAGE) then begin xreadDamage(); exit; end;
+  if (ttype = TRIGGER_HEALTH) then begin xreadHealth(); exit; end;
+  if (ttype = TRIGGER_SHOT) then begin xreadShot(); exit; end;
+  if (ttype = TRIGGER_EFFECT) then begin xreadEffect(); exit; end;
+  if (ttype = TRIGGER_SCRIPT) then begin xreadScript(); exit; end;
+  raise Exception.Create('invalid trigger type in mb_Read_TriggerData');
+end;
+
+
+procedure mb_Read_TMapHeaderRec_1 (var tr: TMapHeaderRec_1; const buf; bufsize: Integer);
+  procedure xreadTmapheaderrec_1 ();
+  begin
+    getBytesAt(tr.MapName, buf, 0, 32);
+    getBytesAt(tr.MapAuthor, buf, 32, 32);
+    getBytesAt(tr.MapDescription, buf, 64, 256);
+    getBytesAt(tr.MusicName, buf, 320, 64);
+    getBytesAt(tr.SkyName, buf, 384, 64);
+    getWordAt(tr.Width, buf, 448);
+    getWordAt(tr.Height, buf, 450);
+  end;
+
+begin
+  if (bufsize < 452) then raise Exception.Create('invalid buffer size in readTMapHeaderRec_1');
+  xreadTmapheaderrec_1();
+end;
+
+procedure mb_Read_TTextureRec_1 (var tr: TTextureRec_1; const buf; bufsize: Integer);
+  procedure xreadTtexturerec_1 ();
+  begin
+    getBytesAt(tr.Resource, buf, 0, 64);
+    getBytesAt(tr.Anim, buf, 64, 1);
+  end;
+
+begin
+  if (bufsize < 65) then raise Exception.Create('invalid buffer size in readTTextureRec_1');
+  xreadTtexturerec_1();
+end;
+
+procedure mb_Read_TPanelRec_1 (var tr: TPanelRec_1; const buf; bufsize: Integer);
+  procedure xreadTpanelrec_1 ();
+  begin
+    getIntAt(tr.X, buf, 0);
+    getIntAt(tr.Y, buf, 4);
+    getWordAt(tr.Width, buf, 8);
+    getWordAt(tr.Height, buf, 10);
+    getWordAt(tr.TextureNum, buf, 12);
+    getWordAt(tr.PanelType, buf, 14);
+    getBytesAt(tr.Alpha, buf, 16, 1);
+    getBytesAt(tr.Flags, buf, 17, 1);
+  end;
+
+begin
+  if (bufsize < 18) then raise Exception.Create('invalid buffer size in readTPanelRec_1');
+  xreadTpanelrec_1();
+end;
+
+procedure mb_Read_TItemRec_1 (var tr: TItemRec_1; const buf; bufsize: Integer);
+  procedure xreadTitemrec_1 ();
+  begin
+    getIntAt(tr.X, buf, 0);
+    getIntAt(tr.Y, buf, 4);
+    getBytesAt(tr.ItemType, buf, 8, 1);
+    getBytesAt(tr.Options, buf, 9, 1);
+  end;
+
+begin
+  if (bufsize < 10) then raise Exception.Create('invalid buffer size in readTItemRec_1');
+  xreadTitemrec_1();
+end;
+
+procedure mb_Read_TMonsterRec_1 (var tr: TMonsterRec_1; const buf; bufsize: Integer);
+  procedure xreadTmonsterrec_1 ();
+  begin
+    getIntAt(tr.X, buf, 0);
+    getIntAt(tr.Y, buf, 4);
+    getBytesAt(tr.MonsterType, buf, 8, 1);
+    getBytesAt(tr.Direction, buf, 9, 1);
+  end;
+
+begin
+  if (bufsize < 10) then raise Exception.Create('invalid buffer size in readTMonsterRec_1');
+  xreadTmonsterrec_1();
+end;
+
+procedure mb_Read_TAreaRec_1 (var tr: TAreaRec_1; const buf; bufsize: Integer);
+  procedure xreadTarearec_1 ();
+  begin
+    getIntAt(tr.X, buf, 0);
+    getIntAt(tr.Y, buf, 4);
+    getBytesAt(tr.AreaType, buf, 8, 1);
+    getBytesAt(tr.Direction, buf, 9, 1);
+  end;
+
+begin
+  if (bufsize < 10) then raise Exception.Create('invalid buffer size in readTAreaRec_1');
+  xreadTarearec_1();
+end;
+
+procedure mb_Read_TTriggerRec_1 (var tr: TTriggerRec_1; const buf; bufsize: Integer);
+  procedure xreadTtriggerrec_1 ();
+  begin
+    getIntAt(tr.X, buf, 0);
+    getIntAt(tr.Y, buf, 4);
+    getWordAt(tr.Width, buf, 8);
+    getWordAt(tr.Height, buf, 10);
+    getBytesAt(tr.Enabled, buf, 12, 1);
+    getIntAt(tr.TexturePanel, buf, 13);
+    getBytesAt(tr.TriggerType, buf, 17, 1);
+    getBytesAt(tr.ActivateType, buf, 18, 1);
+    getBytesAt(tr.Keys, buf, 19, 1);
+    getBytesAt(tr.DATA, buf, 20, 128);
+  end;
+
+begin
+  if (bufsize < 148) then raise Exception.Create('invalid buffer size in readTTriggerRec_1');
+  xreadTtriggerrec_1();
+end;
+
+procedure mb_Write_TriggerData (var buf; bufsize: Integer; ttype: Integer; var tr: TTriggerData);
+  procedure xwriteExit ();
+  begin
+    putBytesAt(buf, 0, tr.MapName, 16);
+  end;
+
+  procedure xwriteTeleport ();
+  begin
+    putIntAt(buf, 0, tr.TargetPoint.x);
+    putIntAt(buf, 4, tr.TargetPoint.y);
+    putBytesAt(buf, 8, tr.d2d_teleport, 1);
+    putBytesAt(buf, 9, tr.silent_teleport, 1);
+    putBytesAt(buf, 10, tr.TlpDir, 1);
+  end;
+
+  procedure xwriteOpendoor ();
+  begin
+    putIntAt(buf, 0, tr.PanelID);
+    putBytesAt(buf, 4, tr.NoSound, 1);
+    putBytesAt(buf, 5, tr.d2d_doors, 1);
+  end;
+
+  procedure xwritePress ();
+  begin
+    putIntAt(buf, 0, tr.tX);
+    putIntAt(buf, 4, tr.tY);
+    putWordAt(buf, 8, tr.tWidth);
+    putWordAt(buf, 10, tr.tHeight);
+    putWordAt(buf, 12, tr.Wait);
+    putWordAt(buf, 14, tr.Count);
+    putIntAt(buf, 16, tr.MonsterID);
+    putBytesAt(buf, 20, tr.ExtRandom, 1);
+  end;
+
+  procedure xwriteSecret ();
+  begin
+  end;
+
+  procedure xwriteTexture ();
+  begin
+    putBytesAt(buf, 0, tr.ActivateOnce, 1);
+    putBytesAt(buf, 1, tr.AnimOnce, 1);
+  end;
+
+  procedure xwriteSound ();
+  begin
+    putBytesAt(buf, 0, tr.SoundName, 64);
+    putBytesAt(buf, 64, tr.Volume, 1);
+    putBytesAt(buf, 65, tr.Pan, 1);
+    putBytesAt(buf, 66, tr.Local, 1);
+    putBytesAt(buf, 67, tr.PlayCount, 1);
+    putBytesAt(buf, 68, tr.SoundSwitch, 1);
+  end;
+
+  procedure xwriteSpawnmonster ();
+  begin
+    putIntAt(buf, 0, tr.MonPos.x);
+    putIntAt(buf, 4, tr.MonPos.y);
+    putBytesAt(buf, 8, tr.MonType, 1);
+    putIntAt(buf, 12, tr.MonHealth);
+    putBytesAt(buf, 16, tr.MonDir, 1);
+    putBytesAt(buf, 17, tr.MonActive, 1);
+    putIntAt(buf, 20, tr.MonCount);
+    putBytesAt(buf, 24, tr.MonEffect, 1);
+    putWordAt(buf, 26, tr.MonMax);
+    putWordAt(buf, 28, tr.MonDelay);
+    putBytesAt(buf, 30, tr.MonBehav, 1);
+  end;
+
+  procedure xwriteSpawnitem ();
+  begin
+    putIntAt(buf, 0, tr.ItemPos.x);
+    putIntAt(buf, 4, tr.ItemPos.y);
+    putBytesAt(buf, 8, tr.ItemType, 1);
+    putBytesAt(buf, 9, tr.ItemFalls, 1);
+    putBytesAt(buf, 10, tr.ItemOnlyDM, 1);
+    putIntAt(buf, 12, tr.ItemCount);
+    putBytesAt(buf, 16, tr.ItemEffect, 1);
+    putWordAt(buf, 18, tr.ItemMax);
+    putWordAt(buf, 20, tr.ItemDelay);
+  end;
+
+  procedure xwriteMusic ();
+  begin
+    putBytesAt(buf, 0, tr.MusicName, 64);
+    putBytesAt(buf, 64, tr.MusicAction, 1);
+  end;
+
+  procedure xwritePush ();
+  begin
+    putWordAt(buf, 0, tr.PushAngle);
+    putBytesAt(buf, 2, tr.PushForce, 1);
+    putBytesAt(buf, 3, tr.ResetVel, 1);
+  end;
+
+  procedure xwriteScore ();
+  begin
+    putBytesAt(buf, 0, tr.ScoreAction, 1);
+    putBytesAt(buf, 1, tr.ScoreCount, 1);
+    putBytesAt(buf, 2, tr.ScoreTeam, 1);
+    putBytesAt(buf, 3, tr.ScoreCon, 1);
+    putBytesAt(buf, 4, tr.ScoreMsg, 1);
+  end;
+
+  procedure xwriteMessage ();
+  begin
+    putBytesAt(buf, 0, tr.MessageKind, 1);
+    putBytesAt(buf, 1, tr.MessageSendTo, 1);
+    putBytesAt(buf, 2, tr.MessageText, 100);
+    putWordAt(buf, 102, tr.MessageTime);
+  end;
+
+  procedure xwriteDamage ();
+  begin
+    putWordAt(buf, 0, tr.DamageValue);
+    putWordAt(buf, 2, tr.DamageInterval);
+  end;
+
+  procedure xwriteHealth ();
+  begin
+    putWordAt(buf, 0, tr.HealValue);
+    putWordAt(buf, 2, tr.HealInterval);
+    putBytesAt(buf, 4, tr.HealMax, 1);
+    putBytesAt(buf, 5, tr.HealSilent, 1);
+  end;
+
+  procedure xwriteShot ();
+  begin
+    putIntAt(buf, 0, tr.ShotPos.x);
+    putIntAt(buf, 4, tr.ShotPos.y);
+    putBytesAt(buf, 8, tr.ShotType, 1);
+    putBytesAt(buf, 9, tr.ShotTarget, 1);
+    putBytesAt(buf, 10, tr.ShotSound, 1);
+    putBytesAt(buf, 11, tr.ShotAllMap, 1);
+    putIntAt(buf, 12, tr.ShotPanelID);
+    putWordAt(buf, 16, tr.ShotIntSight);
+    putWordAt(buf, 18, tr.ShotAngle);
+    putWordAt(buf, 20, tr.ShotWait);
+    putWordAt(buf, 22, tr.ShotAccuracy);
+    putWordAt(buf, 24, tr.ShotAmmo);
+    putWordAt(buf, 26, tr.ShotIntReload);
+  end;
+
+  procedure xwriteEffect ();
+  begin
+    putBytesAt(buf, 0, tr.FXCount, 1);
+    putBytesAt(buf, 1, tr.FXType, 1);
+    putBytesAt(buf, 2, tr.FXSubType, 1);
+    putBytesAt(buf, 3, tr.FXColorR, 1);
+    putBytesAt(buf, 4, tr.FXColorG, 1);
+    putBytesAt(buf, 5, tr.FXColorB, 1);
+    putBytesAt(buf, 6, tr.FXPos, 1);
+    putWordAt(buf, 8, tr.FXWait);
+    putBytesAt(buf, 10, tr.FXVelX, 1);
+    putBytesAt(buf, 11, tr.FXVelY, 1);
+    putBytesAt(buf, 12, tr.FXSpreadL, 1);
+    putBytesAt(buf, 13, tr.FXSpreadR, 1);
+    putBytesAt(buf, 14, tr.FXSpreadU, 1);
+    putBytesAt(buf, 15, tr.FXSpreadD, 1);
+  end;
+
+begin
+  if (bufsize < 104) then raise Exception.Create('invalid buffer size in mb_Write_TriggerData');
+  if (ttype = TRIGGER_EXIT) then begin xwriteExit(); exit; end;
+  if (ttype = TRIGGER_TELEPORT) then begin xwriteTeleport(); exit; end;
+  if (ttype = TRIGGER_OPENDOOR) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_CLOSEDOOR) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_DOOR) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_DOOR5) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_CLOSETRAP) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_TRAP) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_LIFTUP) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_LIFTDOWN) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_LIFT) then begin xwriteOpendoor(); exit; end;
+  if (ttype = TRIGGER_PRESS) then begin xwritePress(); exit; end;
+  if (ttype = TRIGGER_ON) then begin xwritePress(); exit; end;
+  if (ttype = TRIGGER_OFF) then begin xwritePress(); exit; end;
+  if (ttype = TRIGGER_ONOFF) then begin xwritePress(); exit; end;
+  if (ttype = TRIGGER_SECRET) then begin xwriteSecret(); exit; end;
+  if (ttype = TRIGGER_TEXTURE) then begin xwriteTexture(); exit; end;
+  if (ttype = TRIGGER_SOUND) then begin xwriteSound(); exit; end;
+  if (ttype = TRIGGER_SPAWNMONSTER) then begin xwriteSpawnmonster(); exit; end;
+  if (ttype = TRIGGER_SPAWNITEM) then begin xwriteSpawnitem(); exit; end;
+  if (ttype = TRIGGER_MUSIC) then begin xwriteMusic(); exit; end;
+  if (ttype = TRIGGER_PUSH) then begin xwritePush(); exit; end;
+  if (ttype = TRIGGER_SCORE) then begin xwriteScore(); exit; end;
+  if (ttype = TRIGGER_MESSAGE) then begin xwriteMessage(); exit; end;
+  if (ttype = TRIGGER_DAMAGE) then begin xwriteDamage(); exit; end;
+  if (ttype = TRIGGER_HEALTH) then begin xwriteHealth(); exit; end;
+  if (ttype = TRIGGER_SHOT) then begin xwriteShot(); exit; end;
+  if (ttype = TRIGGER_EFFECT) then begin xwriteEffect(); exit; end;
+  raise Exception.Create('invalid trigger type in mb_Write_TriggerData');
+end;
+
+
+procedure mb_Write_TMapHeaderRec_1 (var buf; bufsize: Integer; var tr: TMapHeaderRec_1);
+  procedure xwriteTmapheaderrec_1 ();
+  begin
+    putBytesAt(buf, 0, tr.MapName, 32);
+    putBytesAt(buf, 32, tr.MapAuthor, 32);
+    putBytesAt(buf, 64, tr.MapDescription, 256);
+    putBytesAt(buf, 320, tr.MusicName, 64);
+    putBytesAt(buf, 384, tr.SkyName, 64);
+    putWordAt(buf, 448, tr.Width);
+    putWordAt(buf, 450, tr.Height);
+  end;
+
+begin
+  if (bufsize < 452) then raise Exception.Create('invalid buffer size in writeTMapHeaderRec_1');
+  xwriteTmapheaderrec_1();
+end;
+
+procedure mb_Write_TTextureRec_1 (var buf; bufsize: Integer; var tr: TTextureRec_1);
+  procedure xwriteTtexturerec_1 ();
+  begin
+    putBytesAt(buf, 0, tr.Resource, 64);
+    putBytesAt(buf, 64, tr.Anim, 1);
+  end;
+
+begin
+  if (bufsize < 65) then raise Exception.Create('invalid buffer size in writeTTextureRec_1');
+  xwriteTtexturerec_1();
+end;
+
+procedure mb_Write_TPanelRec_1 (var buf; bufsize: Integer; var tr: TPanelRec_1);
+  procedure xwriteTpanelrec_1 ();
+  begin
+    putIntAt(buf, 0, tr.X);
+    putIntAt(buf, 4, tr.Y);
+    putWordAt(buf, 8, tr.Width);
+    putWordAt(buf, 10, tr.Height);
+    putWordAt(buf, 12, tr.TextureNum);
+    putWordAt(buf, 14, tr.PanelType);
+    putBytesAt(buf, 16, tr.Alpha, 1);
+    putBytesAt(buf, 17, tr.Flags, 1);
+  end;
+
+begin
+  if (bufsize < 18) then raise Exception.Create('invalid buffer size in writeTPanelRec_1');
+  xwriteTpanelrec_1();
+end;
+
+procedure mb_Write_TItemRec_1 (var buf; bufsize: Integer; var tr: TItemRec_1);
+  procedure xwriteTitemrec_1 ();
+  begin
+    putIntAt(buf, 0, tr.X);
+    putIntAt(buf, 4, tr.Y);
+    putBytesAt(buf, 8, tr.ItemType, 1);
+    putBytesAt(buf, 9, tr.Options, 1);
+  end;
+
+begin
+  if (bufsize < 10) then raise Exception.Create('invalid buffer size in writeTItemRec_1');
+  xwriteTitemrec_1();
+end;
+
+procedure mb_Write_TMonsterRec_1 (var buf; bufsize: Integer; var tr: TMonsterRec_1);
+  procedure xwriteTmonsterrec_1 ();
+  begin
+    putIntAt(buf, 0, tr.X);
+    putIntAt(buf, 4, tr.Y);
+    putBytesAt(buf, 8, tr.MonsterType, 1);
+    putBytesAt(buf, 9, tr.Direction, 1);
+  end;
+
+begin
+  if (bufsize < 10) then raise Exception.Create('invalid buffer size in writeTMonsterRec_1');
+  xwriteTmonsterrec_1();
+end;
+
+procedure mb_Write_TAreaRec_1 (var buf; bufsize: Integer; var tr: TAreaRec_1);
+  procedure xwriteTarearec_1 ();
+  begin
+    putIntAt(buf, 0, tr.X);
+    putIntAt(buf, 4, tr.Y);
+    putBytesAt(buf, 8, tr.AreaType, 1);
+    putBytesAt(buf, 9, tr.Direction, 1);
+  end;
+
+begin
+  if (bufsize < 10) then raise Exception.Create('invalid buffer size in writeTAreaRec_1');
+  xwriteTarearec_1();
+end;
+
+procedure mb_Write_TTriggerRec_1 (var buf; bufsize: Integer; var tr: TTriggerRec_1);
+  procedure xwriteTtriggerrec_1 ();
+  begin
+    putIntAt(buf, 0, tr.X);
+    putIntAt(buf, 4, tr.Y);
+    putWordAt(buf, 8, tr.Width);
+    putWordAt(buf, 10, tr.Height);
+    putBytesAt(buf, 12, tr.Enabled, 1);
+    putIntAt(buf, 13, tr.TexturePanel);
+    putBytesAt(buf, 17, tr.TriggerType, 1);
+    putBytesAt(buf, 18, tr.ActivateType, 1);
+    putBytesAt(buf, 19, tr.Keys, 1);
+    putBytesAt(buf, 20, tr.DATA, 128);
+  end;
+
+begin
+  if (bufsize < 148) then raise Exception.Create('invalid buffer size in writeTTriggerRec_1');
+  xwriteTtriggerrec_1();
+end;
+
diff --git a/src/shared/mapstructsizes.inc b/src/shared/mapstructsizes.inc
new file mode 100644 (file)
index 0000000..e793c06
--- /dev/null
@@ -0,0 +1,25 @@
+const
+  SizeOf_TMapHeaderRec_1 = 452;
+  SizeOf_TTextureRec_1 = 65;
+  SizeOf_TPanelRec_1 = 18;
+  SizeOf_TItemRec_1 = 10;
+  SizeOf_TMonsterRec_1 = 10;
+  SizeOf_TAreaRec_1 = 10;
+  SizeOf_TTriggerRec_1 = 148;
+
+procedure mb_Read_TriggerData (var tr: TTriggerData; ttype: Integer; const buf; bufsize: Integer);
+procedure mb_Write_TriggerData (var buf; bufsize: Integer; ttype: Integer; var tr: TTriggerData);
+procedure mb_Read_TMapHeaderRec_1 (var tr: TMapHeaderRec_1; const buf; bufsize: Integer);
+procedure mb_Write_TMapHeaderRec_1 (var buf; bufsize: Integer; var tr: TMapHeaderRec_1);
+procedure mb_Read_TTextureRec_1 (var tr: TTextureRec_1; const buf; bufsize: Integer);
+procedure mb_Write_TTextureRec_1 (var buf; bufsize: Integer; var tr: TTextureRec_1);
+procedure mb_Read_TPanelRec_1 (var tr: TPanelRec_1; const buf; bufsize: Integer);
+procedure mb_Write_TPanelRec_1 (var buf; bufsize: Integer; var tr: TPanelRec_1);
+procedure mb_Read_TItemRec_1 (var tr: TItemRec_1; const buf; bufsize: Integer);
+procedure mb_Write_TItemRec_1 (var buf; bufsize: Integer; var tr: TItemRec_1);
+procedure mb_Read_TMonsterRec_1 (var tr: TMonsterRec_1; const buf; bufsize: Integer);
+procedure mb_Write_TMonsterRec_1 (var buf; bufsize: Integer; var tr: TMonsterRec_1);
+procedure mb_Read_TAreaRec_1 (var tr: TAreaRec_1; const buf; bufsize: Integer);
+procedure mb_Write_TAreaRec_1 (var buf; bufsize: Integer; var tr: TAreaRec_1);
+procedure mb_Read_TTriggerRec_1 (var tr: TTriggerRec_1; const buf; bufsize: Integer);
+procedure mb_Write_TTriggerRec_1 (var buf; bufsize: Integer; var tr: TTriggerRec_1);
diff --git a/src/shared/utils.pas b/src/shared/utils.pas
new file mode 100644 (file)
index 0000000..253e838
--- /dev/null
@@ -0,0 +1,527 @@
+(* Copyright (C)  DooM 2D:Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$MODE DELPHI}
+unit utils;
+
+interface
+
+uses
+  SysUtils, Classes;
+
+
+// does filename have one of ".wad", ".pk3", ".zip" extensions?
+function hasWadExtension (fn: AnsiString): Boolean;
+
+// does filepath have ".XXX:\" in it?
+function isWadPath (fn: AnsiString): Boolean;
+
+// adds ".wad" extension if filename doesn't have one of ".wad", ".pk3", ".zip"
+function addWadExtension (fn: AnsiString): AnsiString;
+
+// convert number to strig with nice commas
+function Int64ToStrComma (i: Int64): AnsiString;
+
+function UpCase1251 (ch: Char): Char;
+function LoCase1251 (ch: Char): Char;
+
+// `true` if strings are equal; ignoring case for cp1251
+function StrEquCI1251 (const s0, s1: AnsiString): Boolean;
+
+function utf8Valid (const s: AnsiString): Boolean;
+
+function utf8to1251 (s: AnsiString): AnsiString;
+
+// `pathname` will be modified if path is valid
+// `lastIsDir` should be `true` if we are searching for directory
+// nobody cares about shitdoze, so i'll use the same code path for it
+function findFileCI (var pathname: AnsiString; lastIsDir: Boolean=false): Boolean;
+
+// they throws
+function openDiskFileRO (pathname: AnsiString): TStream;
+function createDiskFile (pathname: AnsiString): TStream;
+
+// little endian
+procedure writeInt (st: TStream; v: Byte); overload;
+procedure writeInt (st: TStream; v: ShortInt); overload;
+procedure writeInt (st: TStream; v: Word); overload;
+procedure writeInt (st: TStream; v: SmallInt); overload;
+procedure writeInt (st: TStream; v: LongWord); overload;
+procedure writeInt (st: TStream; v: LongInt); overload;
+procedure writeInt (st: TStream; v: Int64); overload;
+procedure writeInt (st: TStream; v: UInt64); overload;
+
+function readByte (st: TStream): Byte;
+function readShortInt (st: TStream): ShortInt;
+function readWord (st: TStream): Word;
+function readSmallInt (st: TStream): SmallInt;
+function readLongWord (st: TStream): LongWord;
+function readLongInt (st: TStream): LongInt;
+function readInt64 (st: TStream): Int64;
+function readUInt64 (st: TStream): UInt64;
+
+// big endian
+procedure writeIntBE (st: TStream; v: Byte); overload;
+procedure writeIntBE (st: TStream; v: ShortInt); overload;
+procedure writeIntBE (st: TStream; v: Word); overload;
+procedure writeIntBE (st: TStream; v: SmallInt); overload;
+procedure writeIntBE (st: TStream; v: LongWord); overload;
+procedure writeIntBE (st: TStream; v: LongInt); overload;
+procedure writeIntBE (st: TStream; v: Int64); overload;
+procedure writeIntBE (st: TStream; v: UInt64); overload;
+
+function readByteBE (st: TStream): Byte;
+function readShortIntBE (st: TStream): ShortInt;
+function readWordBE (st: TStream): Word;
+function readSmallIntBE (st: TStream): SmallInt;
+function readLongWordBE (st: TStream): LongWord;
+function readLongIntBE (st: TStream): LongInt;
+function readInt64BE (st: TStream): Int64;
+function readUInt64BE (st: TStream): UInt64;
+
+
+implementation
+
+
+function hasWadExtension (fn: AnsiString): Boolean;
+begin
+  fn := ExtractFileExt(fn);
+  result := StrEquCI1251(fn, '.wad') or StrEquCI1251(fn, '.pk3') or StrEquCI1251(fn, '.zip');
+end;
+
+
+function addWadExtension (fn: AnsiString): AnsiString;
+begin
+  result := fn;
+  if not hasWadExtension(result) then result := result+'.wad';
+end;
+
+
+function isWadPath (fn: AnsiString): Boolean;
+var
+  p: Integer;
+  s: AnsiString;
+begin
+  result := false;
+  while true do
+  begin
+    p := Pos(':', fn);
+    if (p = 0) or (length(fn)-p < 1) then break;
+    if (p-4 > 1) and (fn[p-4] = '.') and ((fn[p+1] = '\') or (fn[p+1] = '/')) then
+    begin
+      s := Copy(fn, p-4, 4);
+      if StrEquCI1251(s, '.wad') or StrEquCI1251(s, '.pk3') or StrEquCI1251(s, '.zip') then
+      begin
+        result := true;
+        exit;
+      end;
+    end;
+    Delete(fn, 1, p);
+  end;
+end;
+
+
+function Int64ToStrComma (i: Int64): AnsiString;
+var
+  f: Integer;
+begin
+  Str(i, result);
+  f := Length(result)+1;
+  while f > 4 do
+  begin
+    Dec(f, 3); Insert(',', result, f);
+  end;
+end;
+
+
+function UpCase1251 (ch: Char): Char;
+begin
+  if ch < #128 then
+  begin
+    if (ch >= 'a') and (ch <= 'z') then Dec(ch, 32);
+  end
+  else
+  begin
+    if (ch >= #224) and (ch <= #255) then
+    begin
+      Dec(ch, 32);
+    end
+    else
+    begin
+      case ch of
+        #184, #186, #191: Dec(ch, 16);
+        #162, #179: Dec(ch);
+      end;
+    end;
+  end;
+  result := ch;
+end;
+
+
+function LoCase1251 (ch: Char): Char;
+begin
+  if ch < #128 then
+  begin
+    if (ch >= 'A') and (ch <= 'Z') then Inc(ch, 32);
+  end
+  else
+  begin
+    if (ch >= #192) and (ch <= #223) then
+    begin
+      Inc(ch, 32);
+    end
+    else
+    begin
+      case ch of
+        #168, #170, #175: Inc(ch, 16);
+        #161, #178: Inc(ch);
+      end;
+    end;
+  end;
+  result := ch;
+end;
+
+
+function StrEquCI1251 (const s0, s1: AnsiString): Boolean;
+var
+  i: Integer;
+begin
+  result := false;
+  if length(s0) <> length(s1) then exit;
+  for i := 1 to length(s0) do if UpCase1251(s0[i]) <> UpCase1251(s1[i]) then exit;
+  result := true;
+end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+// utils
+// `ch`: utf8 start
+// -1: invalid utf8
+function utf8CodeLen (ch: Word): Integer;
+begin
+  if ch < $80 then begin result := 1; exit; end;
+  if (ch and $FE) = $FC then begin result := 6; exit; end;
+  if (ch and $FC) = $F8 then begin result := 5; exit; end;
+  if (ch and $F8) = $F0 then begin result := 4; exit; end;
+  if (ch and $F0) = $E0 then begin result := 3; exit; end;
+  if (ch and $E0) = $C0 then begin result := 2; exit; end;
+  result := -1; // invalid
+end;
+
+
+function utf8Valid (const s: AnsiString): Boolean;
+var
+  pos, len: Integer;
+begin
+  result := false;
+  pos := 1;
+  while pos <= length(s) do
+  begin
+    len := utf8CodeLen(Byte(s[pos]));
+    if len < 1 then exit; // invalid sequence start
+    if pos+len-1 > length(s) then exit; // out of chars in string
+    Dec(len);
+    Inc(pos);
+    // check other sequence bytes
+    while len > 0 do
+    begin
+      if (Byte(s[pos]) and $C0) <> $80 then exit;
+      Dec(len);
+      Inc(pos);
+    end;
+  end;
+  result := true;
+end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+const
+  uni2wint: array [128..255] of Word = (
+    $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
+    $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
+    $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
+    $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
+    $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
+    $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
+    $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
+    $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
+  );
+
+
+function decodeUtf8Char (s: AnsiString; var pos: Integer): char;
+var
+  b, c: Integer;
+begin
+  (* The following encodings are valid, except for the 5 and 6 byte
+   * combinations:
+   *  0xxxxxxx
+   *  110xxxxx 10xxxxxx
+   *  1110xxxx 10xxxxxx 10xxxxxx
+   *  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+   *  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+   *  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+   *)
+  result := '?';
+  if pos > length(s) then exit;
+
+  b := Byte(s[pos]);
+  Inc(pos);
+  if b < $80 then begin result := char(b); exit; end;
+
+  // mask out unused bits
+       if (b and $FE) = $FC then b := b and $01
+  else if (b and $FC) = $F8 then b := b and $03
+  else if (b and $F8) = $F0 then b := b and $07
+  else if (b and $F0) = $E0 then b := b and $0F
+  else if (b and $E0) = $C0 then b := b and $1F
+  else exit; // invalid utf8
+
+  // now continue
+  while pos <= length(s) do
+  begin
+    c := Byte(s[pos]);
+    if (c and $C0) <> $80 then break; // no more
+    b := b shl 6;
+    b := b or (c and $3F);
+    Inc(pos);
+  end;
+
+  // done, try 1251
+  for c := 128 to 255 do if uni2wint[c] = b then begin result := char(c and $FF); exit; end;
+  // alas
+end;
+
+
+function utf8to1251 (s: AnsiString): AnsiString;
+var
+  pos: Integer;
+begin
+  if not utf8Valid(s) then begin result := s; exit; end;
+  pos := 1;
+  while pos <= length(s) do
+  begin
+    if Byte(s[pos]) >= $80 then break;
+    Inc(pos);
+  end;
+  if pos > length(s) then begin result := s; exit; end; // nothing to do here
+  result := '';
+  pos := 1;
+  while pos <= length(s) do result := result+decodeUtf8Char(s, pos);
+end;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+// `pathname` will be modified if path is valid
+// `lastIsDir` should be `true` if we are searching for directory
+// nobody cares about shitdoze, so i'll use the same code path for it
+function findFileCI (var pathname: AnsiString; lastIsDir: Boolean=false): Boolean;
+var
+  sr: TSearchRec;
+  npt: AnsiString;
+  newname: AnsiString = '';
+  curname: AnsiString;
+  wantdir: Boolean;
+  attr: LongInt;
+  foundher: Boolean;
+begin
+  npt := pathname;
+  result := (length(npt) > 0);
+  if (length(npt) > 0) and ((npt[1] = '/') or (npt[1] = '\')) then newname := '/';
+  while length(npt) > 0 do
+  begin
+    // remove trailing slashes
+    while (length(npt) > 0) and ((npt[1] = '/') or (npt[1] = '\')) do Delete(npt, 1, 1);
+    if length(npt) = 0 then break;
+    // extract name
+    curname := '';
+    while (length(npt) > 0) and (npt[1] <> '/') and (npt[1] <> '\') do
+    begin
+      curname := curname+npt[1];
+      Delete(npt, 1, 1);
+    end;
+    // remove trailing slashes again
+    while (length(npt) > 0) and ((npt[1] = '/') or (npt[1] = '\')) do Delete(npt, 1, 1);
+    wantdir := lastIsDir or (length(npt) > 0); // do we want directory here?
+    //writeln(Format('npt=[%s]; newname=[%s]; curname=[%s]; wantdir=%d', [npt, newname, curname, Integer(wantdir)]));
+    // try the easiest case first
+    attr := FileGetAttr(newname+curname);
+    if attr <> -1 then
+    begin
+      if wantdir = ((attr and faDirectory) <> 0) then
+      begin
+        // i found her!
+        newname := newname+curname;
+        if wantdir then newname := newname+'/';
+        continue;
+      end;
+    end;
+    //writeln(Format('npt=[%s]; newname=[%s]; curname=[%s]; wantdir=%d', [npt, newname, curname, Integer(wantdir)]));
+    // alas, either not found, or invalid attributes
+    foundher := false;
+    try
+      if FindFirst(newname+'*', faAnyFile, sr) = 0 then
+      repeat
+        if (wantdir = ((sr.attr and faDirectory) <> 0)) and StrEquCI1251(sr.name, curname) then
+        begin
+          // i found her!
+          newname := newname+sr.name;
+          if wantdir then newname := newname+'/';
+          foundher := true;
+          break;
+        end;
+      until FindNext(sr) <> 0;
+    finally
+      FindClose(sr);
+    end;
+    if not foundher then begin newname := ''; result := false; break; end;
+  end;
+  if result then pathname := newname;
+end;
+
+
+function openDiskFileRO (pathname: AnsiString): TStream;
+begin
+  if not findFileCI(pathname) then raise Exception.Create('can''t open file "'+pathname+'"');
+  result := TFileStream.Create(pathname, fmOpenRead or {fmShareDenyWrite}fmShareDenyNone);
+end;
+
+function createDiskFile (pathname: AnsiString): TStream;
+var
+  path: AnsiString;
+begin
+  path := ExtractFilePath(pathname);
+  if length(path) > 0 then
+  begin
+    if not findFileCI(path, true) then raise Exception.Create('can''t create file "'+pathname+'"');
+  end;
+  result := TFileStream.Create(path+ExtractFileName(pathname), fmCreate);
+end;
+
+
+procedure writeIntegerLE (st: TStream; vp: Pointer; size: Integer);
+{$IFDEF ENDIAN_LITTLE}
+begin
+  st.writeBuffer(vp^, size);
+end;
+{$ELSE}
+var
+  p: PByte;
+begin
+  p := PByte(vp)+size-1;
+  while size > 0 do
+  begin
+    st.writeBuffer(p^, 1);
+    Dec(size);
+    Dec(p);
+  end;
+end;
+{$ENDIF}
+
+procedure writeIntegerBE (st: TStream; vp: Pointer; size: Integer);
+{$IFDEF ENDIAN_LITTLE}
+var
+  p: PByte;
+begin
+  p := PByte(vp)+size-1;
+  while size > 0 do
+  begin
+    st.writeBuffer(p^, 1);
+    Dec(size);
+    Dec(p);
+  end;
+end;
+{$ELSE}
+begin
+  st.writeBuffer(vp^, size);
+end;
+{$ENDIF}
+
+procedure writeInt (st: TStream; v: Byte); overload; begin writeIntegerLE(st, @v, 1); end;
+procedure writeInt (st: TStream; v: ShortInt); overload; begin writeIntegerLE(st, @v, 1); end;
+procedure writeInt (st: TStream; v: Word); overload; begin writeIntegerLE(st, @v, 2); end;
+procedure writeInt (st: TStream; v: SmallInt); overload; begin writeIntegerLE(st, @v, 2); end;
+procedure writeInt (st: TStream; v: LongWord); overload; begin writeIntegerLE(st, @v, 4); end;
+procedure writeInt (st: TStream; v: LongInt); overload; begin writeIntegerLE(st, @v, 4); end;
+procedure writeInt (st: TStream; v: Int64); overload; begin writeIntegerLE(st, @v, 8); end;
+procedure writeInt (st: TStream; v: UInt64); overload; begin writeIntegerLE(st, @v, 8); end;
+
+procedure writeIntBE (st: TStream; v: Byte); overload; begin writeIntegerBE(st, @v, 1); end;
+procedure writeIntBE (st: TStream; v: ShortInt); overload; begin writeIntegerBE(st, @v, 1); end;
+procedure writeIntBE (st: TStream; v: Word); overload; begin writeIntegerBE(st, @v, 2); end;
+procedure writeIntBE (st: TStream; v: SmallInt); overload; begin writeIntegerBE(st, @v, 2); end;
+procedure writeIntBE (st: TStream; v: LongWord); overload; begin writeIntegerBE(st, @v, 4); end;
+procedure writeIntBE (st: TStream; v: LongInt); overload; begin writeIntegerBE(st, @v, 4); end;
+procedure writeIntBE (st: TStream; v: Int64); overload; begin writeIntegerBE(st, @v, 8); end;
+procedure writeIntBE (st: TStream; v: UInt64); overload; begin writeIntegerBE(st, @v, 8); end;
+
+
+procedure readIntegerLE (st: TStream; vp: Pointer; size: Integer);
+{$IFDEF ENDIAN_LITTLE}
+begin
+  st.readBuffer(vp^, size);
+end;
+{$ELSE}
+var
+  p: PByte;
+begin
+  p := PByte(vp)+size-1;
+  while size > 0 do
+  begin
+    st.readBuffer(p^, 1);
+    Dec(size);
+    Dec(p);
+  end;
+end;
+{$ENDIF}
+
+procedure readIntegerBE (st: TStream; vp: Pointer; size: Integer);
+{$IFDEF ENDIAN_LITTLE}
+var
+  p: PByte;
+begin
+  p := PByte(vp)+size-1;
+  while size > 0 do
+  begin
+    st.readBuffer(p^, 1);
+    Dec(size);
+    Dec(p);
+  end;
+end;
+{$ELSE}
+begin
+  st.readBuffer(vp^, size);
+end;
+{$ENDIF}
+
+function readByte (st: TStream): Byte; begin readIntegerLE(st, @result, 1); end;
+function readShortInt (st: TStream): ShortInt; begin readIntegerLE(st, @result, 1); end;
+function readWord (st: TStream): Word; begin readIntegerLE(st, @result, 2); end;
+function readSmallInt (st: TStream): SmallInt; begin readIntegerLE(st, @result, 2); end;
+function readLongWord (st: TStream): LongWord; begin readIntegerLE(st, @result, 4); end;
+function readLongInt (st: TStream): LongInt; begin readIntegerLE(st, @result, 4); end;
+function readInt64 (st: TStream): Int64; begin readIntegerLE(st, @result, 8); end;
+function readUInt64 (st: TStream): UInt64; begin readIntegerLE(st, @result, 8); end;
+
+function readByteBE (st: TStream): Byte; begin readIntegerBE(st, @result, 1); end;
+function readShortIntBE (st: TStream): ShortInt; begin readIntegerBE(st, @result, 1); end;
+function readWordBE (st: TStream): Word; begin readIntegerBE(st, @result, 2); end;
+function readSmallIntBE (st: TStream): SmallInt; begin readIntegerBE(st, @result, 2); end;
+function readLongWordBE (st: TStream): LongWord; begin readIntegerBE(st, @result, 4); end;
+function readLongIntBE (st: TStream): LongInt; begin readIntegerBE(st, @result, 4); end;
+function readInt64BE (st: TStream): Int64; begin readIntegerBE(st, @result, 8); end;
+function readUInt64BE (st: TStream): UInt64; begin readIntegerBE(st, @result, 8); end;
+
+
+end.