Bläddra i källkod

Combined GLSL.ShaderBump & GLSL.ShaderBumps units

GLScene 5 år sedan
förälder
incheckning
2bad7ab57e
74 ändrade filer med 11588 tillägg och 9818 borttagningar
  1. 1 1
      Demos/CPP/cgshaders/CGBombShader/Unit1.cpp
  2. 1 1
      Demos/CPP/cgshaders/CGBombShader/Unit1.h
  3. 2 2
      Demos/CPP/cgshaders/celshading/Unit1.cpp
  4. 1 1
      Demos/CPP/cgshaders/celshading/Unit1.h
  5. 2 2
      Demos/CPP/glslshaders/BumpShader/Unit1.cpp
  6. 2 2
      Demos/CPP/glslshaders/BumpShader/Unit1.h
  7. 3 3
      Demos/CPP/glslshaders/DiffuseSpecularShader/Unit1.cpp
  8. 2 2
      Demos/CPP/glslshaders/DiffuseSpecularShader/Unit1.h
  9. 1 1
      Demos/CPP/glslshaders/GLSLShaderComponent/Unit1.cpp
  10. 1 1
      Demos/CPP/glslshaders/GLSLShaderComponent/Unit1.h
  11. 1 1
      Demos/CPP/glslshaders/Ocean/Unit1.cpp
  12. 1 1
      Demos/CPP/glslshaders/PostShader/Unit1.cpp
  13. 3 3
      Demos/CPP/glslshaders/PostShader/Unit1.h
  14. 1 0
      Demos/Delphi/cgshaders/CGBombShader/uMainForm.dfm
  15. 1 1
      Demos/Delphi/cgshaders/CGBombShader/uMainForm.pas
  16. 1 1
      Demos/Delphi/cgshaders/cellshading/Unit1.pas
  17. 1 1
      Demos/Delphi/cgshaders/simple/Unit1.pas
  18. 1 1
      Demos/Delphi/cgshaders/texturing/Unit1.pas
  19. 4 4
      Demos/Delphi/glslshaders/BumpShader/uMainForm.pas
  20. 2 2
      Demos/Delphi/glslshaders/DiffuseSpecularShader/uMainForm.pas
  21. 1 1
      Demos/Delphi/glslshaders/GLSLShaderComponent/uMainForm.pas
  22. 3 3
      Demos/Delphi/glslshaders/PostShaders/UMainForm.pas
  23. 17 16
      Demos/Delphi/glslshaders/ShadersLab/UMainForm.dfm
  24. 1 1
      Demos/Delphi/glslshaders/ShadersLab/UMainForm.pas
  25. 3 3
      Demos/Delphi/rendering/phong/Unit1.pas
  26. 1 1
      Demos/Delphi/specialsFX/posteffect/uMainForm.pas
  27. 24 16
      Demos/Delphi/utilities/recorder/Unit1.pas
  28. 1 1
      Packages/GLScene_Cg_DT.dpk
  29. 1 1
      Packages/GLScene_Cg_DT.dproj
  30. 3 3
      Packages/GLScene_Cg_RT.dpk
  31. 3 3
      Packages/GLScene_Cg_RT.dproj
  32. 3 2
      Packages/GLScene_DT.dpk
  33. 1 7
      Packages/GLScene_DT.dproj
  34. 13 14
      Packages/GLScene_RT.dpk
  35. 13 14
      Packages/GLScene_RT.dproj
  36. 0 1
      Source/FileTGA.pas
  37. 2484 2484
      Source/Formats.FileLWObjects.pas
  38. 4643 4683
      Source/Formats.FileVFW.pas
  39. 1 1
      Source/Formats.FileX.pas
  40. 1 1
      Source/GLAVIRecorder.pas
  41. 2 1
      Source/GLBaseClasses.pas
  42. 3 4
      Source/GLCrossPlatform.pas
  43. 1 1
      Source/GLFileLWO.pas
  44. 1 1
      Source/GLFileX.pas
  45. 505 0
      Source/GLS.AVIRecorder.pas
  46. 2 4
      Source/GLS.ArchiveManager.pas
  47. 1589 1589
      Source/GLS.Isosurface.pas
  48. 15 16
      Source/GLS.SceneRegister.pas
  49. 0 853
      Source/GLS.ShaderBump.pas
  50. 0 3
      Source/GLS.ShaderCombiner.pas
  51. 1 2
      Source/GLS.Triangulation.pas
  52. 3 3
      Source/GLSL.AsmShader.pas
  53. 846 13
      Source/GLSL.BumpShaders.pas
  54. 2 2
      Source/GLSL.CgBombShader.pas
  55. 4 4
      Source/GLSL.CgPostTransformationShader.pas
  56. 5 5
      Source/GLSL.CgRegister.pas
  57. 3 2
      Source/GLSL.CgShader.pas
  58. 1 1
      Source/GLSL.CustomShader.pas
  59. 827 0
      Source/GLSL.DiffuseSpecularShader.pas
  60. 3 3
      Source/GLSL.PhongShader.pas
  61. 492 0
      Source/GLSL.PostEffects.pas
  62. 17 7
      Source/GLSL.PostShaders.pas
  63. 5 5
      Source/GLSL.Shader.pas
  64. 2 2
      Source/GLSL.ShaderDiffuseSpecular.pas
  65. 1 1
      Source/GLSL.ShaderErosion.pas
  66. 1 1
      Source/GLSL.ShaderFur.pas
  67. 1 1
      Source/GLSL.ShaderGlass.pas
  68. 1 1
      Source/GLSL.ShaderGooch.pas
  69. 1 1
      Source/GLSL.ShaderIvory.pas
  70. 1 1
      Source/GLSL.ShaderLattice.pas
  71. 1 1
      Source/GLSL.ShaderSem.pas
  72. 1 1
      Source/GLSL.ShaderToon.pas
  73. 1 1
      Source/GLSL.ShaderVertexDisplacement.pas
  74. 1 1
      Source/Scene.CrossXML.pas

+ 1 - 1
Demos/CPP/cgshaders/CGBombShader/Unit1.cpp

@@ -20,7 +20,7 @@
 #pragma link "GLFileMD2"
 #pragma link "GLFile3DS"
 
-#pragma link "GLS.cgBombShader"
+#pragma link "GLSL.cgBombShader"
 
 #pragma resource "*.dfm"
 TForm1 *Form1;

+ 1 - 1
Demos/CPP/cgshaders/CGBombShader/Unit1.h

@@ -22,7 +22,7 @@
 #include "GLSimpleNavigation.hpp"
 #include "GLVectorFileObjects.hpp"
 #include "GLSceneViewer.hpp"
-#include "GLS.cgBombShader.hpp"
+#include "GLSL.cgBombShader.hpp"
 #include "JPeg.hpp"
 #include "GLFileMD2.hpp"
 #include "GLFile3DS.hpp"

+ 2 - 2
Demos/CPP/cgshaders/celshading/Unit1.cpp

@@ -10,7 +10,7 @@
 #pragma link "GLAsyncTimer"
 #pragma link "GLBaseClasses"
 #pragma link "GLCadencer"
-#pragma link "GLS.cgShader"
+#pragma link "GLSL.cgShader"
 #pragma link "GLCoordinates"
 #pragma link "GLCrossPlatform"
 #pragma link "GLMaterial"
@@ -20,7 +20,7 @@
 #pragma link "GLSceneViewer"
 #pragma link "GLFileMD2"
 
-#pragma link "GLS.cgShader"
+#pragma link "GLSL.cgShader"
 #pragma resource "*.dfm"
 TForm1 *Form1;
 //---------------------------------------------------------------------------

+ 1 - 1
Demos/CPP/cgshaders/celshading/Unit1.h

@@ -21,7 +21,7 @@
 #include "GLFileMD2.hpp"
 #include "GLS.Utils.hpp"
 #include "Import.CgGL.hpp"
-#include "GLS.cgShader.hpp"
+#include "GLSL.cgShader.hpp"
 
 //---------------------------------------------------------------------------
 class TForm1 : public TForm

+ 2 - 2
Demos/CPP/glslshaders/BumpShader/Unit1.cpp

@@ -12,7 +12,7 @@
 #pragma link "GLCadencer"
 #pragma link "GLCoordinates"
 #pragma link "GLCrossPlatform"
-#pragma link "GLS.ShaderCustom"
+#pragma link "GLSL.CustomShader"
 #pragma link "GLGeomObjects"
 #pragma link "GLGraph"
 #pragma link "GLMaterial"
@@ -29,7 +29,7 @@
 #pragma link "GLFileMS3D"
 #pragma link "GLBaseClasses"
 #pragma link "GLSL.Shader"
-#pragma link "GLSL.ShaderBump"
+#pragma link "GLSL.BumpShaders"
 #pragma resource "*.dfm"
 TForm1 *Form1;
 //---------------------------------------------------------------------------

+ 2 - 2
Demos/CPP/glslshaders/BumpShader/Unit1.h

@@ -13,7 +13,7 @@
 #include "GLCadencer.hpp"
 #include "GLCoordinates.hpp"
 #include "GLCrossPlatform.hpp"
-#include "GLS.ShaderCustom.hpp"
+#include "GLSL.CustomShader.hpp"
 #include "GLGeomObjects.hpp"
 #include "GLGraph.hpp"
 #include "GLMaterial.hpp"
@@ -32,7 +32,7 @@
 #include "GLS.Utils.hpp"
 #include "GLBaseClasses.hpp"
 #include "GLSL.Shader.hpp"
-#include "GLSL.ShaderBump.hpp"
+#include "GLSL.BumpShaders.hpp"
 
 //---------------------------------------------------------------------------
 class TForm1 : public TForm

+ 3 - 3
Demos/CPP/glslshaders/DiffuseSpecularShader/Unit1.cpp

@@ -11,14 +11,14 @@
 #pragma link "GLCadencer"
 #pragma link "GLCoordinates"
 #pragma link "GLCrossPlatform"
-#pragma link "GLS.ShaderCustom"
+#pragma link "GLSL.CustomShader"
 #pragma link "GLGeomObjects"
 #pragma link "GLGraph"
 #pragma link "GLMaterial"
 #pragma link "GLObjects"
 #pragma link "GLScene"
 #pragma link "GLSimpleNavigation"
-#pragma link "GLSL.ShaderDiffuseSpecular"
+#pragma link "GLSL.DiffuseSpecularShader"
 #pragma link "GLSL.Shader"
 #pragma link "GLVectorFileObjects"
 #pragma link "GLSceneViewer"
@@ -28,8 +28,8 @@
 #pragma link "FileDDSImage"
 #pragma link "GLFileMS3D"
 
-#pragma link "GLSL.ShaderDiffuseSpecular"
 #pragma resource "*.dfm"
+
 TForm1 *Form1;
 //---------------------------------------------------------------------------
 __fastcall TForm1::TForm1(TComponent* Owner)

+ 2 - 2
Demos/CPP/glslshaders/DiffuseSpecularShader/Unit1.h

@@ -13,7 +13,7 @@
 #include "GLCadencer.hpp"
 #include "GLCoordinates.hpp"
 #include "GLCrossPlatform.hpp"
-#include "GLS.ShaderCustom.hpp"
+#include "GLSL.CustomShader.hpp"
 #include "GLGeomObjects.hpp"
 #include "GLGraph.hpp"
 #include "GLMaterial.hpp"
@@ -30,7 +30,7 @@
 #include "FileDDSImage.hpp"
 #include "GLFileMS3D.hpp"
 #include "GLS.Utils.hpp"
-#include "GLSL.ShaderDiffuseSpecular.hpp"
+#include "GLSL.DiffuseSpecularShader.hpp"
 
 //---------------------------------------------------------------------------
 class TForm1 : public TForm

+ 1 - 1
Demos/CPP/glslshaders/GLSLShaderComponent/Unit1.cpp

@@ -11,7 +11,7 @@
 #pragma link "GLCadencer"
 #pragma link "GLCoordinates"
 #pragma link "GLCrossPlatform"
-#pragma link "GLS.ShaderCustom"
+#pragma link "GLSL.CustomShader"
 #pragma link "GLGeomObjects"
 #pragma link "GLGraph"
 #pragma link "GLMaterial"

+ 1 - 1
Demos/CPP/glslshaders/GLSLShaderComponent/Unit1.h

@@ -13,7 +13,7 @@
 #include "GLCadencer.hpp"
 #include "GLCoordinates.hpp"
 #include "GLCrossPlatform.hpp"
-#include "GLS.ShaderCustom.hpp"
+#include "GLSL.CustomShader.hpp"
 #include "GLGeomObjects.hpp"
 #include "GLGraph.hpp"
 #include "GLMaterial.hpp"

+ 1 - 1
Demos/CPP/glslshaders/Ocean/Unit1.cpp

@@ -93,7 +93,7 @@ void __fastcall TForm1::DOInitializeRender(TObject *Sender, TGLRenderContextInfo
 void __fastcall TForm1::GLUserShader1DoApply(TObject *Sender, TGLRenderContextInfo &rci)
 
 {
-  Scene.VectorGeometry::TVector camPos;
+  TVector camPos;
 
   programObject = new TGLProgramHandle();
   programObject->UseProgramObject();

+ 1 - 1
Demos/CPP/glslshaders/PostShader/Unit1.cpp

@@ -15,7 +15,6 @@
 #pragma link "GLGraph"
 #pragma link "GLMaterial"
 #pragma link "GLObjects"
-#pragma link "GLPostEffects"
 #pragma link "GLScene"
 #pragma link "GLSimpleNavigation"
 #pragma link "GLVectorFileObjects"
@@ -24,6 +23,7 @@
 #pragma link "GLFileMS3D"
 #pragma link "GLFile3DS"
 
+#pragma link "GLSL.PostEffects"
 #pragma resource "*.dfm"
 TForm1 *Form1;
 //---------------------------------------------------------------------------

+ 3 - 3
Demos/CPP/glslshaders/PostShader/Unit1.h

@@ -18,21 +18,21 @@
 #include "GLGraph.hpp"
 #include "GLMaterial.hpp"
 #include "GLObjects.hpp"
-#include "GLPostEffects.hpp"
 #include "GLScene.hpp"
 #include "GLSimpleNavigation.hpp"
 #include "GLVectorFileObjects.hpp"
 #include "GLSceneViewer.hpp"
 #include "GLS.Utils.hpp"
 
-#include "GLSL.ShaderPosts.hpp"
-#include "GLS.CGPostTransformationShader.hpp"
+#include "GLSL.PostShaders.hpp"
+#include "GLSL.CGPostTransformationShader.hpp"
 
 // FileFormats
 #include "GLFileTGA.hpp"
 #include "GLFileMD2.hpp"
 #include "GLFileMS3D.hpp"
 #include "GLFile3DS.hpp"
+#include "GLSL.PostEffects.hpp"
 
 //---------------------------------------------------------------------------
 class TForm1 : public TForm

+ 1 - 0
Demos/Delphi/cgshaders/CGBombShader/uMainForm.dfm

@@ -254,6 +254,7 @@ object Form1: TForm1
       Camera = GLCamera1
       Buffer.AntiAliasing = aa4x
       FieldOfView = 148.195465087890600000
+      PenAsTouch = False
       Align = alClient
       TabOrder = 0
     end

+ 1 - 1
Demos/Delphi/cgshaders/CGBombShader/uMainForm.pas

@@ -24,7 +24,7 @@ uses
   GLVectorFileObjects,
   GLFile3DS,
   GLGraph,
-  GLS.cgBombShader,
+  GLSL.cgBombShader,
   GLMaterial,
   Scene.VectorGeometry,
 

+ 1 - 1
Demos/Delphi/cgshaders/cellshading/Unit1.pas

@@ -13,7 +13,7 @@ uses
 
   GLS.OpenGLx,
   Import.cgGL,
-  GLS.cgShader,
+  GLSL.CgShader,
 
   GLScene,
   Scene.VectorTypes,

+ 1 - 1
Demos/Delphi/cgshaders/simple/Unit1.pas

@@ -16,7 +16,7 @@ uses
 
   Import.cg,
   Import.cgGL,
-  GLS.cgShader,
+  GLSL.CgShader,
 
   GLScene,
   Scene.VectorTypes,

+ 1 - 1
Demos/Delphi/cgshaders/texturing/Unit1.pas

@@ -18,7 +18,7 @@ uses
   GLS.OpenGLx,
   Import.Cg,
   Import.cgGL,
-  GLS.cgShader,
+  GLSL.CgShader,
 
   GLScene,
   Scene.VectorTypes,

+ 4 - 4
Demos/Delphi/glslshaders/BumpShader/uMainForm.pas

@@ -24,9 +24,6 @@ uses
   GLGraph,
   GLGeomObjects,
   Scene.VectorGeometry,
-  GLSL.ShaderBump,
-  GLS.ShaderCustom,
-  GLSL.Shader,
   GLMaterial,
   GLCoordinates,
   GLBaseClasses,
@@ -36,7 +33,10 @@ uses
   FileDDSImage,
   GLFileMD2,
   GLFileSMD,
-  GLCrossPlatform;
+  GLCrossPlatform,
+  GLSL.Shader,
+  GLSL.CustomShader,
+  GLSL.BumpShaders;
 
 type
   TGLSLTestForm = class(TForm)

+ 2 - 2
Demos/Delphi/glslshaders/DiffuseSpecularShader/uMainForm.pas

@@ -25,8 +25,8 @@ uses
   GLVectorFileObjects,
 
   GLSL.Shader,
-  GLSL.ShaderDiffuseSpecular,
-  GLS.ShaderCustom,
+  GLSL.DiffuseSpecularShader,
+  GLSL.CustomShader,
   GLS.ShaderUser,
 
   GLSimpleNavigation,

+ 1 - 1
Demos/Delphi/glslshaders/GLSLShaderComponent/uMainForm.pas

@@ -23,7 +23,7 @@ uses
   GLGeomObjects,
   GLVectorFileObjects,
   GLSimpleNavigation,
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLCrossPlatform,
   GLMaterial,
   GLCoordinates,

+ 3 - 3
Demos/Delphi/glslshaders/PostShaders/UMainForm.pas

@@ -18,7 +18,7 @@ uses
   GLCadencer,
   GLSceneViewer,
   GLScene,
-  GLPostEffects,
+  GLSL.PostEffects,
   GLGraph,
   GLS.Utils,
   GLContext,
@@ -31,9 +31,9 @@ uses
   GLCrossPlatform,
   GLMaterial,
   GLBaseClasses,
-  GLSL.ShaderPosts,
+  GLSL.PostShaders,
 
-  GLS.cgPostTransformationShader,
+  GLSL.CgPostTransformationShader,
   GLFileMD2,
   GLFileMS3D,
   GLFile3DS;

+ 17 - 16
Demos/Delphi/glslshaders/ShadersLab/UMainForm.dfm

@@ -39,6 +39,7 @@ object MainForm: TMainForm
       Height = 496
       ActivePage = TabSheet1
       Align = alTop
+      MultiLine = True
       TabOrder = 0
       object TabSheet1: TTabSheet
         Caption = 'Fur'
@@ -368,9 +369,9 @@ object MainForm: TMainForm
         Caption = 'Lattice'
         ImageIndex = 1
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object lblLatticeScaleX: TLabel
           Left = 291
           Top = 41
@@ -603,9 +604,9 @@ object MainForm: TMainForm
         Caption = 'Erosion'
         ImageIndex = 2
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object Label1: TLabel
           Left = 8
           Top = 46
@@ -915,9 +916,9 @@ object MainForm: TMainForm
         Caption = 'Ivory'
         ImageIndex = 3
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object chkIvoryShader: TCheckBox
           Left = 16
           Top = 16
@@ -932,9 +933,9 @@ object MainForm: TMainForm
         Caption = 'Gootch'
         ImageIndex = 4
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object Label13: TLabel
           Left = 16
           Top = 47
@@ -1217,9 +1218,9 @@ object MainForm: TMainForm
         Caption = 'S.E.M'
         ImageIndex = 5
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object Label19: TLabel
           Left = 16
           Top = 44
@@ -1354,9 +1355,9 @@ object MainForm: TMainForm
         Caption = 'Displacement'
         ImageIndex = 6
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object Label21: TLabel
           Left = 24
           Top = 52
@@ -1670,9 +1671,9 @@ object MainForm: TMainForm
         Caption = 'Glass'
         ImageIndex = 7
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object Label56: TLabel
           Left = 11
           Top = 36
@@ -1860,9 +1861,9 @@ object MainForm: TMainForm
         Caption = 'Toon'
         ImageIndex = 8
         ExplicitLeft = 0
-        ExplicitTop = 0
+        ExplicitTop = 24
         ExplicitWidth = 0
-        ExplicitHeight = 0
+        ExplicitHeight = 468
         object Label64: TLabel
           Left = 7
           Top = 51

+ 1 - 1
Demos/Delphi/glslshaders/ShadersLab/UMainForm.pas

@@ -50,7 +50,7 @@ uses
   GLSimpleNavigation, 
   GLHUDObjects,
 
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLSL.ShaderFur,
   GLSL.ShaderLattice,
   GLSL.ShaderIvory,

+ 3 - 3
Demos/Delphi/rendering/phong/Unit1.pas

@@ -15,15 +15,15 @@ uses
   GLScene, GLObjects,
   GLTeapot,
   GLTexture,
-  GLS.ShaderPhong,
+  GLSL.AsmShader,
   GLSceneViewer,
   GLAsyncTimer, GLCadencer,
   GLS.ShaderCustom,
   GLCrossPlatform,
   GLMaterial, GLCoordinates,
   GLBaseClasses,
-  GLS.ShaderAsm,
-  GLS.ShaderPhong;
+  GLSL.AsmShader,
+  GLSL.AsmShader;
 
 type
   TForm1 = class(TForm)

+ 1 - 1
Demos/Delphi/specialsFX/posteffect/uMainForm.pas

@@ -24,7 +24,7 @@ uses
   GLCadencer,
   GLSceneViewer,
   GLSimpleNavigation,
-  GLPostEffects,
+  GLSL.PostEffects,
   GLCrossPlatform,
   GLMeshUtils,
   Scene.VectorGeometry,

+ 24 - 16
Demos/Delphi/utilities/recorder/Unit1.pas

@@ -3,12 +3,25 @@ unit Unit1;
 interface
 
 uses
-  System.Classes, System.SysUtils, System.Math,
-  Vcl.Forms, Vcl.Graphics, Vcl.Controls,
-  Vcl.ComCtrls, Vcl.ExtCtrls, Vcl.StdCtrls,
+  System.Classes, 
+  System.SysUtils, 
+  System.Math,
+  Vcl.Forms, 
+  Vcl.Graphics, 
+  Vcl.Controls,
+  Vcl.ComCtrls, 
+  Vcl.ExtCtrls, 
+  Vcl.StdCtrls,
   
-  GLScene, GLObjects, GLAsyncTimer,  GLCadencer, GLAVIRecorder, GLSceneViewer,
-  GLCrossPlatform, GLCoordinates, GLBaseClasses;
+  GLScene, 
+  GLObjects, 
+  GLAsyncTimer,  
+  GLCadencer, 
+  GLS.AVIRecorder, 
+  GLSceneViewer,
+  GLCrossPlatform, 
+  GLCoordinates, 
+  GLBaseClasses;
 
 type
   TForm1 = class(TForm)
@@ -33,16 +46,16 @@ type
     procedure AVIRecorder1PostProcessEvent(Sender: TObject;
       frame: TBitmap);
   private
-     
-     UserAbort : boolean;
-  public
-     
+      UserAbort : boolean;
   end;
 
 var
   Form1: TForm1;
 
+//-------------------------------------  
 implementation
+ public
+ 
 
 {$R *.DFM}
 
@@ -85,19 +98,14 @@ begin
    StaticText1.Visible:=false; // the FPS shown is not correct now,
                                // so just hide it for the time being.
    i:=0;
-
    Button1.enabled:=false;
    TrackBar.enabled:=false;
-
    try
       while (i<360) and not UserAbort do begin
          TrackBar.Position:=i;
          TrackBarChange(self);
-
          AVIRecorder1.AddAVIFrame;
-
          // you might want to update your progress bar here.
-
          Application.ProcessMessages; // so that our app. is not freezed,
                                       // and will accept user abort.
          inc(i);
@@ -110,7 +118,6 @@ begin
       Button1.enabled:=true;
       TrackBar.enabled:=true;
    end;
-
 end;
 
 procedure TForm1.AVIRecorder1PostProcessEvent(Sender: TObject;
@@ -118,7 +125,8 @@ procedure TForm1.AVIRecorder1PostProcessEvent(Sender: TObject;
 begin
    // PostProcess event is used to add a "watermark"
    // that will be in the AVI, but isn't visible on-screen
-   with frame.Canvas do begin
+   with frame.Canvas do 
+   begin
       Font.Color:=clAqua;
       Font.Name:='Courrier New';
       Font.Size:=24;

+ 1 - 1
Packages/GLScene_Cg_DT.dpk

@@ -38,6 +38,6 @@ requires
   GLScene_Cg_RT;
 
 contains
-  GLS.cgRegister in '..\Source\GLS.cgRegister.pas';
+  GLSL.CgRegister in '..\Source\GLSL.CgRegister.pas';
 
 end.

+ 1 - 1
Packages/GLScene_Cg_DT.dproj

@@ -118,7 +118,7 @@
         <DCCReference Include="VclSmp.dcp"/>
         <DCCReference Include="GLScene_DT.dcp"/>
         <DCCReference Include="GLScene_Cg_RT.dcp"/>
-        <DCCReference Include="..\Source\GLS.cgRegister.pas"/>
+        <DCCReference Include="..\Source\GLSL.CgRegister.pas"/>
         <RcCompile Include="..\Resources\GLSceneShaders.rc">
             <Form>GLSceneShaders.res</Form>
         </RcCompile>

+ 3 - 3
Packages/GLScene_Cg_RT.dpk

@@ -38,8 +38,8 @@ requires
 contains
   Import.cgGL in '..\Source\Import.cgGL.pas',
   Import.cg in '..\Source\Import.cg.pas',
-  GLS.cgShader in '..\Source\GLS.cgShader.pas',
-  GLS.cgShaderBomb in '..\Source\GLS.cgShaderBomb.pas',
-  GLS.cgShaderPostTransformation in '..\Source\GLS.cgShaderPostTransformation.pas';
+  GLSL.CgShader in '..\Source\GLSL.CgShader.pas',
+  GLSL.CgBombShader in '..\Source\GLSL.CgBombShader.pas',
+  GLSL.CgPostTransformationShader in '..\Source\GLSL.CgPostTransformationShader.pas';
 
 end.

+ 3 - 3
Packages/GLScene_Cg_RT.dproj

@@ -134,9 +134,9 @@
         <DCCReference Include="GLScene_RT.dcp"/>
         <DCCReference Include="..\Source\Import.cgGL.pas"/>
         <DCCReference Include="..\Source\Import.cg.pas"/>
-        <DCCReference Include="..\Source\GLS.cgShader.pas"/>
-        <DCCReference Include="..\Source\GLS.cgShaderBomb.pas"/>
-        <DCCReference Include="..\Source\GLS.cgShaderPostTransformation.pas"/>
+        <DCCReference Include="..\Source\GLSL.CgShader.pas"/>
+        <DCCReference Include="..\Source\GLSL.CgBombShader.pas"/>
+        <DCCReference Include="..\Source\GLSL.CgPostTransformationShader.pas"/>
         <BuildConfiguration Include="Debug">
             <Key>Cfg_2</Key>
             <CfgParent>Base</CfgParent>

+ 3 - 2
Packages/GLScene_DT.dpk

@@ -56,10 +56,11 @@ contains
   FPlugInManagerEditor in '..\Source\FPlugInManagerEditor.pas' {GLPlugInManagerEditorForm},
   FXCollectionEditor in '..\Source\FXCollectionEditor.pas' {GLXCollectionEditorForm},
   FInfo in '..\Source\FInfo.pas' {GLInfoForm},
-  XCollectionRegister in '..\Source\XCollectionRegister.pas',
-  GLS.SceneRegister in '..\Source\GLS.SceneRegister.pas';
+  GLS.SceneRegister in '..\Source\GLS.SceneRegister.pas',
+  XCollectionRegister in '..\Source\XCollectionRegister.pas';
 
 end.
 
 
 
+

+ 1 - 7
Packages/GLScene_DT.dproj

@@ -167,14 +167,8 @@
         <DCCReference Include="..\Source\FInfo.pas">
             <Form>GLInfoForm</Form>
         </DCCReference>
-        <DCCReference Include="..\Source\XCollectionRegister.pas"/>
         <DCCReference Include="..\Source\GLS.SceneRegister.pas"/>
-        <RcCompile Include="..\Resources\GLSceneObjects.rc">
-            <Form>GLSceneObjects.res</Form>
-        </RcCompile>
-        <RcCompile Include="..\Resources\GLScene.rc">
-            <Form>GLScene.res</Form>
-        </RcCompile>
+        <DCCReference Include="..\Source\XCollectionRegister.pas"/>
         <BuildConfiguration Include="Debug">
             <Key>Cfg_2</Key>
             <CfgParent>Base</CfgParent>

+ 13 - 14
Packages/GLScene_RT.dpk

@@ -47,16 +47,16 @@ contains
   FileQ3MD3 in '..\Source\FileQ3MD3.pas',
   FileB3D in '..\Source\FileB3D.pas',
   FileGL2 in '..\Source\FileGL2.pas',
-  FileLWObjects in '..\Source\FileLWObjects.pas',
+  Formats.FileLWObjects in '..\Source\Formats.FileLWObjects.pas',
   FileMD2 in '..\Source\FileMD2.pas',
   FileMD3 in '..\Source\FileMD3.pas',
   FileO3TCImage in '..\Source\FileO3TCImage.pas',
   FileOCT in '..\Source\FileOCT.pas',
   FileTGA in '..\Source\FileTGA.pas',
-  FileX in '..\Source\FileX.pas',
-  FileVFW in '..\Source\FileVFW.pas',
+  Formats.FileX in '..\Source\Formats.FileX.pas',
+  Formats.FileVFW in '..\Source\Formats.FileVFW.pas',
   FileVRMLParser in '..\Source\FileVRMLParser.pas',
-  GLAVIRecorder in '..\Source\GLAVIRecorder.pas',
+  GLS.AVIRecorder in '..\Source\GLS.AVIRecorder.pas',
   GLAnimatedSprite in '..\Source\GLAnimatedSprite.pas',
   GLAnimationUtils in '..\Source\GLAnimationUtils.pas',
   GLApplicationFileIO in '..\Source\GLApplicationFileIO.pas',
@@ -152,7 +152,7 @@ contains
   GLImageUtils in '..\Source\GLImageUtils.pas',
   GLImposter in '..\Source\GLImposter.pas',
   GLIsolines in '..\Source\GLIsolines.pas',
-  GLIsosurface in '..\Source\GLIsosurface.pas',
+  GLS.Isosurface in '..\Source\GLS.Isosurface.pas',
   GLJoystick in '..\Source\GLJoystick.pas',
   GLKeyboard in '..\Source\GLKeyboard.pas',
   GLLensFlare in '..\Source\GLLensFlare.pas',
@@ -189,7 +189,7 @@ contains
   GLPolyhedron in '..\Source\GLPolyhedron.pas',
   Scene.Polynomials in '..\Source\Scene.Polynomials.pas',
   GLPortal in '..\Source\GLPortal.pas',
-  GLPostEffects in '..\Source\GLPostEffects.pas',
+  GLSL.PostEffects in '..\Source\GLSL.PostEffects.pas',
   GLProcTextures in '..\Source\GLProcTextures.pas',
   GLProjectedTextures in '..\Source\GLProjectedTextures.pas',
   GLProxyObjects in '..\Source\GLProxyObjects.pas',
@@ -198,20 +198,19 @@ contains
   GLS.RandomHDS in '..\Source\GLS.RandomHDS.pas',
   GLRenderContextInfo in '..\Source\GLRenderContextInfo.pas',
   GLS.ArchiveManager in '..\Source\GLS.ArchiveManager.pas',
-  GLS.CrossXML in '..\Source\GLS.CrossXML.pas',
+  Scene.CrossXML in '..\Source\Scene.CrossXML.pas',
   GLS.Generics in '..\Source\GLS.Generics.pas',
-  GLS.ShaderAsm in '..\Source\GLS.ShaderAsm.pas',
-  GLS.ShaderBump in '..\Source\GLS.ShaderBump.pas',
+  GLSL.AsmShader in '..\Source\GLSL.AsmShader.pas',
   GLS.ShaderCel in '..\Source\GLS.ShaderCel.pas',
   GLS.ShaderCombiner in '..\Source\GLS.ShaderCombiner.pas',
-  GLS.ShaderCustom in '..\Source\GLS.ShaderCustom.pas',
+  GLSL.CustomShader in '..\Source\GLSL.CustomShader.pas',
   GLS.ShaderMultiMaterial in '..\Source\GLS.ShaderMultiMaterial.pas',
   GLS.ShaderOutline in '..\Source\GLS.ShaderOutline.pas',
-  GLS.ShaderPhong in '..\Source\GLS.ShaderPhong.pas',
+  GLSL.PhongShader in '..\Source\GLSL.PhongShader.pas',
   GLS.ShaderTextureSharing in '..\Source\GLS.ShaderTextureSharing.pas',
   GLS.ShaderUser in '..\Source\GLS.ShaderUser.pas',
-  GLSL.ShaderBump in '..\Source\GLSL.ShaderBump.pas',
-  GLSL.ShaderDiffuseSpecular in '..\Source\GLSL.ShaderDiffuseSpecular.pas',
+  GLSL.BumpShaders in '..\Source\GLSL.BumpShaders.pas',
+  GLSL.DiffuseSpecularShader in '..\Source\GLSL.DiffuseSpecularShader.pas',
   GLSL.ShaderErosion in '..\Source\GLSL.ShaderErosion.pas',
   GLSL.ShaderFur in '..\Source\GLSL.ShaderFur.pas',
   GLSL.ShaderGlass in '..\Source\GLSL.ShaderGlass.pas',
@@ -219,7 +218,7 @@ contains
   GLSL.ShaderIvory in '..\Source\GLSL.ShaderIvory.pas',
   GLSL.ShaderLattice in '..\Source\GLSL.ShaderLattice.pas',
   GLSL.ShaderParameter in '..\Source\GLSL.ShaderParameter.pas',
-  GLSL.ShaderPosts in '..\Source\GLSL.ShaderPosts.pas',
+  GLSL.PostShaders in '..\Source\GLSL.PostShaders.pas',
   GLSL.ProjectedTextures in '..\Source\GLSL.ProjectedTextures.pas',
   GLSL.ShaderSem in '..\Source\GLSL.ShaderSem.pas',
   GLSL.Shader in '..\Source\GLSL.Shader.pas',

+ 13 - 14
Packages/GLScene_RT.dproj

@@ -150,16 +150,16 @@
         <DCCReference Include="..\Source\FileQ3MD3.pas"/>
         <DCCReference Include="..\Source\FileB3D.pas"/>
         <DCCReference Include="..\Source\FileGL2.pas"/>
-        <DCCReference Include="..\Source\FileLWObjects.pas"/>
+        <DCCReference Include="..\Source\Formats.FileLWObjects.pas"/>
         <DCCReference Include="..\Source\FileMD2.pas"/>
         <DCCReference Include="..\Source\FileMD3.pas"/>
         <DCCReference Include="..\Source\FileO3TCImage.pas"/>
         <DCCReference Include="..\Source\FileOCT.pas"/>
         <DCCReference Include="..\Source\FileTGA.pas"/>
-        <DCCReference Include="..\Source\FileX.pas"/>
-        <DCCReference Include="..\Source\FileVFW.pas"/>
+        <DCCReference Include="..\Source\Formats.FileX.pas"/>
+        <DCCReference Include="..\Source\Formats.FileVFW.pas"/>
         <DCCReference Include="..\Source\FileVRMLParser.pas"/>
-        <DCCReference Include="..\Source\GLAVIRecorder.pas"/>
+        <DCCReference Include="..\Source\GLS.AVIRecorder.pas"/>
         <DCCReference Include="..\Source\GLAnimatedSprite.pas"/>
         <DCCReference Include="..\Source\GLAnimationUtils.pas"/>
         <DCCReference Include="..\Source\GLApplicationFileIO.pas"/>
@@ -255,7 +255,7 @@
         <DCCReference Include="..\Source\GLImageUtils.pas"/>
         <DCCReference Include="..\Source\GLImposter.pas"/>
         <DCCReference Include="..\Source\GLIsolines.pas"/>
-        <DCCReference Include="..\Source\GLIsosurface.pas"/>
+        <DCCReference Include="..\Source\GLS.Isosurface.pas"/>
         <DCCReference Include="..\Source\GLJoystick.pas"/>
         <DCCReference Include="..\Source\GLKeyboard.pas"/>
         <DCCReference Include="..\Source\GLLensFlare.pas"/>
@@ -292,7 +292,7 @@
         <DCCReference Include="..\Source\GLPolyhedron.pas"/>
         <DCCReference Include="..\Source\Scene.Polynomials.pas"/>
         <DCCReference Include="..\Source\GLPortal.pas"/>
-        <DCCReference Include="..\Source\GLPostEffects.pas"/>
+        <DCCReference Include="..\Source\GLSL.PostEffects.pas"/>
         <DCCReference Include="..\Source\GLProcTextures.pas"/>
         <DCCReference Include="..\Source\GLProjectedTextures.pas"/>
         <DCCReference Include="..\Source\GLProxyObjects.pas"/>
@@ -301,20 +301,19 @@
         <DCCReference Include="..\Source\GLS.RandomHDS.pas"/>
         <DCCReference Include="..\Source\GLRenderContextInfo.pas"/>
         <DCCReference Include="..\Source\GLS.ArchiveManager.pas"/>
-        <DCCReference Include="..\Source\GLS.CrossXML.pas"/>
+        <DCCReference Include="..\Source\Scene.CrossXML.pas"/>
         <DCCReference Include="..\Source\GLS.Generics.pas"/>
-        <DCCReference Include="..\Source\GLS.ShaderAsm.pas"/>
-        <DCCReference Include="..\Source\GLS.ShaderBump.pas"/>
+        <DCCReference Include="..\Source\GLSL.AsmShader.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderCel.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderCombiner.pas"/>
-        <DCCReference Include="..\Source\GLS.ShaderCustom.pas"/>
+        <DCCReference Include="..\Source\GLSL.CustomShader.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderMultiMaterial.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderOutline.pas"/>
-        <DCCReference Include="..\Source\GLS.ShaderPhong.pas"/>
+        <DCCReference Include="..\Source\GLSL.PhongShader.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderTextureSharing.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderUser.pas"/>
-        <DCCReference Include="..\Source\GLSL.ShaderBump.pas"/>
-        <DCCReference Include="..\Source\GLSL.ShaderDiffuseSpecular.pas"/>
+        <DCCReference Include="..\Source\GLSL.BumpShaders.pas"/>
+        <DCCReference Include="..\Source\GLSL.DiffuseSpecularShader.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderErosion.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderFur.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderGlass.pas"/>
@@ -322,7 +321,7 @@
         <DCCReference Include="..\Source\GLSL.ShaderIvory.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderLattice.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderParameter.pas"/>
-        <DCCReference Include="..\Source\GLSL.ShaderPosts.pas"/>
+        <DCCReference Include="..\Source\GLSL.PostShaders.pas"/>
         <DCCReference Include="..\Source\GLSL.ProjectedTextures.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderSem.pas"/>
         <DCCReference Include="..\Source\GLSL.Shader.pas"/>

+ 0 - 1
Source/FileTGA.pas

@@ -280,7 +280,6 @@ end;
 initialization
 //-------------------------------------------
 
-  { Register this Fileformat-Handler with GLScene }
   RegisterRasterFormat('tga', 'TARGA Image File', TGLTGAImage);
 
 end.

+ 2484 - 2484
Source/FileLWObjects.pas → Source/Formats.FileLWObjects.pas

@@ -1,2484 +1,2484 @@
-//
-// This unit is part of the GLScene Engine, http://glscene.org
-//
-
-unit FileLWObjects;
-
-(* =============================================================
-
-This unit provides functions, constants and now classes for use in
-working with Lightwave3D Object files.
-
-Chunk ID constants are defined for all of the Chunk IDs listed
-in the Lightwave 7.5 sdk.
-It is important to note that this is a constant work-in-progress
-and as such there are omissions and may be errors. Feedback and
-suggestions would be appreciated.
-There are two ways of using this unit. The first uses user-defines
-callbacks to handle parsing lwo chunk data. The second way uses
-object orientation.
-
-Loading LWO chunk data via callbacks
-A function is provided for loading a Lightwave object from a file.
-The Loader itself uses a callback mechanism for the loading of
-Lightwave object chunks. The callback is called for every chunk
-(with the exception of the FORM and LWOB or LWO2 chunks).
-
-The Chunk struct passed in the callback contains members for the
-chunk ID, chunk size and pointer to chunk data. This data is
-untouched internally so any parsing and numeric formatting
-is up to you. This provides maximum flexibility and allows you to
-handle the data that you need without loading the entire object
-into ram first.
-
-The chunk data memory is freed upon the return of the callback
-so do not keep a reference to the chunk data. Copy it to your own
-storage.
-
-function LoadLW0(const Filename: string; ReadProc: TLWOReadProc;
- UserData: Pointer): LongWord; cdecl;
-
- Filename:      The fully qualified filename of the file to be
-                loaded.
-
- ReadCallback:  The address of a TLWOReadCallback procedure
-                defined as:
-                TLWOReadCallback = procedure(Chunk: TLWChunk;
-                  UserData: Pointer); cdecl;
-                This procedure will be called for every chunk
-                encountered in the Lightwave object file. The
-                Chunk parameter is the chunk struct of the chunk
-                being loaded. UserData is the pointer supplied
-                in the original call to LoadLWO (see below).
-
- UserData:      A pointer to user supplied data to be passed
-                in the ReadCallback.
-
-A non-zero results indicates that the object file was parsed
-successfully.
-
-Loading LWO chunks via objects
-============================
-To load data from a lightwave object file, create an instance of
-TLWObjectFile and call its LoadFromFile method.
-
-The data can then be accessed with the Chunks array property and
-iterated in combination with the ChunkCount property.
-
-Chunk data is parsed and interfaced by descendents of the TLWChunk
-class. I have made handlers for the following chunk types:
-
-TLWLayr  Modeler Layer chunk
-TLWPnts  Points chunk
-TLWPols  Polygons chunk
-TLWPTag  Polygon tag mapping
-TLWSurf  Surface subchunk container
-TLWTags  Tags (Name tag strings for named items)
-TLWVMap  Vertex Mapping
-
-The data for chunks without handlers can be gotten at with the
-Data and Size properties of the TLWChunk. Data is a pointer to
-the start of the chunk data. This data is unparsed.
-Data is nil for descendents.
-
-
-This should provide enough to move geometry into your favourite
-delphi-based 3d engine.
-
-
-Making chunk handler objects
-============================
-
-All chunk types are derived from TLWChunk in the following manner:
-
-TLWChunk
-
-ex:
-
-TLWPTag        <- PTAG chunk type. polygon tag map.
-
-TLWParentChunk <- A base class for chunks that can contain other chunks.
-                 This is not necessarily how the data is stored in
-                 the file but more for ease of access to data.
- ex:
- TLWPnts <- PNTS chunk type (points)
- TLWLayr <- LAYR chunk type (modeler layer)
- TLWSurf <- SURF chunk type (constains surface attributes as sub chunks)
- TLWSubChunk <- A base class for chunks whose max data len is 65536 bytes.
- TLWDiff   <- DIFF subchunk type (diffuse surface parameter)
- TLWSpec   <- SPEC subchunk type (specularity surface parameter)...
- etc.
-
-Each descendent of TLWChunk or TLWSubChunk is required to override
-the GetID class function, the LoadData method and the Clear method
-to provide custom handling for chunktype data.
-
-ex:
-...
-type
-  TLWPnts = class (TLWParentChunk)
-  private
-    FPoints: TVEC12DynArray;
-    function GetCount: LongWord;
-    protected
-    procedure Clear; override;
-    procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord); override;
-  public
-    class function GetID: TID4; override;
-    function GetVMap(VMapID: TID4; out VMap: TLWVMap): boolean;
-    property Count: LongWord read GetCount;
-    property Points: TVEC12DynArray read FPoints;
-  end;
-...
-
-// Return the the chunk id that is the target of this handler
-
-class function TLWPnts.GetID: TID4;
-begin
-  result := ID_PNTS;
-end;
-
-// Load the point data - the stream is already positioned at the start of the chunk data
-
-procedure TLWPnts.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-begin
-  SetLength(FPoints,DataSize div 12); // allocate storage for DataSize div 12 points
-  ReadMotorolaNumber(AStream,@FPoints[0],4,DataSize div 4); // read the point data
-end;
-
-
-// Cleanup - Free any memory that you've allocated
-
-procedure TLWPnts.Clear;
-begin
-  SetLength(FPoints,0);
-end;
-
-
-Utility Functions
-=================
-A function is provided for converting an array of numbers between
-Motorola and Intel format (big endian <-> little endian). Converting
-only needs to be done for numeric types that are of 2 or 4 byte
-lengths.
-
-procedure ReverseByteOrder(ValueIn: Pointer; Size: integer; Count: integer = 1);
-
- ValueIn: The address of a number or array of numbers to have their
-          bytes swapped.
- Size:    The size in bytes of each numeric type.
- Count:   The count of numbers in the numbers array. The default
-          value is 1.
-
-Two routines are provided for reading and writing big endian
-(Motorola and misc other processor vendors ) numbers to and from a
-stream. These routines handle 2 and 4 byte numeric types and can
-also handle arrays.
-
-procedure ReadMotorolaNumber(Stream: TStream; Data: Pointer;
- ElementSize: integer; Count: integer = 1);
-
-function WriteMotorolaNumber(Stream: TStream; Data: Pointer;
- ElementSize: integer; Count: integer = 1): Integer;
-
-Each take a valid TStream descendent, a pointer to the numeric data,
-the element size of the data elements (either 2 or 4) and the array
-element count if sending an array. The default count is 1.
-
-Notes for improvement of this unit:
-
-- A version ID tag should be visible to all chunks in order to
- provide handling for Lightwave pre 6.0 object files.
-
-- Chunk type handlers should leave memory allocation to
- the base class (TLWChunk) and act more as an interface
- to the data pointed to by Data in TLWChunk. This would
- keep memory allocation very efficient and make implementing
- chunk handlers even easier.
-
-  Author:     Brian Johns [email protected]
-  Purpose:    Lightwave object support unit for Delphi.
-  Notes:      For the Lightwave Object File Format documentation please refer to
-  http://www.lightwave3d.com/developer.
-  Lightwave3D is a registered trademark of Newtek Incorporated.
-
-===================================================================== *)
-
-interface
-
-{$I GLScene.inc}
-
-uses
-  System.Classes,
-  System.SysUtils,
-  System.IOUtils,
-  System.Math,
-  Scene.VectorGeometry;
-
-type
-
-  TID4 = array [0 .. 3] of AnsiChar;
-  PID4 = ^TID4;
-  TID4DynArray = array of TID4;
-
-const
-  ID_NULL = '#0#0#0#0'; // NULL ID
-
-  ID_LWSC: TID4 = 'LWSC'; // Lightwave scene file
-  ID_FORM: TID4 = 'FORM'; // IFF Form
-  ID_LWOB: TID4 = 'LWOB'; // Lightwave Object version 1.0 - 5.x
-  ID_LWLO: TID4 = 'LWLO'; // Lightwave Layered Object
-  ID_LAYR: TID4 = 'LAYR'; // LAYER
-  ID_PNTS: TID4 = 'PNTS'; // Points chunk
-  ID_SRFS: TID4 = 'SRFS'; // Surface Names chunk
-  ID_POLS: TID4 = 'POLS'; // Polygons chunk
-  ID_CRVS: TID4 = 'CRVS'; // Curves chunk
-  ID_PCHS: TID4 = 'PCHS'; // Patches chunk
-  ID_SURF: TID4 = 'SURF'; // Surfaces chunk
-  ID_COLR: TID4 = 'COLR'; // Color chunk
-
-  ID_FLAG: TID4 = 'FLAG'; // Surface Flags
-
-  ID_LUMI: TID4 = 'LUMI'; // Luminosity
-  ID_DIFF: TID4 = 'DIFF'; // Diffuse
-  ID_SPEC: TID4 = 'SPEC'; // Specular
-  ID_REFL: TID4 = 'REFL'; // Reflective
-  ID_TRAN: TID4 = 'TRAN'; // Transparency
-
-  ID_VLUM: TID4 = 'VLUM'; // Luminosity
-  ID_VDIF: TID4 = 'VDIF'; // Diffuse
-  ID_VSPC: TID4 = 'VSPC'; // Specularity
-  ID_VRFL: TID4 = 'VRFL'; // Reflective
-  ID_VTRN: TID4 = 'VTRN'; // Transparency
-
-  ID_GLOS: TID4 = 'GLOS'; // Glossiness SmallInt
-
-  ID_SIDE: TID4 = 'SIDE'; // Sidedness
-
-  ID_RFLT: TID4 = 'RFLT'; // REFLECTION MODE (PRE 6.0)
-
-  ID_RFOP: TID4 = 'RFOP'; // REFLECTION OPTIONS
-  ID_RIMG: TID4 = 'RIMG'; // REFLECTION IMAGE
-  ID_RSAN: TID4 = 'RSAN'; // REFLECTION MAP SEAM ANGLE
-  ID_RIND: TID4 = 'RIND'; // REFRACTIVE INDEX
-  ID_EDGE: TID4 = 'EDGE'; // EDGE TRANSPARENCY THRESHOLD
-  ID_SMAN: TID4 = 'SMAN'; // SMOOTHING ANGLE RADIANS
-  ID_ALPH: TID4 = 'ALPH'; // ALPHA MODE
-  ID_CTEX: TID4 = 'CTEX'; // COLOR TEXTURE
-  ID_DTEX: TID4 = 'DTEX'; // DIFFUSE TEXTURE
-  ID_STEX: TID4 = 'STEX'; // SPECULAR TEXTURE
-  ID_RTEX: TID4 = 'RTEX'; // REFLECTIION TEXTURE
-  ID_TTEX: TID4 = 'TTEX'; // TRANSPARENCY TEXTURE
-  ID_LTEX: TID4 = 'LTEX'; // LUMINANCE TEXTURE
-  ID_BTEX: TID4 = 'BTEX'; // BUMP TEXTURE
-  ID_TFLG: TID4 = 'TFLG'; // TEXTURE FLAGS
-  ID_TSIZ: TID4 = 'TSIZ'; // TEXTURE SIZE
-  ID_TCTR: TID4 = 'TCTR'; // TEXTURE CENTER
-  ID_TFAL: TID4 = 'TFAL'; // TEXTURE FALLOFF
-  ID_TVEL: TID4 = 'TVAL'; // TEXTURE VALUE
-  ID_TREF: TID4 = 'TREF'; // TEXTURE REFERENCE
-  ID_TCLR: TID4 = 'TCLR'; // TEXTURE COLOR
-  ID_TVAL: TID4 = 'TVAL'; // TEXTURE VALUE
-  ID_TAMP: TID4 = 'TAMP'; // TEXTURE AMPLITUDE
-  ID_TFP0: TID4 = 'TFP0'; // TEXTURE PARAMETERS
-  ID_TFP1: TID4 = 'TFP1'; //
-  ID_TFP2: TID4 = 'TFP2'; //
-  ID_TIP0: TID4 = 'TIP0'; //
-  ID_TIP1: TID4 = 'TIP1'; //
-  ID_TIP2: TID4 = 'TIP2'; //
-  ID_TSP0: TID4 = 'TSP0'; //
-  ID_TSP1: TID4 = 'TSP1'; //
-  ID_TSP2: TID4 = 'TSP2'; //
-  ID_TFRQ: TID4 = 'TFRQ'; //
-  ID_TIMG: TID4 = 'TIMG'; // TEXTURE IMG
-  ID_TALP: TID4 = 'TALP'; //
-  ID_TWRP: TID4 = 'TWRP'; // TEXTURE WRAP
-  ID_TAAS: TID4 = 'TAAS'; //
-  ID_TOPC: TID4 = 'TOPC'; //
-  ID_SHDR: TID4 = 'SHDR'; //
-  ID_SDAT: TID4 = 'SDAT'; //
-  ID_IMSQ: TID4 = 'IMSQ'; // IMAGE SEQUENCE
-  ID_FLYR: TID4 = 'FLYR'; // FLYER SEQUENCE
-  ID_IMCC: TID4 = 'IMCC'; //
-
-  SURF_FLAG_LUMINOUS = 1;
-  SURF_FLAG_OUTLINE = 2;
-  SURF_FLAG_SMOOTHING = 4;
-  SURF_FLAG_COLORHIGHLIGHTS = 8;
-  SURF_FLAG_COLORFILTER = 16;
-  SURF_FLAG_OPAQUEEDGE = 32;
-  SURF_FLAG_TRANSPARENTEDGE = 64;
-  SURF_FLAG_SHARPTERMINATOR = 128;
-  SURF_FLAG_DOUBLESIDED = 256;
-  SURF_FLAG_ADDITIVE = 512;
-  SURF_FLAG_SHADOWALPHA = 1024;
-
-  CURV_CONTINUITY_FIRST = 1;
-  CURV_CONTINUITY_LAST = 2;
-
-  IMSQ_FLAG_LOOP = 1;
-  IMSQ_FLAG_INTERLACE = 2;
-
-  ID_LWO2: TID4 = 'LWO2'; // OBJECT
-  ID_VMAP: TID4 = 'VMAP'; // VERTEX MAP
-  ID_TAGS: TID4 = 'TAGS'; // TAGS?
-  ID_PTAG: TID4 = 'PTAG'; // POLYGON TAG MAP
-  ID_VMAD: TID4 = 'VMAD'; // DISCONTINUOUS VERTEX MAP
-  ID_ENVL: TID4 = 'ENVL'; // ENVELOPE
-  ID_CLIP: TID4 = 'CLIP'; // CLIP
-  ID_BBOX: TID4 = 'BBOX'; // BOUNDING BOX
-  ID_DESC: TID4 = 'DESC'; // DESCRIPTION
-  ID_TEXT: TID4 = 'TEXT'; // TEXT
-  ID_ICON: TID4 = 'ICON'; // ICON
-
-  ENVL_PRE: TID4 = 'PRE'#0; // PRE-BEHAVIOUR
-  ENVL_POST: TID4 = 'POST'; // POST
-  ENVL_KEY: TID4 = 'KEY'#0; // KEY
-  ENVL_SPAN: TID4 = 'SPAN'; // SPAN
-  ENVL_CHAN: TID4 = 'CHAN'; // CHAN
-  ENVL_NAME: TID4 = 'NAME'; // NAME
-
-  ID_STIL: TID4 = 'STIL'; // STILL IMAGE FILENAME
-  ID_ISEQ: TID4 = 'ISEQ'; // IMAGE SEQUENCE
-  ID_ANIM: TID4 = 'ANIM'; // PLUGIN ANIMATION
-  ID_STCC: TID4 = 'STCC'; // COLOR CYCLING STILL
-  ID_CONT: TID4 = 'CONT'; // CONTRAST
-  ID_BRIT: TID4 = 'BRIT'; // BRIGHTNESS
-  ID_SATR: TID4 = 'SATR'; // SATURATION
-  ID_HUE: TID4 = 'HUE'#0; // HUE
-  ID_GAMMA: TID4 = 'GAMM'; // GAMMA
-  ID_NEGA: TID4 = 'NEGA'; // NEGATIVE IMAGE
-  ID_IFLT: TID4 = 'IFLT'; // IMAGE PLUG-IN FILTER
-  ID_PFLT: TID4 = 'PFLT'; // PIXEL PLUG-IN FILTER
-
-  POLS_TYPE_FACE: TID4 = 'FACE'; // FACES
-  POLS_TYPE_CURV: TID4 = 'CURV'; // CURVE
-  POLS_TYPE_PTCH: TID4 = 'PTCH'; // PATCH
-  POLS_TYPE_MBAL: TID4 = 'MBAL'; // METABALL
-  POLS_TYPE_BONE: TID4 = 'BONE'; // SKELEGON?
-
-  VMAP_TYPE_PICK: TID4 = 'PICK'; // SELECTION SET
-  VMAP_TYPE_WGHT: TID4 = 'WGHT'; // WEIGHT MAP
-  VMAP_TYPE_MNVW: TID4 = 'MNVW'; // SUBPATCH WEIGHT MAP
-  VMAP_TYPE_TXUV: TID4 = 'TXUV'; // UV MAP
-  VMAP_TYPE_RGB: TID4 = 'RGB'#0; // RGB MAP
-  VMAP_TYPE_RGBA: TID4 = 'RGBA'; // RGBA MAP
-  VMAP_TYPE_MORF: TID4 = 'MORF'; // MORPH MAP: RELATIVE VERTEX DISPLACEMENT
-  VMAP_TYPE_SPOT: TID4 = 'SPOT'; // SPOT MAP: ABSOLUTE VERTEX POSITIONS
-
-  PTAG_TYPE_SURF: TID4 = 'SURF'; // SURFACE
-  PTAG_TYPE_PART: TID4 = 'PART'; // PARENT PART
-  PTAG_TYPE_SMGP: TID4 = 'SMGP'; // SMOOTH GROUP
-
-  PRE_POST_RESET = 0; // RESET
-  PRE_POST_CONSTANT = 1; // CONSTANT
-  PRE_POST_REPEAT = 2; // REPEAT
-  PRE_POST_OSCILLATE = 3; // OSCILLATE
-  PRE_POST_OFFSET = 4; // OFFSET REPEAT
-  PRE_POST_LINEAR = 5; // LINEAR
-
-  POLS_VCOUNT_MASK = $3FF;
-  POLS_FLAGS_MASK = $FC00;
-
-  SIDE_FRONT = 1;
-  SIDE_BACK = 2;
-  SIDE_FRONT_AND_BACK = SIDE_FRONT and SIDE_BACK;
-
-  RFOP_BACKDROP = 0;
-  RFOP_RAYTRACEANDBACKDROP = 1;
-  RFOP_SPHERICALMAP = 2;
-  RFOP_RAYTRACEANDSPHERICALMAP = 3;
-
-type
-  TI1 = ShortInt;
-  PI1 = ^TI1;
-
-  TI2 = SmallInt;
-  PI2 = ^TI2;
-
-  TI4 = LongInt;
-  PI4 = ^TI4;
-
-  TU1 = Byte;
-  PU1 = ^TU1;
-  TU1DynArray = array of TU1;
-
-  TU2 = Word;
-  PU2 = ^TU2;
-  TU2Array = array [0 .. 65534] of TU2;
-  PU2Array = ^TU2Array;
-  TU2DynArray = array of TU2;
-
-  TU4 = LongWord;
-  PU4 = ^TU4;
-  TU4Array = array [0 .. 65534] of TU4;
-  PU4Array = ^TU4Array;
-  TU4DynArray = array of TU4;
-
-  TF4 = Single;
-  PF4 = ^TF4;
-  TF4Array = array [0 .. 65534] of TF4;
-  PF4Array = ^TF4Array;
-  TF4DynArray = array of TF4;
-
-  TANG4 = TF4;
-  PANG4 = ^TANG4;
-
-  // TS0 = PAnsiChar;
-
-  TVec12 = array [0 .. 2] of TF4;
-  PVec12 = ^TVec12;
-
-  TVec12Array = array [0 .. 65534] of TVec12;
-  PVec12Array = ^TVec12Array;
-  TVec12DynArray = array of TVec12;
-
-  TColr12 = TVec12;
-  PColr12 = ^TColr12;
-
-  TColr12DynArray = array of TColr12;
-
-  TColr4 = array [0 .. 3] of TU1;
-  PColr4 = ^TColr4;
-
-  // Lightwave Chunk Struct - Used in TLWOReadCallback
-  PLWChunkRec = ^TLWChunkRec;
-
-  TLWChunkRec = record
-    id: TID4;
-    size: TU4;
-    data: Pointer;
-  end;
-
-  // Lightwave SubChunk Struct - Used in TLWOReadCallback
-  PLWSubChunkRec = ^TLWSubChunkRec;
-
-  TLWSubChunkRec = record
-    id: TID4;
-    size: TU2;
-    data: Pointer;
-  end;
-
-  TLWPolsInfo = record
-    norm: TVec12;
-    vnorms: TVec12DynArray;
-    surfid: TU2;
-  end;
-
-  TLWPolsInfoDynArray = array of TLWPolsInfo;
-
-  TLWPntsInfo = record
-    npols: TU2;
-    pols: TU2DynArray;
-  end;
-
-  TLWPntsInfoDynArray = array of TLWPntsInfo;
-
-  TLWPolsDynArray = TU2DynArray;
-
-  TLWPolyTagMapDynArray = TU2DynArray;
-
-  TLWPolyTagMap = record
-    poly: TU2;
-    tag: TU2;
-  end;
-
-  PLWPolyTagMap = ^TLWPolyTagMap;
-
-  // Value Map
-  TLWVertexMap = record
-    vert: TU2;
-    values: TF4DynArray;
-  end;
-
-  TLWVertexMapDynArray = array of TLWVertexMap;
-
-  TLWChunkList = class;
-  TLWParentChunk = class;
-
-  TLWChunk = class(TPersistent)
-  private
-    FData: Pointer;
-    FID: TID4;
-    FSize: TU4;
-    FParentChunk: TLWParentChunk;
-    FOwner: TLWChunkList;
-    function GetRootChunks: TLWChunkList;
-    function GetIndex: Integer;
-  protected
-    procedure Clear; virtual;
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); virtual;
-    procedure Loaded; virtual;
-  public
-    destructor Destroy; override;
-    class function GetID: TID4; virtual;
-    procedure LoadFromStream(AStream: TStream); virtual;
-    property data: Pointer read FData;
-    property id: TID4 read FID;
-    property size: TU4 read FSize;
-    // ParentChunk may be nil indicating this is a root chunk. ie. TLWLayr
-    property ParentChunk: TLWParentChunk read FParentChunk;
-    property RootChunks: TLWChunkList read GetRootChunks;
-    property Index: Integer read GetIndex;
-    property Owner: TLWChunkList read FOwner;
-  end;
-
-  TLWChunkClass = class of TLWChunk;
-
-  TLWSubChunk = class(TLWChunk)
-  public
-    procedure LoadFromStream(AStream: TStream); override;
-  end;
-
-  TLWChunkFind = procedure(AChunk: TLWChunk; Criteria: Pointer;
-    var Found: boolean);
-
-  TLWChunkList = class(TList)
-  private
-    FOwnsItems: boolean;
-    FOwner: TObject;
-    function GetItem(Index: Integer): TLWChunk;
-  protected
-    procedure Loaded; virtual;
-  public
-    constructor Create(AOwnsItems: boolean; AOwner: TObject);
-    destructor Destroy; override;
-    function Add(AChunk: TLWChunk): Integer;
-    procedure Clear; override;
-    procedure Delete(Index: Integer);
-    function FindChunk(ChunkFind: TLWChunkFind; Criteria: Pointer;
-      StartIndex: Integer = 0): Integer;
-    property Items[Index: Integer]: TLWChunk read GetItem; default;
-    property OwnsItems: boolean read FOwnsItems;
-    property Owner: TObject read FOwner;
-  end;
-
-  TLWParentChunk = class(TLWChunk)
-  private
-    FItems: TLWChunkList;
-    function GetItems: TLWChunkList;
-    function GetFloatParam(Param: TID4): Single;
-    function GetWordParam(Param: TID4): Word;
-    function GetVec3Param(Param: TID4): TVec12;
-    function GetLongParam(Param: TID4): LongWord;
-    function GetVXParam(Param: TID4): Word;
-  protected
-    function GetParamAddr(Param: TID4): Pointer; virtual;
-    procedure Clear; override;
-    procedure Loaded; override;
-  public
-    property Items: TLWChunkList read GetItems;
-    property ParamAddr[Param: TID4]: Pointer read GetParamAddr;
-    property FloatParam[Param: TID4]: Single read GetFloatParam;
-    property WordParam[Param: TID4]: Word read GetWordParam;
-    property LongParam[Param: TID4]: LongWord read GetLongParam;
-    property Vec3Param[Param: TID4]: TVec12 read GetVec3Param;
-    property VXParam[Param: TID4]: Word read GetVXParam;
-  end;
-
-  TLWVMap = class;
-
-  TLWPnts = class(TLWParentChunk)
-  private
-    FPnts: TVec12DynArray;
-    FPntsInfo: TLWPntsInfoDynArray;
-    function GetPntsCount: LongWord;
-    function AddPoly(PntIdx, PolyIdx: Integer): Integer;
-  protected
-    procedure Clear; override;
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-  public
-    class function GetID: TID4; override;
-    function GetVMap(VMapID: TID4; out VMap: TLWVMap): boolean;
-    property PntsCount: LongWord read GetPntsCount;
-    property Pnts: TVec12DynArray read FPnts;
-    property PntsInfo: TLWPntsInfoDynArray read FPntsInfo;
-  end;
-
-  TLWPols = class(TLWParentChunk)
-  private
-    FPolsType: TID4;
-    FPols: TLWPolsDynArray;
-    FPolsInfo: TLWPolsInfoDynArray;
-    FPolsCount: Integer;
-    function GetPolsByIndex(AIndex: TU2): Integer;
-    function GetIndiceCount: TU4;
-    function GetIndice(AIndex: Integer): TU2;
-    function GetPolsCount: Integer;
-    procedure CalcPolsNormals;
-    procedure CalcPntsNormals;
-  protected
-    procedure Clear; override;
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-    procedure Loaded; override;
-  public
-    class function GetID: TID4; override;
-    function GetPolsByPntIdx(VertIdx: TU2; var VertPolys: TU2DynArray): Integer;
-    property PolsByIndex[AIndex: TU2]: Integer read GetPolsByIndex;
-    property IndiceCount: TU4 read GetIndiceCount;
-    property Indices[AIndex: Integer]: TU2 read GetIndice;
-    property PolsType: TID4 read FPolsType;
-    property PolsCount: Integer read GetPolsCount;
-    property PolsInfo: TLWPolsInfoDynArray read FPolsInfo;
-  end;
-
-  TLWVMap = class(TLWChunk)
-  private
-    FDimensions: TU2;
-    FName: string;
-    FValues: TLWVertexMapDynArray;
-    FVMapType: TID4;
-    function GetValue(AIndex: TU2): TLWVertexMap;
-    function GetValueCount: Integer;
-  protected
-    procedure Clear; override;
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-  public
-    class function GetID: TID4; override;
-    property Dimensions: TU2 read FDimensions;
-    property Name: string read FName;
-    property Value[AIndex: TU2]: TLWVertexMap read GetValue;
-    property ValueCount: Integer read GetValueCount;
-    property VMapType: TID4 read FVMapType;
-  end;
-
-  TLWTags = class(TLWChunk)
-  private
-    FTags: TStrings;
-    function GetTags: TStrings;
-  protected
-    procedure Clear; override;
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-  public
-    destructor Destroy; override;
-    class function GetID: TID4; override;
-    function TagToName(tag: TU2): string;
-    property Tags: TStrings read GetTags;
-  end;
-
-  TLWSurf = class(TLWParentChunk)
-  private
-    FName: string;
-    FSource: string;
-    function GetSurfId: Integer;
-  protected
-    function GetParamAddr(Param: TID4): Pointer; override;
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-  public
-    destructor Destroy; override;
-    class function GetID: TID4; override;
-    property surfid: Integer read GetSurfId;
-    property Name: string read FName;
-    property Source: string read FSource;
-  end;
-
-  TLWLayr = class(TLWParentChunk)
-  private
-    FFlags: TU2;
-    FName: string;
-    FNumber: TU2;
-    FParent: TU2;
-    FPivot: TVec12;
-  protected
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-  public
-    destructor Destroy; override;
-    class function GetID: TID4; override;
-    property Flags: TU2 read FFlags;
-    property Name: string read FName;
-    property Number: TU2 read FNumber;
-    property Parent: TU2 read FParent;
-    property Pivot: TVec12 read FPivot;
-  end;
-
-  TLWPTag = class(TLWChunk)
-  private
-    FMapType: TID4;
-    FTagMaps: TLWPolyTagMapDynArray;
-    FTags: TU2DynArray;
-    function AddTag(Value: TU2): Integer;
-    function GetTag(AIndex: Integer): TU2;
-    function GetTagCount: Integer;
-    function GetTagMapCount: Integer;
-    function GetTagMaps(AIndex: Integer): TLWPolyTagMap;
-    procedure ValidateTagInfo;
-  protected
-    procedure Clear; override;
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-  public
-    constructor Create;
-    function GetPolsByTag(tag: TU2; var PolyIndices: TU2DynArray): Integer;
-    class function GetID: TID4; override;
-    property MapType: TID4 read FMapType;
-    property TagCount: Integer read GetTagCount;
-    property TagMapCount: Integer read GetTagMapCount;
-    property TagMaps[AIndex: Integer]: TLWPolyTagMap read GetTagMaps; default;
-    property Tags[AIndex: Integer]: TU2 read GetTag;
-  end;
-
-  TLWObjectFile = class(TObject)
-  private
-    FChunks: TLWChunkList;
-    FFileName: string;
-    function GetChunks: TLWChunkList;
-    function GetCount: Integer;
-    function GetSurfaceByName(Index: string): TLWSurf;
-    function GetSurfaceByTag(Index: TU2): TLWSurf;
-  public
-    constructor Create;
-    destructor Destroy; override;
-    function TagToName(tag: TU2): string;
-    procedure LoadFromFile(const AFilename: string);
-    procedure LoadFromStream(AStream: TStream);
-    property ChunkCount: Integer read GetCount;
-    property Chunks: TLWChunkList read GetChunks;
-    property FileName: string read FFileName;
-    property SurfaceByName[Index: string]: TLWSurf read GetSurfaceByName;
-    property SurfaceByTag[Index: TU2]: TLWSurf read GetSurfaceByTag;
-  end;
-
-  TLWClip = class(TLWParentChunk)
-  private
-    FClipIndex: TU4;
-  protected
-    procedure LoadData(AStream: TStream;
-      DataStart, DataSize: LongWord); override;
-  public
-    class function GetID: TID4; override;
-    property ClipIndex: TU4 read FClipIndex;
-  end;
-
-  TLWContentNotify = procedure(Sender: TObject; var Content: string) of object;
-
-  TLWContentDir = class
-  private
-    FSubDirs: TStrings;
-    FRoot: string;
-    function GetSubDirs: TStrings;
-    procedure SetRoot(const Value: string);
-    procedure SetSubDirs(const Value: TStrings);
-    // function ContentSearch(AFilename: string): string;
-  public
-    destructor Destroy; override;
-    function FindContent(AFilename: string): string;
-    property Root: string read FRoot write SetRoot;
-    property SubDirs: TStrings read GetSubDirs write SetSubDirs;
-  end;
-
-  TLWOReadCallback = procedure(Chunk: TLWChunkRec; data: Pointer); cdecl;
-
-procedure RegisterChunkClass(ChunkClass: TLWChunkClass);
-
-function LoadLW0FromStream(Stream: TStream; ReadCallback: TLWOReadCallback;
-  UserData: Pointer): LongWord; cdecl;
-function LoadLWOFromFile(const AFilename: string;
-  ReadCallback: TLWOReadCallback; UserData: Pointer): LongWord;
-
-procedure ReadMotorolaNumber(Stream: TStream; data: Pointer;
-  ElementSize: Integer; Count: Integer = 1);
-function WriteMotorolaNumber(Stream: TStream; data: Pointer;
-  ElementSize: Integer; Count: Integer = 1): Integer;
-
-function ReadS0(Stream: TStream; out Str: string): Integer;
-procedure WriteS0(Stream: TStream; data: string);
-
-procedure WriteU4AsVX(Stream: TStream; data: Pointer; Count: Integer);
-function ReadVXAsU4(Stream: TStream; data: Pointer; Count: Integer = 1)
-  : Integer;
-
-procedure ReverseByteOrder(ValueIn: Pointer; size: Integer; Count: Integer = 1);
-
-function ToDosPath(const Path: string): string;
-function ToUnixPath(const Path: string): string;
-
-function ID4ToInt(const id: TID4): Integer;
-
-// ChunkFind procedures
-procedure FindChunkById(AChunk: TLWChunk; data: Pointer; var Found: boolean);
-procedure FindSurfaceByName(AChunk: TLWChunk; AName: Pointer;
-  var Found: boolean);
-procedure FindSurfaceByTag(AChunk: TLWChunk; ATag: Pointer; var Found: boolean);
-
-procedure FindVMapByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
-procedure FindClipByClipIndex(AChunk: TLWChunk; AIndex: Pointer;
-  var Found: boolean);
-
-function GetContentDir: TLWContentDir;
-
-// --------------------------------------------------------------------
-implementation
-// --------------------------------------------------------------------
-
-type
-  PWord = ^Word;
-  PLongWord = ^LongWord;
-
-var
-  ChunkClasses: TList;
-  ContentDir: TLWContentDir;
-
-function ToDosPath(const Path: string): string;
-var
-  i: Integer;
-begin
-  result := Path;
-  for i := 1 to Length(result) do
-    if result[i] = '/' then
-      result[i] := '\';
-end;
-
-function ToUnixPath(const Path: string): string;
-var
-  i: Integer;
-begin
-  result := Path;
-  for i := 1 to Length(result) do
-    if result[i] = '\' then
-      result[i] := '/';
-end;
-
-function GetContentDir: TLWContentDir;
-begin
-  if ContentDir = nil then
-    ContentDir := TLWContentDir.Create;
-  result := ContentDir;
-end;
-
-procedure FindChunkById(AChunk: TLWChunk; data: Pointer; var Found: boolean);
-begin
-  if AChunk.FID = PID4(data)^ then
-    Found := true
-  else
-    Found := false;
-end;
-
-procedure FindClipByClipIndex(AChunk: TLWChunk; AIndex: Pointer;
-  var Found: boolean);
-begin
-  if (AChunk is TLWClip) and (TLWClip(AChunk).ClipIndex = PU2(AIndex)^) then
-    Found := true;
-end;
-
-procedure FindSurfaceByName(AChunk: TLWChunk; AName: Pointer;
-  var Found: boolean);
-begin
-  if (AChunk is TLWSurf) and (TLWSurf(AChunk).Name = PString(AName)^) then
-    Found := true;
-end;
-
-procedure FindSurfaceByTag(AChunk: TLWChunk; ATag: Pointer; var Found: boolean);
-begin
-  if (AChunk is TLWSurf) and (TLWSurf(AChunk).surfid = PU2(ATag)^) then
-    Found := true;
-end;
-
-procedure FindVMapByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
-begin
-  if (AChunk is TLWVMap) and (TLWVMap(AChunk).Name = PString(AName)^) then
-    Found := true;
-end;
-
-function VecAdd(v1, v2: TVec12): TVec12;
-begin
-  result[0] := v1[0] + v2[0];
-  result[1] := v1[1] + v2[1];
-  result[2] := v1[2] + v2[2];
-end;
-
-function VecSub(v1, v2: TVec12): TVec12;
-begin
-  result[0] := v1[0] - v2[0];
-  result[1] := v1[1] - v2[1];
-  result[2] := v1[2] - v2[2];
-end;
-
-function VecCross(v1, v2: TVec12): TVec12;
-begin
-  result[0] := v1[1] * v2[2] - v1[2] * v2[1];
-  result[1] := v1[2] * v2[0] - v1[0] * v2[2];
-  result[2] := v1[0] * v2[1] - v1[1] * v2[0];
-end;
-
-function VecDot(v1, v2: TVec12): TF4;
-begin
-  result := v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
-end;
-
-function VecNorm(v: TVec12): TVec12;
-var
-  mag: TF4;
-begin
-  mag := Sqrt(VecDot(v, v));
-
-  if mag > 0 then
-    mag := 1 / mag;
-
-  result[0] := v[0] * mag;
-  result[1] := v[1] * mag;
-  result[2] := v[2] * mag;
-end;
-
-function CalcPlaneNormal(v1, v2, v3: TVec12): TVec12;
-var
-  e1, e2: TVec12;
-begin
-  e1 := VecSub(v2, v1);
-  e2 := VecSub(v3, v1);
-  result := VecCross(e1, e2);
-  result := VecNorm(result);
-end;
-
-procedure FindSurfByName(Chunk: TLWChunk; var Found: boolean);
-begin
-
-end;
-
-(*-----------------------------------------------------------------------------
-  Procedure: GetChunkClasses
-  Date:      08-Aug-2002
-  Arguments: None
-  Result:    TClassList
-
-  Singleton access for the chunk class list.
-  -----------------------------------------------------------------------------*)
-function GetChunkClasses: TList;
-begin
-  if ChunkClasses = nil then
-    ChunkClasses := TList.Create;
-  result := ChunkClasses;
-end;
-
-procedure UnRegisterChunkClasses;
-var
-  i: Integer;
-begin
-  with GetChunkClasses do
-    for i := 0 to Count - 1 do
-      UnregisterClass(TPersistentClass(Items[i]));
-end;
-
-(*-----------------------------------------------------------------------------
-  Procedure: RegisterChunkClass
-  Date:      08-Aug-2002
-  Arguments: ChunkClass: TLWChunkClass
-  Result:    None
-
-  Adds a user defined chunk class to the chunk class list.
-  -----------------------------------------------------------------------------*)
-procedure RegisterChunkClass(ChunkClass: TLWChunkClass);
-begin
-  GetChunkClasses.Add(ChunkClass);
-  // if FindClass(ChunkClass.ClassName) <> nil then
-  // UnRegisterClass(ChunkClass);
-  // RegisterClass(ChunkClass);
-end;
-
-(*-----------------------------------------------------------------------------
-  Procedure: GetChunkClass
-  Date:      08-Aug-2002
-  Arguments: ChunkID: TID4
-  Result:    TLWChunkClass
-
-  Returns the chunk class associated with ChunkID.
-  -----------------------------------------------------------------------------*)
-function GetChunkClass(ChunkID: TID4; ADefault: TLWChunkClass): TLWChunkClass;
-var
-  i: Integer;
-begin
-
-  if ADefault = nil then
-    result := TLWChunk
-  else
-    result := ADefault;
-
-  for i := 0 to ChunkClasses.Count - 1 do
-  begin
-
-    if TLWChunkClass(ChunkClasses.Items[i]).GetID = ChunkID then
-    begin
-
-      result := TLWChunkClass(ChunkClasses.Items[i]);
-      Exit;
-
-    end;
-
-  end;
-
-end;
-
-(*-----------------------------------------------------------------------------
-  Procedure: Tokenize
-  Date:      08-Aug-2002
-  Arguments: const Src: string; Delimiter: Char; Dst: TStrings
-  Result:    None
-
-  Breaks up a string into TStrings items when the Delimiter character is
-  encountered.
-  -----------------------------------------------------------------------------*)
-procedure Tokenize(const Src: string; Delimiter: Char; Dst: TStrings);
-var
-  i, L, SL: Integer;
-  SubStr: string;
-begin
-  if Dst = nil then
-    Exit;
-
-  L := Length(Src);
-  if (L = 0) or (Dst = nil) then
-    Exit;
-  SubStr := '';
-  for i := 1 to L do
-  begin
-    if (Src[i] <> Delimiter) then
-      SubStr := SubStr + Src[i]
-    else
-    begin
-      SL := Length(SubStr);
-      if SL > 0 then
-      begin
-        Dst.Add(SubStr);
-        SubStr := '';
-      end;
-    end;
-  end;
-  if Length(SubStr) > 0 then
-    Dst.Add(SubStr);
-end;
-
-(*-----------------------------------------------------------------------------
-  Procedure: LoadLW0FromStream
-  Date:      08-Aug-2002
-  Arguments: Stream: TStream; ReadCallback: TLWOReadCallback; UserData: Pointer
-  Result:    LongWord
-  -----------------------------------------------------------------------------*)
-function LoadLW0FromStream(Stream: TStream; ReadCallback: TLWOReadCallback;
-  UserData: Pointer): LongWord;
-var
-  Chunk: TLWChunkRec;
-  CurId: TID4;
-  StartPos, CurSize: TU4;
-
-begin
-  try
-    Stream.Read(CurId, 4);
-
-    ReadMotorolaNumber(Stream, @CurSize, 4);
-
-    if UpperCase(string(CurId)) = 'FORM' then
-    begin
-      Stream.Read(CurId, 4);
-    end
-    else
-      raise Exception.Create
-        ('Invalid magic number. Not a valid Lightwave Object');
-    with Stream do
-      while Position < size do
-      begin
-        Read(Chunk, 8);
-        ReverseByteOrder(@Chunk.size, 4);
-        StartPos := Position;
-        GetMem(Chunk.data, Chunk.size);
-        Stream.Read(Chunk.data^, Chunk.size);
-        if Assigned(ReadCallback) then
-          ReadCallback(Chunk, UserData);
-        FreeMem(Chunk.data, Chunk.size);
-        Position := StartPos + Chunk.size + (StartPos + Chunk.size) mod 2;
-      end;
-    Stream.Free;
-    result := High(LongWord);
-  except
-    On E: Exception do
-    begin
-      Stream.Free;
-      result := 0;
-    end;
-  end;
-end;
-
-function LoadLWOFromFile(const AFilename: String;
-  ReadCallback: TLWOReadCallback; UserData: Pointer): LongWord;
-var
-  Stream: TStream;
-begin
-  Stream := TFileStream.Create(AFilename, fmOpenRead);
-  try
-    result := LoadLW0FromStream(Stream, ReadCallback, UserData);
-  finally
-    Stream.Free;
-  end;
-end;
-
-procedure ReverseByteOrder(ValueIn: Pointer; size: Integer; Count: Integer = 1);
-var
-  W: Word;
-  pB: PByte;
-  Blo, Bhi: Byte;
-  L: LongWord;
-  i: Integer;
-begin
-  i := 0;
-
-  case size of
-    2:
-      begin
-
-        while i < Count do
-        begin
-          W := PU2Array(ValueIn)^[i];
-
-          pB := @W;
-          Blo := pB^;
-          Inc(pB);
-          Bhi := pB^;
-          pB^ := Blo;
-          Dec(pB);
-          pB^ := Bhi;
-          PU2Array(ValueIn)^[i] := W;
-
-          Inc(i);
-        end;
-      end;
-
-    4:
-      begin
-        while i < Count do
-        begin
-          L := PU4Array(ValueIn)^[i];
-          pB := @W;
-          Blo := pB^;
-          Inc(pB);
-          Bhi := pB^;
-          pB^ := Blo;
-          Dec(pB);
-          pB^ := Bhi;
-          PU4Array(ValueIn)^[i] := L;
-
-          Inc(i);
-        end;
-      end;
-  else
-    raise Exception.Create('Lightwave.ReverseByteOrder: Invalid Size = ' +
-      IntToStr(size));
-  end;
-end;
-
-procedure ReadMotorolaNumber(Stream: TStream; data: Pointer;
-  ElementSize: Integer; Count: Integer = 1);
-begin
-  Stream.Read(data^, Count * ElementSize);
-
-  if (ElementSize = 2) or (ElementSize = 4) then
-    ReverseByteOrder(data, ElementSize, Count);
-end;
-
-function WriteMotorolaNumber(Stream: TStream; data: Pointer;
-  ElementSize: Integer; Count: Integer = 1): Integer;
-var
-  TempData: Pointer;
-begin
-  result := 0;
-  if data <> nil then
-  begin
-    TempData := AllocMem(ElementSize * Count);
-    try
-      if (ElementSize = 2) or (ElementSize = 4) then
-        ReverseByteOrder(TempData, ElementSize, Count);
-      result := Stream.Write(data, Count * ElementSize);
-    except
-      on E: Exception do
-      begin
-        FreeMem(TempData, Count * ElementSize);
-        raise;
-      end;
-    end;
-  end;
-end;
-
-function ReadS0(Stream: TStream; out Str: string): Integer;
-var
-  Buf: array [0 .. 1] of AnsiChar;
-  StrBuf: string;
-begin
-  Stream.Read(Buf, 2);
-  StrBuf := '';
-  while Buf[1] <> #0 do
-  begin
-    StrBuf := StrBuf + string(Buf);
-    Stream.Read(Buf, 2);
-  end;
-
-  if Buf[0] <> #0 then
-    StrBuf := StrBuf + Char(Buf[0]);
-
-  Str := Copy(StrBuf, 1, Length(StrBuf));
-  result := Length(Str) + 1;
-  result := result + (result mod 2);
-end;
-
-function ValueOfVX(VX: Pointer): TU4;
-var
-  TmpU2: TU2;
-  TmpU4: TU4;
-begin
-  if PU1(VX)^ = $FF then
-  begin
-    TmpU4 := TU4(PU1(VX)^) and $FFFFFFF0;
-    ReverseByteOrder(@TmpU4, 4);
-  end
-  else
-  begin
-    TmpU2 := TU2(PU2(VX)^);
-    ReverseByteOrder(@TmpU2, 2);
-    TmpU4 := TmpU2;
-  end;
-  result := TmpU4;
-end;
-
-function ReadVXAsU4(Stream: TStream; data: Pointer; Count: Integer = 1)
-  : Integer;
-var
-  i, ReadCount: Integer;
-  BufByte: Byte;
-  TempU2: TU2;
-begin
-  ReadCount := 0;
-  for i := 0 to Count - 1 do
-  begin
-
-    Stream.Read(BufByte, 1);
-    Stream.Position := Stream.Position - 1;
-
-    if BufByte = 255 then
-    begin
-      Stream.Read(data^, SizeOf(TU4));
-      PU4Array(data)^[i] := PU4Array(data)^[i] and $FFFFFFF0;
-      ReverseByteOrder(data, SizeOf(TU4));
-      Inc(ReadCount, 4);
-    end
-    else
-    begin
-      Stream.Read(TempU2, SizeOf(TU2));
-      ReverseByteOrder(@TempU2, SizeOf(TU2));
-      PU4Array(data)^[i] := TempU2;
-      Inc(ReadCount, 2);
-    end;
-
-  end;
-  result := ReadCount;
-end;
-
-function ReadVXAsU2(Stream: TStream; data: Pointer; Count: Integer = 1)
-  : Integer;
-var
-  i, ReadCount: Integer;
-  BufByte: Byte;
-  TempU2: TU2;
-begin
-  ReadCount := 0;
-  for i := 0 to Count - 1 do
-  begin
-    Stream.Read(BufByte, 1);
-    Stream.Position := Stream.Position - 1;
-    if BufByte = 255 then
-    begin
-      Stream.Position := Stream.Position + 4;
-      PU2Array(data)^[i] := 0;
-      Inc(ReadCount, 4);
-    end
-    else
-    begin
-      Stream.Read(TempU2, SizeOf(TU2));
-      ReverseByteOrder(@TempU2, SizeOf(TU2));
-      PU2Array(data)^[i] := TempU2;
-      Inc(ReadCount, 2);
-    end;
-  end;
-  result := ReadCount;
-end;
-
-procedure WriteS0(Stream: TStream; data: string);
-begin
-  // ToDo: WriteS0
-end;
-
-procedure WriteU4AsVX(Stream: TStream; data: Pointer; Count: Integer);
-var
-  i: Integer;
-  TempU2: TU2;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    if PU4Array(data)^[i] < 65280 then
-    begin
-      TempU2 := PU4Array(data)^[i];
-      WriteMotorolaNumber(Stream, @TempU2, SizeOf(TU2));
-    end
-    else
-      WriteMotorolaNumber(Stream, data, SizeOf(TU4));
-  end;
-end;
-
-type
-  PInteger = ^Integer;
-
-function ID4ToInt(const id: TID4): Integer;
-var
-  TmpId: AnsiString;
-begin
-
-  TmpId := id;
-
-  TmpId := AnsiString(UpperCase(string(id)));
-
-  result := PInteger(@TmpId)^;
-
-end;
-
-(*********************************** TLWChunk ********************************)
-
-destructor TLWChunk.Destroy;
-begin
-  Clear;
-  inherited;
-end;
-
-procedure TLWChunk.Clear;
-begin
-  FreeMem(FData, FSize);
-  FSize := 0;
-  FData := nil;
-end;
-
-class function TLWChunk.GetID: TID4;
-begin
-  result := #0#0#0#0;
-end;
-
-procedure TLWChunk.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-begin
-  GetMem(FData, DataSize);
-  AStream.Read(PByteArray(FData)^[0], DataSize);
-end;
-
-procedure TLWChunk.LoadFromStream(AStream: TStream);
-var
-  DataStart: Integer;
-  DataSize: TU4;
-begin
-  with AStream do
-  begin
-
-    ReadMotorolaNumber(AStream, @DataSize, 4);
-
-    DataStart := Position;
-
-    FSize := DataSize;
-
-    LoadData(AStream, DataStart, DataSize);
-
-    Position := Cardinal(DataStart) + DataSize +
-      (Cardinal(DataStart) + DataSize) mod 2;
-
-  end;
-end;
-
-
-(********************************* TLWChunkList *******************************)
-
-constructor TLWChunkList.Create(AOwnsItems: boolean; AOwner: TObject);
-begin
-  inherited Create;
-  FOwnsItems := AOwnsItems;
-  FOwner := AOwner;
-end;
-
-destructor TLWChunkList.Destroy;
-begin
-  Clear;
-  inherited;
-end;
-
-procedure TLWChunkList.Clear;
-begin
-  while Count > 0 do
-    Delete(Count - 1);
-  inherited;
-end;
-
-procedure TLWChunkList.Delete(Index: Integer);
-begin
-  if FOwnsItems then
-    Items[Index].Free;
-  inherited Delete(Index);
-end;
-
-function TLWChunkList.GetItem(Index: Integer): TLWChunk;
-begin
-  result := TLWChunk(inherited Items[Index]);
-end;
-
-(******************************** TLWObjectFile *******************************)
-
-constructor TLWObjectFile.Create;
-begin
-
-  inherited;
-
-end;
-
-destructor TLWObjectFile.Destroy;
-begin
-
-  FreeAndNil(FChunks);
-
-  inherited;
-
-end;
-
-function TLWObjectFile.GetChunks: TLWChunkList;
-begin
-  if FChunks = nil then
-    FChunks := TLWChunkList.Create(true, Self);
-  result := FChunks;
-end;
-
-function TLWObjectFile.GetCount: Integer;
-begin
-  result := Chunks.Count;
-end;
-
-function TLWObjectFile.GetSurfaceByName(Index: string): TLWSurf;
-var
-  SurfIdx: Integer;
-begin
-  SurfIdx := Chunks.FindChunk(@FindSurfaceByName, @Index, 0);
-  if SurfIdx <> -1 then
-    result := TLWSurf(Chunks[SurfIdx])
-  else
-    result := nil;
-end;
-
-function TLWObjectFile.GetSurfaceByTag(Index: TU2): TLWSurf;
-var
-  TagName: string;
-begin
-  TagName := TagToName(Index);
-  result := SurfaceByName[TagName];
-end;
-
-procedure TLWObjectFile.LoadFromFile(const AFilename: string);
-var
-  Stream: TMemoryStream;
-begin
-
-  Stream := TMemoryStream.Create;
-  try
-    Stream.LoadFromFile(AFilename);
-
-    LoadFromStream(Stream);
-    Stream.Free;
-    FFileName := AFilename;
-  except
-    on E: Exception do
-    begin
-      Stream.Free;
-      raise;
-    end;
-  end;
-
-end;
-
-procedure TLWObjectFile.LoadFromStream(AStream: TStream);
-var
-  CurId: TID4;
-  CurSize: LongWord;
-  CurPnts, CurPols, CurItems: TLWChunkList;
-begin
-  CurPols := nil;
-  CurPnts := nil;
-
-  AStream.Read(CurId, 4);
-
-  ReadMotorolaNumber(AStream, @CurSize, 4);
-
-  if UpperCase(string(CurId)) = 'FORM' then
-  begin
-
-    AStream.Read(CurId, 4);
-
-    if CurId <> 'LWO2' then
-      raise Exception.Create
-        ('Only Version 6.0+ version objects are supported.');
-
-  end
-  else
-    raise Exception.Create
-      ('Invalid magic number. Not a valid Lightwave Object');
-
-  CurItems := Chunks;
-
-  while AStream.Position < AStream.size do
-  begin
-    AStream.Read(CurId, 4);
-
-    if (CurId = ID_PTAG) then
-    begin
-      CurPols.Add(GetChunkClass(CurId, TLWChunk).Create);
-
-      with CurPols[CurPols.Count - 1] do
-      begin
-        FID := CurId;
-        LoadFromStream(AStream);
-      end;
-    end
-    else if (CurId = ID_VMAP) or (CurId = ID_VMAD) then
-    begin
-      CurPnts.Add(GetChunkClass(CurId, TLWChunk).Create);
-      with CurPnts[CurPnts.Count - 1] do
-      begin
-        FID := CurId;
-        LoadFromStream(AStream);
-      end;
-    end
-    else
-    begin
-      if (CurId = ID_LAYR) or (CurId = ID_SURF) or (CurId = ID_TAGS) or
-        (CurId = ID_CLIP) then
-        CurItems := Chunks;
-      CurItems.Add(GetChunkClass(CurId, TLWChunk).Create);
-      with CurItems[CurItems.Count - 1] do
-      begin
-        FID := CurId;
-        LoadFromStream(AStream);
-      end;
-
-    end;
-
-    if CurId = ID_LAYR then
-      CurItems := TLWParentChunk(CurItems[CurItems.Count - 1]).Items
-    else if CurId = ID_POLS then
-      CurPols := TLWParentChunk(CurItems[CurItems.Count - 1]).Items
-    else if CurId = ID_PNTS then
-      CurPnts := TLWParentChunk(CurItems[CurItems.Count - 1]).Items;
-  end;
-  Chunks.Loaded;
-end;
-
-(*********************************** TLWPnts **********************************)
-
-function TLWPnts.AddPoly(PntIdx, PolyIdx: Integer): Integer;
-var
-  i, L: Integer;
-begin
-  // DONE: Pnts.AddPoly
-
-  for i := 0 to FPntsInfo[PntIdx].npols - 1 do
-  begin
-    if FPntsInfo[PntIdx].pols[i] = PolyIdx then
-    begin
-      result := i;
-      Exit;
-    end;
-  end;
-
-  L := Length(FPntsInfo[PntIdx].pols);
-  SetLength(FPntsInfo[PntIdx].pols, L + 1);
-  FPntsInfo[PntIdx].npols := L + 1;
-  FPntsInfo[PntIdx].pols[L] := PolyIdx;
-  result := L;
-end;
-
-procedure TLWPnts.Clear;
-var
-  i: Integer;
-begin
-  for i := 0 to PntsCount - 1 do
-    SetLength(FPntsInfo[i].pols, 0);
-  SetLength(FPntsInfo, 0);
-  SetLength(FPnts, 0);
-end;
-
-function TLWPnts.GetPntsCount: LongWord;
-begin
-  result := Length(FPnts);
-end;
-
-class function TLWPnts.GetID: TID4;
-begin
-  result := ID_PNTS;
-end;
-
-function TLWPnts.GetVMap(VMapID: TID4; out VMap: TLWVMap): boolean;
-var
-  i: Integer;
-begin
-  result := false;
-  for i := 0 to Items.Count - 1 do
-  begin
-    if (Items[i] is TLWVMap) and (TLWVMap(Items[i]).VMapType = VMapID) then
-    begin
-
-      result := true;
-      VMap := TLWVMap(Items[i]);
-      Exit;
-    end;
-
-  end;
-
-end;
-
-procedure TLWPnts.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-begin
-  SetLength(FPnts, DataSize div 12);
-  // allocate storage for DataSize div 12 points
-  SetLength(FPntsInfo, DataSize div 12); // Point info
-  ReadMotorolaNumber(AStream, @FPnts[0], 4, DataSize div 4);
-  // read the point data
-end;
-
-(*********************************** TLWPols **********************************)
-
-procedure TLWPols.CalcPolsNormals;
-var
-  i, j, PolyIdx: Integer;
-  Pnts: TLWPnts;
-begin
-  if IndiceCount = 0 then
-    Exit;
-
-  with ParentChunk as TLWLayr do
-    Pnts := TLWPnts(Items[Items.FindChunk(@FindChunkById, @ID_PNTS, 0)]);
-
-  for PolyIdx := 0 to FPolsCount - 1 do
-  begin
-    // DONE: call Pnts.AddPoly
-    i := PolsByIndex[PolyIdx];
-    with Pnts do
-    begin
-      for j := 1 to Indices[i] do
-        AddPoly(Indices[i + j], PolyIdx);
-      SetLength(FPolsInfo[PolyIdx].vnorms, Indices[i]);
-      if Indices[PolyIdx] > 2 then
-        FPolsInfo[PolyIdx].norm := CalcPlaneNormal(Pnts[Indices[i + 1]],
-          Pnts[Indices[i + 2]], Pnts[Indices[i + 3]])
-      else
-        FPolsInfo[PolyIdx].norm := VecNorm(Pnts[Indices[i + 1]]);
-    end;
-  end;
-end;
-
-procedure TLWPols.Clear;
-var
-  i: Integer;
-begin
-  for i := 0 to FPolsCount - 1 do
-    SetLength(FPolsInfo[i].vnorms, 0);
-  SetLength(FPolsInfo, 0);
-  SetLength(FPols, 0);
-end;
-
-function TLWPols.GetPolsByIndex(AIndex: TU2): Integer;
-var
-  i, cnt: Cardinal;
-begin
-  result := -1;
-  i := 0;
-  cnt := 0;
-
-  if AIndex = 0 then
-  begin
-    result := 0;
-    Exit;
-  end;
-
-  while (i < IndiceCount - 1) and (cnt <> AIndex) do
-  begin
-    Inc(i, Indices[i] + 1);
-    Inc(cnt);
-  end;
-  if cnt = AIndex then
-    result := i;
-end;
-
-class function TLWPols.GetID: TID4;
-begin
-  result := ID_POLS;
-end;
-
-function TLWPols.GetIndiceCount: TU4;
-begin
-  result := Length(FPols);
-end;
-
-function TLWPols.GetIndice(AIndex: Integer): TU2;
-begin
-  result := FPols[AIndex];
-end;
-
-function TLWPols.GetPolsCount: Integer;
-begin
-  result := FPolsCount;
-end;
-
-procedure TLWPols.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-var
-  EndPos: Integer;
-  Idx: TU4;
-  TmpU2: TU2;
-begin
-
-  Idx := 0;
-  EndPos := DataStart + DataSize;
-
-  with AStream do
-  begin
-
-    Read(FPolsType, 4);
-
-    // To avoid memory manager hits, set an estimate length of indices
-    SetLength(FPols, (DataSize - 4) div 2);
-
-    while Position < EndPos do
-    begin
-
-      ReadMotorolaNumber(AStream, @FPols[Idx], 2);
-      TmpU2 := FPols[Idx] and POLS_VCOUNT_MASK;
-
-      ReadVXAsU2(AStream, @FPols[Idx + 1], TmpU2);
-      Inc(Idx, FPols[Idx] + 1);
-      Inc(FPolsCount);
-    end;
-    // correct length estimate errors if any
-    if (Idx + 1) < Cardinal(Length(FPols)) then
-      SetLength(FPols, Idx + 1);
-  end;
-  SetLength(FPolsInfo, FPolsCount);
-  CalcPolsNormals;
-end;
-
-(*********************************** TLWVMap **********************************)
-
-procedure TLWVMap.Clear;
-var
-  i: Integer;
-begin
-  for i := 0 to Length(FValues) - 1 do
-    SetLength(FValues[i].values, 0);
-  SetLength(FValues, 0);
-end;
-
-class function TLWVMap.GetID: TID4;
-begin
-  result := ID_VMAP;
-end;
-
-function TLWVMap.GetValue(AIndex: TU2): TLWVertexMap;
-begin
-  result := FValues[AIndex];
-end;
-
-function TLWVMap.GetValueCount: Integer;
-begin
-  result := Length(FValues);
-end;
-
-procedure TLWVMap.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-var
-  Idx: TU4;
-begin
-  Idx := 0;
-  with AStream do
-  begin
-    Read(FVMapType, 4);
-    ReadMotorolaNumber(AStream, @FDimensions, 2);
-    ReadS0(AStream, FName);
-    if FDimensions > 0 then
-    begin
-      while Cardinal(Position) < (DataStart + DataSize) do
-      begin
-        SetLength(FValues, Length(FValues) + 1);
-        ReadVXAsU2(AStream, @FValues[Idx].vert, 1);
-        SetLength(FValues[Idx].values, Dimensions * 4);
-        ReadMotorolaNumber(AStream, @FValues[Idx].values[0], 4, Dimensions);
-        Inc(Idx);
-      end;
-    end;
-  end;
-end;
-
-(*********************************** TLWTags **********************************)
-
-destructor TLWTags.Destroy;
-begin
-  inherited;
-end;
-
-procedure TLWTags.Clear;
-begin
-  FreeAndNil(FTags);
-end;
-
-class function TLWTags.GetID: TID4;
-begin
-  result := ID_TAGS;
-end;
-
-function TLWTags.GetTags: TStrings;
-begin
-  if FTags = nil then
-    FTags := TStringList.Create;
-  result := FTags;
-end;
-
-procedure TLWTags.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-var
-  EndPos: TU4;
-  TmpStr: string;
-begin
-  EndPos := DataStart + DataSize;
-  while Cardinal(AStream.Position) < Cardinal(EndPos) do
-  begin
-    ReadS0(AStream, TmpStr);
-    Tags.Add(TmpStr);
-    TmpStr := '';
-  end;
-end;
-
-function TLWTags.TagToName(tag: TU2): string;
-begin
-  result := Tags[tag];
-end;
-
-(********************************* TLWSubChunk ********************************)
-
-procedure TLWSubChunk.LoadFromStream(AStream: TStream);
-var
-  DataStart: Integer;
-  DataSize: TU2;
-begin
-  with AStream do
-  begin
-    ReadMotorolaNumber(AStream, @DataSize, 2);
-    DataStart := Position;
-    FSize := DataSize;
-    LoadData(AStream, DataStart, DataSize);
-    Position := DataStart + DataSize + (DataStart + DataSize) mod 2;
-  end;
-end;
-
-(*********************************** TLWLayr **********************************)
-
-destructor TLWLayr.Destroy;
-begin
-  inherited;
-end;
-
-class function TLWLayr.GetID: TID4;
-begin
-  result := ID_LAYR;
-end;
-
-procedure TLWLayr.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-begin
-  ReadMotorolaNumber(AStream, @FNumber, 2);
-  ReadMotorolaNumber(AStream, @FFlags, 2);
-  ReadMotorolaNumber(AStream, @FPivot, 4, 3);
-  ReadS0(AStream, FName);
-  if ((DataStart + DataSize) - Cardinal(AStream.Position)) > 2 then
-    ReadMotorolaNumber(AStream, @FParent, 2);
-end;
-
-(*********************************** TLWSurf **********************************)
-
-destructor TLWSurf.Destroy;
-begin
-  inherited;
-end;
-
-class function TLWSurf.GetID: TID4;
-begin
-  result := ID_SURF;
-end;
-
-function TLWSurf.GetParamAddr(Param: TID4): Pointer;
-var
-  Idx: Integer;
-  sParam: string;
-begin
-  result := inherited GetParamAddr(Param);
-  if (result = nil) and (Source <> '') then
-  begin
-    sParam := string(Param);
-    Idx := RootChunks.FindChunk(@FindSurfaceByName, @sParam, 0);
-    if Idx <> -1 then
-      result := TLWSurf(RootChunks[Idx]).ParamAddr[Param];
-  end;
-end;
-
-function TLWSurf.GetSurfId: Integer;
-var
-  c, SurfIdx: Integer;
-begin
-  c := 0;
-  SurfIdx := Owner.FindChunk(@FindChunkById, @ID_SURF);
-
-  while (SurfIdx <> -1) and (Owner[SurfIdx] <> Self) do
-  begin
-    SurfIdx := Owner.FindChunk(@FindChunkById, @ID_SURF, SurfIdx + 1);
-    Inc(c);
-  end;
-  result := c;
-end;
-
-procedure TLWSurf.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-var
-  CurId: TID4;
-begin
-  ReadS0(AStream, FName);
-  ReadS0(AStream, FSource);
-  while Cardinal(AStream.Position) < (DataStart + DataSize) do
-  begin
-    AStream.Read(CurId, 4);
-    Items.Add(GetChunkClass(CurId, TLWSubChunk).Create);
-    with Items[Items.Count - 1] do
-    begin
-      FID := CurId;
-      LoadFromStream(AStream);
-    end;
-  end;
-end;
-
-(*********************************** TLWPTag **********************************)
-
-constructor TLWPTag.Create;
-begin
-  inherited;
-end;
-
-function TLWPTag.AddTag(Value: TU2): Integer;
-var
-  i, L: Integer;
-begin
-  result := -1;
-  L := Length(FTags);
-  for i := 0 to L - 1 do
-    if Value = FTags[i] then
-    begin
-      result := i;
-      Exit;
-    end;
-  if result = -1 then
-  begin
-    SetLength(FTags, L + 1);
-    FTags[L] := Value;
-    result := L;
-  end;
-end;
-
-procedure TLWPTag.Clear;
-begin
-  SetLength(FTagMaps, 0);
-  SetLength(FTags, 0);
-end;
-
-function TLWPTag.GetPolsByTag(tag: TU2; var PolyIndices: TU2DynArray): Integer;
-var
-  i: Integer;
-
-  procedure AddPoly(Value: TU2);
-  var
-    L: Integer;
-  begin
-    L := Length(PolyIndices);
-    SetLength(PolyIndices, L + 1);
-    PolyIndices[L] := Value;
-  end;
-begin
-  for i := 0 to TagMapCount - 1 do
-    if TagMaps[i].tag = tag then
-      AddPoly(TagMaps[i].poly);
-  result := Length(PolyIndices);
-end;
-
-class function TLWPTag.GetID: TID4;
-begin
-  result := ID_PTAG;
-end;
-
-function TLWPTag.GetTag(AIndex: Integer): TU2;
-begin
-  ValidateTagInfo;
-  result := FTags[AIndex];
-end;
-
-function TLWPTag.GetTagCount: Integer;
-begin
-  ValidateTagInfo;
-  result := Length(FTags);
-end;
-
-function TLWPTag.GetTagMapCount: Integer;
-begin
-  result := Length(FTagMaps) div 2;
-end;
-
-function TLWPTag.GetTagMaps(AIndex: Integer): TLWPolyTagMap;
-begin
-  result := PLWPolyTagMap(@FTagMaps[AIndex * 2])^;
-end;
-
-procedure TLWPTag.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-var
-  Idx: Integer;
-begin
-  Idx := 0;
-  with AStream do
-  begin
-    Read(FMapType, 4);
-    SetLength(FTagMaps, (DataSize - 4) div 2);
-    while Cardinal(Position) < (DataStart + DataSize) do
-    begin
-      ReadVXAsU2(AStream, @FTagMaps[Idx]);
-      ReadMotorolaNumber(AStream, @FTagMaps[Idx + 1], 2);
-      Inc(Idx, 2);
-    end;
-    // correct length guestimate errors if any
-    if (Idx + 1) < Length(FTagMaps) then
-      SetLength(FTagMaps, Idx + 1);
-  end;
-end;
-
-procedure TLWPTag.ValidateTagInfo;
-var
-  i: Integer;
-begin
-  if Length(FTags) > 0 then
-    Exit;
-  for i := 0 to TagMapCount - 1 do
-    AddTag(TagMaps[i].tag);
-end;
-
-(******************************** TLWParentChunk ******************************)
-
-procedure TLWParentChunk.Clear;
-begin
-  FreeAndNil(FItems);
-  inherited;
-end;
-
-function TLWParentChunk.GetFloatParam(Param: TID4): Single;
-var
-  pdata: Pointer;
-begin
-  pdata := ParamAddr[Param];
-  if pdata <> nil then
-  begin
-
-    result := PF4(pdata)^;
-    ReverseByteOrder(@result, 4);
-
-  end
-  else
-    result := 0.0;
-end;
-
-function TLWParentChunk.GetItems: TLWChunkList;
-begin
-  if FItems = nil then
-    FItems := TLWChunkList.Create(true, Self);
-  result := FItems;
-end;
-
-function TLWParentChunk.GetLongParam(Param: TID4): LongWord;
-var
-  pdata: Pointer;
-begin
-  pdata := ParamAddr[Param];
-  if pdata <> nil then
-  begin
-
-    result := PU4(pdata)^;
-    ReverseByteOrder(@result, 4);
-  end
-  else
-    result := 0;
-end;
-
-function TLWParentChunk.GetParamAddr(Param: TID4): Pointer;
-var
-  Idx: Integer;
-begin
-  result := nil;
-  Idx := Items.FindChunk(@FindChunkById, @Param, 0);
-  if Idx <> -1 then
-    result := Items[Idx].data;
-end;
-
-function TLWPols.GetPolsByPntIdx(VertIdx: TU2;
-  var VertPolys: TU2DynArray): Integer;
-var
-  i, j, L: Integer;
-begin
-  L := 0;
-  if Length(VertPolys) > 0 then
-    SetLength(VertPolys, 0);
-  for i := 0 to PolsCount - 1 do
-  begin
-    for j := 1 to Indices[PolsByIndex[i]] do
-    begin
-      if Indices[PolsByIndex[i] + j] = VertIdx then
-      begin
-        L := Length(VertPolys);
-        SetLength(VertPolys, L + 1);
-        VertPolys[L] := i;
-      end;
-    end;
-  end;
-  result := L;
-end;
-
-function TLWChunkList.Add(AChunk: TLWChunk): Integer;
-begin
-  if (FOwner <> nil) and (FOwner is TLWParentChunk) then
-    AChunk.FParentChunk := TLWParentChunk(FOwner);
-
-  AChunk.FOwner := Self;
-  result := inherited Add(AChunk);
-end;
-
-procedure TLWPols.CalcPntsNormals;
-var
-  i, j, k, PntIdx, PolyIdx, SurfIdx: Integer;
-  Pnts: TLWPnts;
-  // PTags: TLWPTag;
-  TmpAddr: Pointer;
-  sman: TF4;
-begin
-  // Todo: CalcPntsNormals
-  if IndiceCount = 0 then
-    Exit;
-  with ParentChunk as TLWLayr do
-    Pnts := TLWPnts(Items[Items.FindChunk(@FindChunkById, @ID_PNTS, 0)]);
-  for PolyIdx := 0 to PolsCount - 1 do
-  begin
-    i := PolsByIndex[PolyIdx];
-    SurfIdx := RootChunks.FindChunk(@FindSurfaceByTag,
-      @FPolsInfo[PolyIdx].surfid);
-    TmpAddr := TLWSurf(RootChunks[SurfIdx]).ParamAddr[ID_SMAN];
-    if TmpAddr <> nil then
-    begin
-      sman := PF4(TmpAddr)^;
-      ReverseByteOrder(@sman, 4);
-    end
-    else
-      sman := 0;
-    for j := 1 to Indices[i] do
-    begin
-      FPolsInfo[PolyIdx].vnorms[j - 1] := FPolsInfo[PolyIdx].norm;
-      if sman <= 0 then
-        continue;
-      PntIdx := Indices[i + j];
-      for k := 0 to Pnts.PntsInfo[PntIdx].npols - 1 do
-      begin
-        if Pnts.PntsInfo[PntIdx].pols[k] = PolyIdx then
-          continue;
-        if ArcCos(VecDot(FPolsInfo[PolyIdx].norm,
-          FPolsInfo[Pnts.PntsInfo[PntIdx].pols[k]].norm)) > sman then
-          continue;
-        FPolsInfo[PolyIdx].vnorms[j - 1] :=
-          VecAdd(FPolsInfo[PolyIdx].vnorms[j - 1],
-          FPolsInfo[Pnts.PntsInfo[PntIdx].pols[k]].norm);
-      end;
-      FPolsInfo[PolyIdx].vnorms[j - 1] :=
-        VecNorm(FPolsInfo[PolyIdx].vnorms[j - 1]);
-    end;
-  end;
-end;
-
-function TLWChunk.GetRootChunks: TLWChunkList;
-var
-  Parent: TLWParentChunk;
-begin
-  result := nil;
-  if (FParentChunk = nil) then
-  begin
-
-    if (FOwner is TLWChunkList) then
-    begin
-      result := FOwner;
-      Exit;
-    end;
-
-  end
-  else
-  begin
-    Parent := FParentChunk;
-    while not(Parent.ParentChunk = nil) do
-      Parent := Parent.ParentChunk;
-    result := Parent.Owner;
-  end;
-end;
-
-function TLWChunkList.FindChunk(ChunkFind: TLWChunkFind; Criteria: Pointer;
-  StartIndex: Integer): Integer;
-var
-  Found: boolean;
-begin
-  Found := false;
-  result := -1;
-  while (StartIndex < Count) and (not Found) do
-  begin
-    ChunkFind(Items[StartIndex], Criteria, Found);
-    if Found then
-    begin
-      result := StartIndex;
-      Exit;
-    end;
-    Inc(StartIndex);
-  end;
-end;
-
-function TLWChunk.GetIndex: Integer;
-begin
-  result := Owner.IndexOf(Self);
-end;
-
-procedure TLWChunk.Loaded;
-begin
-  // do nothing
-end;
-
-procedure TLWChunkList.Loaded;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    Items[i].Loaded;
-  end;
-end;
-
-function TLWParentChunk.GetVec3Param(Param: TID4): TVec12;
-var
-  pdata: Pointer;
-begin
-  pdata := ParamAddr[Param];
-  if pdata <> nil then
-  begin
-
-    result := PVec12(pdata)^;
-    ReverseByteOrder(@result, 4, 3);
-
-  end
-  else
-  begin
-    result[0] := 0;
-    result[1] := 1;
-    result[2] := 2;
-  end;
-end;
-
-function TLWParentChunk.GetVXParam(Param: TID4): Word;
-var
-  pdata: Pointer;
-begin
-  pdata := ParamAddr[Param];
-  if pdata <> nil then
-    result := ValueOfVX(pdata)
-  else
-    result := 0;
-end;
-
-function TLWParentChunk.GetWordParam(Param: TID4): Word;
-var
-  pdata: Pointer;
-begin
-  pdata := ParamAddr[Param];
-  if pdata <> nil then
-  begin
-    result := PU4(pdata)^;
-    ReverseByteOrder(@result, 2);
-  end
-  else
-    result := 0;
-end;
-
-procedure TLWParentChunk.Loaded;
-begin
-  Items.Loaded;
-end;
-
-procedure TLWPols.Loaded;
-begin
-  inherited;
-  CalcPntsNormals;
-end;
-
-function TLWObjectFile.TagToName(tag: TU2): string;
-var
-  TagsIdx: Integer;
-begin
-  TagsIdx := Chunks.FindChunk(@FindChunkById, @ID_TAGS);
-  if TagsIdx <> -1 then
-    result := TLWTags(Chunks[TagsIdx]).TagToName(tag);
-end;
-
-
-(******************** TLWClip ********************)
-
-class function TLWClip.GetID: TID4;
-begin
-  result := ID_CLIP;
-end;
-
-procedure TLWClip.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
-var
-  CurId: TID4;
-begin
-  ReadMotorolaNumber(AStream, @FClipIndex, 4);
-  while Cardinal(AStream.Position) < (DataStart + DataSize) do
-  begin
-
-    AStream.Read(CurId, 4);
-
-    Items.Add(GetChunkClass(CurId, TLWSubChunk).Create);
-
-    with Items[Items.Count - 1] do
-    begin
-
-      FID := CurId;
-      LoadFromStream(AStream);
-
-    end;
-
-  end;
-
-end;
-
-// TLWContentDir
-
-(* function TLWContentDir.ContentSearch(AFilename: string): string;
-  var
-  i: Integer;
-  begin
-
-  if not FileExists(AFilename) then
-  begin
-
-  result := ExtractFileName(AFilename);
-
-  if not FileExists(result) then
-  begin
-
-  for i := 0 to SubDirs.Count - 1 do
-  begin
-
-  if FileExists(Root+'\'+SubDirs[i]+'\'+result) then
-  begin
-  result:=Root+'\'+SubDirs[i]+'\'+result;
-  Exit;
-  end;
-
-  end;
-  result := '';
-
-  end;
-
-  end;
-  end;
-*)
-
-destructor TLWContentDir.Destroy;
-begin
-  FreeAndNil(FSubDirs);
-  inherited;
-end;
-
-function TLWContentDir.FindContent(AFilename: string): string;
-var
-  i: Integer;
-begin
-
-  if not FileExists(AFilename) then
-  begin
-
-    result := ExtractFileName(AFilename);
-
-    if not FileExists(result) then
-    begin
-
-      for i := 0 to SubDirs.Count - 1 do
-      begin
-
-        if FileExists(Root + '\' + SubDirs[i] + '\' + result) then
-        begin
-          result := Root + '\' + SubDirs[i] + '\' + result;
-          Exit;
-        end;
-
-      end;
-      result := '';
-
-    end;
-
-  end;
-end;
-
-function TLWContentDir.GetSubDirs: TStrings;
-begin
-  if FSubDirs = nil then
-    FSubDirs := TStringList.Create;
-  result := FSubDirs;
-end;
-
-procedure TLWContentDir.SetRoot(const Value: string);
-begin
-  FRoot := Value;
-end;
-
-procedure TLWContentDir.SetSubDirs(const Value: TStrings);
-begin
-  SubDirs.Assign(Value);
-end;
-
-initialization
-
-// Pnts
-RegisterChunkClass(TLWPnts);
-
-// Pols
-RegisterChunkClass(TLWPols);
-
-// VMap
-RegisterChunkClass(TLWVMap);
-
-// Tags
-RegisterChunkClass(TLWTags);
-
-// PTAG
-RegisterChunkClass(TLWPTag);
-
-// SURF
-RegisterChunkClass(TLWSurf);
-
-// LAYR
-RegisterChunkClass(TLWLayr);
-
-// CLIP
-RegisterChunkClass(TLWClip);
-
-finalization
-
-// UnRegisterChunkClasses;
-FreeAndNil(ChunkClasses);
-FreeAndNil(ContentDir);
-
-end.
+//
+// This unit is part of the GLScene Engine, http://glscene.org
+//
+
+unit Formats.FileLWObjects;
+
+(* =============================================================
+
+This unit provides functions, constants and now classes for use in
+working with Lightwave3D Object files.
+
+Chunk ID constants are defined for all of the Chunk IDs listed
+in the Lightwave 7.5 sdk.
+It is important to note that this is a constant work-in-progress
+and as such there are omissions and may be errors. Feedback and
+suggestions would be appreciated.
+There are two ways of using this unit. The first uses user-defines
+callbacks to handle parsing lwo chunk data. The second way uses
+object orientation.
+
+Loading LWO chunk data via callbacks
+A function is provided for loading a Lightwave object from a file.
+The Loader itself uses a callback mechanism for the loading of
+Lightwave object chunks. The callback is called for every chunk
+(with the exception of the FORM and LWOB or LWO2 chunks).
+
+The Chunk struct passed in the callback contains members for the
+chunk ID, chunk size and pointer to chunk data. This data is
+untouched internally so any parsing and numeric formatting
+is up to you. This provides maximum flexibility and allows you to
+handle the data that you need without loading the entire object
+into ram first.
+
+The chunk data memory is freed upon the return of the callback
+so do not keep a reference to the chunk data. Copy it to your own
+storage.
+
+function LoadLW0(const Filename: string; ReadProc: TLWOReadProc;
+ UserData: Pointer): LongWord; cdecl;
+
+ Filename:      The fully qualified filename of the file to be
+                loaded.
+
+ ReadCallback:  The address of a TLWOReadCallback procedure
+                defined as:
+                TLWOReadCallback = procedure(Chunk: TLWChunk;
+                  UserData: Pointer); cdecl;
+                This procedure will be called for every chunk
+                encountered in the Lightwave object file. The
+                Chunk parameter is the chunk struct of the chunk
+                being loaded. UserData is the pointer supplied
+                in the original call to LoadLWO (see below).
+
+ UserData:      A pointer to user supplied data to be passed
+                in the ReadCallback.
+
+A non-zero results indicates that the object file was parsed
+successfully.
+
+Loading LWO chunks via objects
+============================
+To load data from a lightwave object file, create an instance of
+TLWObjectFile and call its LoadFromFile method.
+
+The data can then be accessed with the Chunks array property and
+iterated in combination with the ChunkCount property.
+
+Chunk data is parsed and interfaced by descendents of the TLWChunk
+class. I have made handlers for the following chunk types:
+
+TLWLayr  Modeler Layer chunk
+TLWPnts  Points chunk
+TLWPols  Polygons chunk
+TLWPTag  Polygon tag mapping
+TLWSurf  Surface subchunk container
+TLWTags  Tags (Name tag strings for named items)
+TLWVMap  Vertex Mapping
+
+The data for chunks without handlers can be gotten at with the
+Data and Size properties of the TLWChunk. Data is a pointer to
+the start of the chunk data. This data is unparsed.
+Data is nil for descendents.
+
+
+This should provide enough to move geometry into your favourite
+delphi-based 3d engine.
+
+
+Making chunk handler objects
+============================
+
+All chunk types are derived from TLWChunk in the following manner:
+
+TLWChunk
+
+ex:
+
+TLWPTag        <- PTAG chunk type. polygon tag map.
+
+TLWParentChunk <- A base class for chunks that can contain other chunks.
+                 This is not necessarily how the data is stored in
+                 the file but more for ease of access to data.
+ ex:
+ TLWPnts <- PNTS chunk type (points)
+ TLWLayr <- LAYR chunk type (modeler layer)
+ TLWSurf <- SURF chunk type (constains surface attributes as sub chunks)
+ TLWSubChunk <- A base class for chunks whose max data len is 65536 bytes.
+ TLWDiff   <- DIFF subchunk type (diffuse surface parameter)
+ TLWSpec   <- SPEC subchunk type (specularity surface parameter)...
+ etc.
+
+Each descendent of TLWChunk or TLWSubChunk is required to override
+the GetID class function, the LoadData method and the Clear method
+to provide custom handling for chunktype data.
+
+ex:
+...
+type
+  TLWPnts = class (TLWParentChunk)
+  private
+    FPoints: TVEC12DynArray;
+    function GetCount: LongWord;
+    protected
+    procedure Clear; override;
+    procedure LoadData(AStream: TStream; DataStart, DataSize: LongWord); override;
+  public
+    class function GetID: TID4; override;
+    function GetVMap(VMapID: TID4; out VMap: TLWVMap): boolean;
+    property Count: LongWord read GetCount;
+    property Points: TVEC12DynArray read FPoints;
+  end;
+...
+
+// Return the the chunk id that is the target of this handler
+
+class function TLWPnts.GetID: TID4;
+begin
+  result := ID_PNTS;
+end;
+
+// Load the point data - the stream is already positioned at the start of the chunk data
+
+procedure TLWPnts.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+begin
+  SetLength(FPoints,DataSize div 12); // allocate storage for DataSize div 12 points
+  ReadMotorolaNumber(AStream,@FPoints[0],4,DataSize div 4); // read the point data
+end;
+
+
+// Cleanup - Free any memory that you've allocated
+
+procedure TLWPnts.Clear;
+begin
+  SetLength(FPoints,0);
+end;
+
+
+Utility Functions
+=================
+A function is provided for converting an array of numbers between
+Motorola and Intel format (big endian <-> little endian). Converting
+only needs to be done for numeric types that are of 2 or 4 byte
+lengths.
+
+procedure ReverseByteOrder(ValueIn: Pointer; Size: integer; Count: integer = 1);
+
+ ValueIn: The address of a number or array of numbers to have their
+          bytes swapped.
+ Size:    The size in bytes of each numeric type.
+ Count:   The count of numbers in the numbers array. The default
+          value is 1.
+
+Two routines are provided for reading and writing big endian
+(Motorola and misc other processor vendors ) numbers to and from a
+stream. These routines handle 2 and 4 byte numeric types and can
+also handle arrays.
+
+procedure ReadMotorolaNumber(Stream: TStream; Data: Pointer;
+ ElementSize: integer; Count: integer = 1);
+
+function WriteMotorolaNumber(Stream: TStream; Data: Pointer;
+ ElementSize: integer; Count: integer = 1): Integer;
+
+Each take a valid TStream descendent, a pointer to the numeric data,
+the element size of the data elements (either 2 or 4) and the array
+element count if sending an array. The default count is 1.
+
+Notes for improvement of this unit:
+
+- A version ID tag should be visible to all chunks in order to
+ provide handling for Lightwave pre 6.0 object files.
+
+- Chunk type handlers should leave memory allocation to
+ the base class (TLWChunk) and act more as an interface
+ to the data pointed to by Data in TLWChunk. This would
+ keep memory allocation very efficient and make implementing
+ chunk handlers even easier.
+
+  Author:     Brian Johns [email protected]
+  Purpose:    Lightwave object support unit for Delphi.
+  Notes:      For the Lightwave Object File Format documentation please refer to
+  http://www.lightwave3d.com/developer.
+  Lightwave3D is a registered trademark of Newtek Incorporated.
+
+===================================================================== *)
+
+interface
+
+{$I GLScene.inc}
+
+uses
+  System.Classes,
+  System.SysUtils,
+  System.IOUtils,
+  System.Math,
+  Scene.VectorGeometry;
+
+type
+
+  TID4 = array [0 .. 3] of AnsiChar;
+  PID4 = ^TID4;
+  TID4DynArray = array of TID4;
+
+const
+  ID_NULL = '#0#0#0#0'; // NULL ID
+
+  ID_LWSC: TID4 = 'LWSC'; // Lightwave scene file
+  ID_FORM: TID4 = 'FORM'; // IFF Form
+  ID_LWOB: TID4 = 'LWOB'; // Lightwave Object version 1.0 - 5.x
+  ID_LWLO: TID4 = 'LWLO'; // Lightwave Layered Object
+  ID_LAYR: TID4 = 'LAYR'; // LAYER
+  ID_PNTS: TID4 = 'PNTS'; // Points chunk
+  ID_SRFS: TID4 = 'SRFS'; // Surface Names chunk
+  ID_POLS: TID4 = 'POLS'; // Polygons chunk
+  ID_CRVS: TID4 = 'CRVS'; // Curves chunk
+  ID_PCHS: TID4 = 'PCHS'; // Patches chunk
+  ID_SURF: TID4 = 'SURF'; // Surfaces chunk
+  ID_COLR: TID4 = 'COLR'; // Color chunk
+
+  ID_FLAG: TID4 = 'FLAG'; // Surface Flags
+
+  ID_LUMI: TID4 = 'LUMI'; // Luminosity
+  ID_DIFF: TID4 = 'DIFF'; // Diffuse
+  ID_SPEC: TID4 = 'SPEC'; // Specular
+  ID_REFL: TID4 = 'REFL'; // Reflective
+  ID_TRAN: TID4 = 'TRAN'; // Transparency
+
+  ID_VLUM: TID4 = 'VLUM'; // Luminosity
+  ID_VDIF: TID4 = 'VDIF'; // Diffuse
+  ID_VSPC: TID4 = 'VSPC'; // Specularity
+  ID_VRFL: TID4 = 'VRFL'; // Reflective
+  ID_VTRN: TID4 = 'VTRN'; // Transparency
+
+  ID_GLOS: TID4 = 'GLOS'; // Glossiness SmallInt
+
+  ID_SIDE: TID4 = 'SIDE'; // Sidedness
+
+  ID_RFLT: TID4 = 'RFLT'; // REFLECTION MODE (PRE 6.0)
+
+  ID_RFOP: TID4 = 'RFOP'; // REFLECTION OPTIONS
+  ID_RIMG: TID4 = 'RIMG'; // REFLECTION IMAGE
+  ID_RSAN: TID4 = 'RSAN'; // REFLECTION MAP SEAM ANGLE
+  ID_RIND: TID4 = 'RIND'; // REFRACTIVE INDEX
+  ID_EDGE: TID4 = 'EDGE'; // EDGE TRANSPARENCY THRESHOLD
+  ID_SMAN: TID4 = 'SMAN'; // SMOOTHING ANGLE RADIANS
+  ID_ALPH: TID4 = 'ALPH'; // ALPHA MODE
+  ID_CTEX: TID4 = 'CTEX'; // COLOR TEXTURE
+  ID_DTEX: TID4 = 'DTEX'; // DIFFUSE TEXTURE
+  ID_STEX: TID4 = 'STEX'; // SPECULAR TEXTURE
+  ID_RTEX: TID4 = 'RTEX'; // REFLECTIION TEXTURE
+  ID_TTEX: TID4 = 'TTEX'; // TRANSPARENCY TEXTURE
+  ID_LTEX: TID4 = 'LTEX'; // LUMINANCE TEXTURE
+  ID_BTEX: TID4 = 'BTEX'; // BUMP TEXTURE
+  ID_TFLG: TID4 = 'TFLG'; // TEXTURE FLAGS
+  ID_TSIZ: TID4 = 'TSIZ'; // TEXTURE SIZE
+  ID_TCTR: TID4 = 'TCTR'; // TEXTURE CENTER
+  ID_TFAL: TID4 = 'TFAL'; // TEXTURE FALLOFF
+  ID_TVEL: TID4 = 'TVAL'; // TEXTURE VALUE
+  ID_TREF: TID4 = 'TREF'; // TEXTURE REFERENCE
+  ID_TCLR: TID4 = 'TCLR'; // TEXTURE COLOR
+  ID_TVAL: TID4 = 'TVAL'; // TEXTURE VALUE
+  ID_TAMP: TID4 = 'TAMP'; // TEXTURE AMPLITUDE
+  ID_TFP0: TID4 = 'TFP0'; // TEXTURE PARAMETERS
+  ID_TFP1: TID4 = 'TFP1'; //
+  ID_TFP2: TID4 = 'TFP2'; //
+  ID_TIP0: TID4 = 'TIP0'; //
+  ID_TIP1: TID4 = 'TIP1'; //
+  ID_TIP2: TID4 = 'TIP2'; //
+  ID_TSP0: TID4 = 'TSP0'; //
+  ID_TSP1: TID4 = 'TSP1'; //
+  ID_TSP2: TID4 = 'TSP2'; //
+  ID_TFRQ: TID4 = 'TFRQ'; //
+  ID_TIMG: TID4 = 'TIMG'; // TEXTURE IMG
+  ID_TALP: TID4 = 'TALP'; //
+  ID_TWRP: TID4 = 'TWRP'; // TEXTURE WRAP
+  ID_TAAS: TID4 = 'TAAS'; //
+  ID_TOPC: TID4 = 'TOPC'; //
+  ID_SHDR: TID4 = 'SHDR'; //
+  ID_SDAT: TID4 = 'SDAT'; //
+  ID_IMSQ: TID4 = 'IMSQ'; // IMAGE SEQUENCE
+  ID_FLYR: TID4 = 'FLYR'; // FLYER SEQUENCE
+  ID_IMCC: TID4 = 'IMCC'; //
+
+  SURF_FLAG_LUMINOUS = 1;
+  SURF_FLAG_OUTLINE = 2;
+  SURF_FLAG_SMOOTHING = 4;
+  SURF_FLAG_COLORHIGHLIGHTS = 8;
+  SURF_FLAG_COLORFILTER = 16;
+  SURF_FLAG_OPAQUEEDGE = 32;
+  SURF_FLAG_TRANSPARENTEDGE = 64;
+  SURF_FLAG_SHARPTERMINATOR = 128;
+  SURF_FLAG_DOUBLESIDED = 256;
+  SURF_FLAG_ADDITIVE = 512;
+  SURF_FLAG_SHADOWALPHA = 1024;
+
+  CURV_CONTINUITY_FIRST = 1;
+  CURV_CONTINUITY_LAST = 2;
+
+  IMSQ_FLAG_LOOP = 1;
+  IMSQ_FLAG_INTERLACE = 2;
+
+  ID_LWO2: TID4 = 'LWO2'; // OBJECT
+  ID_VMAP: TID4 = 'VMAP'; // VERTEX MAP
+  ID_TAGS: TID4 = 'TAGS'; // TAGS?
+  ID_PTAG: TID4 = 'PTAG'; // POLYGON TAG MAP
+  ID_VMAD: TID4 = 'VMAD'; // DISCONTINUOUS VERTEX MAP
+  ID_ENVL: TID4 = 'ENVL'; // ENVELOPE
+  ID_CLIP: TID4 = 'CLIP'; // CLIP
+  ID_BBOX: TID4 = 'BBOX'; // BOUNDING BOX
+  ID_DESC: TID4 = 'DESC'; // DESCRIPTION
+  ID_TEXT: TID4 = 'TEXT'; // TEXT
+  ID_ICON: TID4 = 'ICON'; // ICON
+
+  ENVL_PRE: TID4 = 'PRE'#0; // PRE-BEHAVIOUR
+  ENVL_POST: TID4 = 'POST'; // POST
+  ENVL_KEY: TID4 = 'KEY'#0; // KEY
+  ENVL_SPAN: TID4 = 'SPAN'; // SPAN
+  ENVL_CHAN: TID4 = 'CHAN'; // CHAN
+  ENVL_NAME: TID4 = 'NAME'; // NAME
+
+  ID_STIL: TID4 = 'STIL'; // STILL IMAGE FILENAME
+  ID_ISEQ: TID4 = 'ISEQ'; // IMAGE SEQUENCE
+  ID_ANIM: TID4 = 'ANIM'; // PLUGIN ANIMATION
+  ID_STCC: TID4 = 'STCC'; // COLOR CYCLING STILL
+  ID_CONT: TID4 = 'CONT'; // CONTRAST
+  ID_BRIT: TID4 = 'BRIT'; // BRIGHTNESS
+  ID_SATR: TID4 = 'SATR'; // SATURATION
+  ID_HUE: TID4 = 'HUE'#0; // HUE
+  ID_GAMMA: TID4 = 'GAMM'; // GAMMA
+  ID_NEGA: TID4 = 'NEGA'; // NEGATIVE IMAGE
+  ID_IFLT: TID4 = 'IFLT'; // IMAGE PLUG-IN FILTER
+  ID_PFLT: TID4 = 'PFLT'; // PIXEL PLUG-IN FILTER
+
+  POLS_TYPE_FACE: TID4 = 'FACE'; // FACES
+  POLS_TYPE_CURV: TID4 = 'CURV'; // CURVE
+  POLS_TYPE_PTCH: TID4 = 'PTCH'; // PATCH
+  POLS_TYPE_MBAL: TID4 = 'MBAL'; // METABALL
+  POLS_TYPE_BONE: TID4 = 'BONE'; // SKELEGON?
+
+  VMAP_TYPE_PICK: TID4 = 'PICK'; // SELECTION SET
+  VMAP_TYPE_WGHT: TID4 = 'WGHT'; // WEIGHT MAP
+  VMAP_TYPE_MNVW: TID4 = 'MNVW'; // SUBPATCH WEIGHT MAP
+  VMAP_TYPE_TXUV: TID4 = 'TXUV'; // UV MAP
+  VMAP_TYPE_RGB: TID4 = 'RGB'#0; // RGB MAP
+  VMAP_TYPE_RGBA: TID4 = 'RGBA'; // RGBA MAP
+  VMAP_TYPE_MORF: TID4 = 'MORF'; // MORPH MAP: RELATIVE VERTEX DISPLACEMENT
+  VMAP_TYPE_SPOT: TID4 = 'SPOT'; // SPOT MAP: ABSOLUTE VERTEX POSITIONS
+
+  PTAG_TYPE_SURF: TID4 = 'SURF'; // SURFACE
+  PTAG_TYPE_PART: TID4 = 'PART'; // PARENT PART
+  PTAG_TYPE_SMGP: TID4 = 'SMGP'; // SMOOTH GROUP
+
+  PRE_POST_RESET = 0; // RESET
+  PRE_POST_CONSTANT = 1; // CONSTANT
+  PRE_POST_REPEAT = 2; // REPEAT
+  PRE_POST_OSCILLATE = 3; // OSCILLATE
+  PRE_POST_OFFSET = 4; // OFFSET REPEAT
+  PRE_POST_LINEAR = 5; // LINEAR
+
+  POLS_VCOUNT_MASK = $3FF;
+  POLS_FLAGS_MASK = $FC00;
+
+  SIDE_FRONT = 1;
+  SIDE_BACK = 2;
+  SIDE_FRONT_AND_BACK = SIDE_FRONT and SIDE_BACK;
+
+  RFOP_BACKDROP = 0;
+  RFOP_RAYTRACEANDBACKDROP = 1;
+  RFOP_SPHERICALMAP = 2;
+  RFOP_RAYTRACEANDSPHERICALMAP = 3;
+
+type
+  TI1 = ShortInt;
+  PI1 = ^TI1;
+
+  TI2 = SmallInt;
+  PI2 = ^TI2;
+
+  TI4 = LongInt;
+  PI4 = ^TI4;
+
+  TU1 = Byte;
+  PU1 = ^TU1;
+  TU1DynArray = array of TU1;
+
+  TU2 = Word;
+  PU2 = ^TU2;
+  TU2Array = array [0 .. 65534] of TU2;
+  PU2Array = ^TU2Array;
+  TU2DynArray = array of TU2;
+
+  TU4 = LongWord;
+  PU4 = ^TU4;
+  TU4Array = array [0 .. 65534] of TU4;
+  PU4Array = ^TU4Array;
+  TU4DynArray = array of TU4;
+
+  TF4 = Single;
+  PF4 = ^TF4;
+  TF4Array = array [0 .. 65534] of TF4;
+  PF4Array = ^TF4Array;
+  TF4DynArray = array of TF4;
+
+  TANG4 = TF4;
+  PANG4 = ^TANG4;
+
+  // TS0 = PAnsiChar;
+
+  TVec12 = array [0 .. 2] of TF4;
+  PVec12 = ^TVec12;
+
+  TVec12Array = array [0 .. 65534] of TVec12;
+  PVec12Array = ^TVec12Array;
+  TVec12DynArray = array of TVec12;
+
+  TColr12 = TVec12;
+  PColr12 = ^TColr12;
+
+  TColr12DynArray = array of TColr12;
+
+  TColr4 = array [0 .. 3] of TU1;
+  PColr4 = ^TColr4;
+
+  // Lightwave Chunk Struct - Used in TLWOReadCallback
+  PLWChunkRec = ^TLWChunkRec;
+
+  TLWChunkRec = record
+    id: TID4;
+    size: TU4;
+    data: Pointer;
+  end;
+
+  // Lightwave SubChunk Struct - Used in TLWOReadCallback
+  PLWSubChunkRec = ^TLWSubChunkRec;
+
+  TLWSubChunkRec = record
+    id: TID4;
+    size: TU2;
+    data: Pointer;
+  end;
+
+  TLWPolsInfo = record
+    norm: TVec12;
+    vnorms: TVec12DynArray;
+    surfid: TU2;
+  end;
+
+  TLWPolsInfoDynArray = array of TLWPolsInfo;
+
+  TLWPntsInfo = record
+    npols: TU2;
+    pols: TU2DynArray;
+  end;
+
+  TLWPntsInfoDynArray = array of TLWPntsInfo;
+
+  TLWPolsDynArray = TU2DynArray;
+
+  TLWPolyTagMapDynArray = TU2DynArray;
+
+  TLWPolyTagMap = record
+    poly: TU2;
+    tag: TU2;
+  end;
+
+  PLWPolyTagMap = ^TLWPolyTagMap;
+
+  // Value Map
+  TLWVertexMap = record
+    vert: TU2;
+    values: TF4DynArray;
+  end;
+
+  TLWVertexMapDynArray = array of TLWVertexMap;
+
+  TLWChunkList = class;
+  TLWParentChunk = class;
+
+  TLWChunk = class(TPersistent)
+  private
+    FData: Pointer;
+    FID: TID4;
+    FSize: TU4;
+    FParentChunk: TLWParentChunk;
+    FOwner: TLWChunkList;
+    function GetRootChunks: TLWChunkList;
+    function GetIndex: Integer;
+  protected
+    procedure Clear; virtual;
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); virtual;
+    procedure Loaded; virtual;
+  public
+    destructor Destroy; override;
+    class function GetID: TID4; virtual;
+    procedure LoadFromStream(AStream: TStream); virtual;
+    property data: Pointer read FData;
+    property id: TID4 read FID;
+    property size: TU4 read FSize;
+    // ParentChunk may be nil indicating this is a root chunk. ie. TLWLayr
+    property ParentChunk: TLWParentChunk read FParentChunk;
+    property RootChunks: TLWChunkList read GetRootChunks;
+    property Index: Integer read GetIndex;
+    property Owner: TLWChunkList read FOwner;
+  end;
+
+  TLWChunkClass = class of TLWChunk;
+
+  TLWSubChunk = class(TLWChunk)
+  public
+    procedure LoadFromStream(AStream: TStream); override;
+  end;
+
+  TLWChunkFind = procedure(AChunk: TLWChunk; Criteria: Pointer;
+    var Found: boolean);
+
+  TLWChunkList = class(TList)
+  private
+    FOwnsItems: boolean;
+    FOwner: TObject;
+    function GetItem(Index: Integer): TLWChunk;
+  protected
+    procedure Loaded; virtual;
+  public
+    constructor Create(AOwnsItems: boolean; AOwner: TObject);
+    destructor Destroy; override;
+    function Add(AChunk: TLWChunk): Integer;
+    procedure Clear; override;
+    procedure Delete(Index: Integer);
+    function FindChunk(ChunkFind: TLWChunkFind; Criteria: Pointer;
+      StartIndex: Integer = 0): Integer;
+    property Items[Index: Integer]: TLWChunk read GetItem; default;
+    property OwnsItems: boolean read FOwnsItems;
+    property Owner: TObject read FOwner;
+  end;
+
+  TLWParentChunk = class(TLWChunk)
+  private
+    FItems: TLWChunkList;
+    function GetItems: TLWChunkList;
+    function GetFloatParam(Param: TID4): Single;
+    function GetWordParam(Param: TID4): Word;
+    function GetVec3Param(Param: TID4): TVec12;
+    function GetLongParam(Param: TID4): LongWord;
+    function GetVXParam(Param: TID4): Word;
+  protected
+    function GetParamAddr(Param: TID4): Pointer; virtual;
+    procedure Clear; override;
+    procedure Loaded; override;
+  public
+    property Items: TLWChunkList read GetItems;
+    property ParamAddr[Param: TID4]: Pointer read GetParamAddr;
+    property FloatParam[Param: TID4]: Single read GetFloatParam;
+    property WordParam[Param: TID4]: Word read GetWordParam;
+    property LongParam[Param: TID4]: LongWord read GetLongParam;
+    property Vec3Param[Param: TID4]: TVec12 read GetVec3Param;
+    property VXParam[Param: TID4]: Word read GetVXParam;
+  end;
+
+  TLWVMap = class;
+
+  TLWPnts = class(TLWParentChunk)
+  private
+    FPnts: TVec12DynArray;
+    FPntsInfo: TLWPntsInfoDynArray;
+    function GetPntsCount: LongWord;
+    function AddPoly(PntIdx, PolyIdx: Integer): Integer;
+  protected
+    procedure Clear; override;
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+  public
+    class function GetID: TID4; override;
+    function GetVMap(VMapID: TID4; out VMap: TLWVMap): boolean;
+    property PntsCount: LongWord read GetPntsCount;
+    property Pnts: TVec12DynArray read FPnts;
+    property PntsInfo: TLWPntsInfoDynArray read FPntsInfo;
+  end;
+
+  TLWPols = class(TLWParentChunk)
+  private
+    FPolsType: TID4;
+    FPols: TLWPolsDynArray;
+    FPolsInfo: TLWPolsInfoDynArray;
+    FPolsCount: Integer;
+    function GetPolsByIndex(AIndex: TU2): Integer;
+    function GetIndiceCount: TU4;
+    function GetIndice(AIndex: Integer): TU2;
+    function GetPolsCount: Integer;
+    procedure CalcPolsNormals;
+    procedure CalcPntsNormals;
+  protected
+    procedure Clear; override;
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+    procedure Loaded; override;
+  public
+    class function GetID: TID4; override;
+    function GetPolsByPntIdx(VertIdx: TU2; var VertPolys: TU2DynArray): Integer;
+    property PolsByIndex[AIndex: TU2]: Integer read GetPolsByIndex;
+    property IndiceCount: TU4 read GetIndiceCount;
+    property Indices[AIndex: Integer]: TU2 read GetIndice;
+    property PolsType: TID4 read FPolsType;
+    property PolsCount: Integer read GetPolsCount;
+    property PolsInfo: TLWPolsInfoDynArray read FPolsInfo;
+  end;
+
+  TLWVMap = class(TLWChunk)
+  private
+    FDimensions: TU2;
+    FName: string;
+    FValues: TLWVertexMapDynArray;
+    FVMapType: TID4;
+    function GetValue(AIndex: TU2): TLWVertexMap;
+    function GetValueCount: Integer;
+  protected
+    procedure Clear; override;
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+  public
+    class function GetID: TID4; override;
+    property Dimensions: TU2 read FDimensions;
+    property Name: string read FName;
+    property Value[AIndex: TU2]: TLWVertexMap read GetValue;
+    property ValueCount: Integer read GetValueCount;
+    property VMapType: TID4 read FVMapType;
+  end;
+
+  TLWTags = class(TLWChunk)
+  private
+    FTags: TStrings;
+    function GetTags: TStrings;
+  protected
+    procedure Clear; override;
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+  public
+    destructor Destroy; override;
+    class function GetID: TID4; override;
+    function TagToName(tag: TU2): string;
+    property Tags: TStrings read GetTags;
+  end;
+
+  TLWSurf = class(TLWParentChunk)
+  private
+    FName: string;
+    FSource: string;
+    function GetSurfId: Integer;
+  protected
+    function GetParamAddr(Param: TID4): Pointer; override;
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+  public
+    destructor Destroy; override;
+    class function GetID: TID4; override;
+    property surfid: Integer read GetSurfId;
+    property Name: string read FName;
+    property Source: string read FSource;
+  end;
+
+  TLWLayr = class(TLWParentChunk)
+  private
+    FFlags: TU2;
+    FName: string;
+    FNumber: TU2;
+    FParent: TU2;
+    FPivot: TVec12;
+  protected
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+  public
+    destructor Destroy; override;
+    class function GetID: TID4; override;
+    property Flags: TU2 read FFlags;
+    property Name: string read FName;
+    property Number: TU2 read FNumber;
+    property Parent: TU2 read FParent;
+    property Pivot: TVec12 read FPivot;
+  end;
+
+  TLWPTag = class(TLWChunk)
+  private
+    FMapType: TID4;
+    FTagMaps: TLWPolyTagMapDynArray;
+    FTags: TU2DynArray;
+    function AddTag(Value: TU2): Integer;
+    function GetTag(AIndex: Integer): TU2;
+    function GetTagCount: Integer;
+    function GetTagMapCount: Integer;
+    function GetTagMaps(AIndex: Integer): TLWPolyTagMap;
+    procedure ValidateTagInfo;
+  protected
+    procedure Clear; override;
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+  public
+    constructor Create;
+    function GetPolsByTag(tag: TU2; var PolyIndices: TU2DynArray): Integer;
+    class function GetID: TID4; override;
+    property MapType: TID4 read FMapType;
+    property TagCount: Integer read GetTagCount;
+    property TagMapCount: Integer read GetTagMapCount;
+    property TagMaps[AIndex: Integer]: TLWPolyTagMap read GetTagMaps; default;
+    property Tags[AIndex: Integer]: TU2 read GetTag;
+  end;
+
+  TLWObjectFile = class(TObject)
+  private
+    FChunks: TLWChunkList;
+    FFileName: string;
+    function GetChunks: TLWChunkList;
+    function GetCount: Integer;
+    function GetSurfaceByName(Index: string): TLWSurf;
+    function GetSurfaceByTag(Index: TU2): TLWSurf;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function TagToName(tag: TU2): string;
+    procedure LoadFromFile(const AFilename: string);
+    procedure LoadFromStream(AStream: TStream);
+    property ChunkCount: Integer read GetCount;
+    property Chunks: TLWChunkList read GetChunks;
+    property FileName: string read FFileName;
+    property SurfaceByName[Index: string]: TLWSurf read GetSurfaceByName;
+    property SurfaceByTag[Index: TU2]: TLWSurf read GetSurfaceByTag;
+  end;
+
+  TLWClip = class(TLWParentChunk)
+  private
+    FClipIndex: TU4;
+  protected
+    procedure LoadData(AStream: TStream;
+      DataStart, DataSize: LongWord); override;
+  public
+    class function GetID: TID4; override;
+    property ClipIndex: TU4 read FClipIndex;
+  end;
+
+  TLWContentNotify = procedure(Sender: TObject; var Content: string) of object;
+
+  TLWContentDir = class
+  private
+    FSubDirs: TStrings;
+    FRoot: string;
+    function GetSubDirs: TStrings;
+    procedure SetRoot(const Value: string);
+    procedure SetSubDirs(const Value: TStrings);
+    // function ContentSearch(AFilename: string): string;
+  public
+    destructor Destroy; override;
+    function FindContent(AFilename: string): string;
+    property Root: string read FRoot write SetRoot;
+    property SubDirs: TStrings read GetSubDirs write SetSubDirs;
+  end;
+
+  TLWOReadCallback = procedure(Chunk: TLWChunkRec; data: Pointer); cdecl;
+
+procedure RegisterChunkClass(ChunkClass: TLWChunkClass);
+
+function LoadLW0FromStream(Stream: TStream; ReadCallback: TLWOReadCallback;
+  UserData: Pointer): LongWord; cdecl;
+function LoadLWOFromFile(const AFilename: string;
+  ReadCallback: TLWOReadCallback; UserData: Pointer): LongWord;
+
+procedure ReadMotorolaNumber(Stream: TStream; data: Pointer;
+  ElementSize: Integer; Count: Integer = 1);
+function WriteMotorolaNumber(Stream: TStream; data: Pointer;
+  ElementSize: Integer; Count: Integer = 1): Integer;
+
+function ReadS0(Stream: TStream; out Str: string): Integer;
+procedure WriteS0(Stream: TStream; data: string);
+
+procedure WriteU4AsVX(Stream: TStream; data: Pointer; Count: Integer);
+function ReadVXAsU4(Stream: TStream; data: Pointer; Count: Integer = 1)
+  : Integer;
+
+procedure ReverseByteOrder(ValueIn: Pointer; size: Integer; Count: Integer = 1);
+
+function ToDosPath(const Path: string): string;
+function ToUnixPath(const Path: string): string;
+
+function ID4ToInt(const id: TID4): Integer;
+
+// ChunkFind procedures
+procedure FindChunkById(AChunk: TLWChunk; data: Pointer; var Found: boolean);
+procedure FindSurfaceByName(AChunk: TLWChunk; AName: Pointer;
+  var Found: boolean);
+procedure FindSurfaceByTag(AChunk: TLWChunk; ATag: Pointer; var Found: boolean);
+
+procedure FindVMapByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
+procedure FindClipByClipIndex(AChunk: TLWChunk; AIndex: Pointer;
+  var Found: boolean);
+
+function GetContentDir: TLWContentDir;
+
+// --------------------------------------------------------------------
+implementation
+// --------------------------------------------------------------------
+
+type
+  PWord = ^Word;
+  PLongWord = ^LongWord;
+
+var
+  ChunkClasses: TList;
+  ContentDir: TLWContentDir;
+
+function ToDosPath(const Path: string): string;
+var
+  i: Integer;
+begin
+  result := Path;
+  for i := 1 to Length(result) do
+    if result[i] = '/' then
+      result[i] := '\';
+end;
+
+function ToUnixPath(const Path: string): string;
+var
+  i: Integer;
+begin
+  result := Path;
+  for i := 1 to Length(result) do
+    if result[i] = '\' then
+      result[i] := '/';
+end;
+
+function GetContentDir: TLWContentDir;
+begin
+  if ContentDir = nil then
+    ContentDir := TLWContentDir.Create;
+  result := ContentDir;
+end;
+
+procedure FindChunkById(AChunk: TLWChunk; data: Pointer; var Found: boolean);
+begin
+  if AChunk.FID = PID4(data)^ then
+    Found := true
+  else
+    Found := false;
+end;
+
+procedure FindClipByClipIndex(AChunk: TLWChunk; AIndex: Pointer;
+  var Found: boolean);
+begin
+  if (AChunk is TLWClip) and (TLWClip(AChunk).ClipIndex = PU2(AIndex)^) then
+    Found := true;
+end;
+
+procedure FindSurfaceByName(AChunk: TLWChunk; AName: Pointer;
+  var Found: boolean);
+begin
+  if (AChunk is TLWSurf) and (TLWSurf(AChunk).Name = PString(AName)^) then
+    Found := true;
+end;
+
+procedure FindSurfaceByTag(AChunk: TLWChunk; ATag: Pointer; var Found: boolean);
+begin
+  if (AChunk is TLWSurf) and (TLWSurf(AChunk).surfid = PU2(ATag)^) then
+    Found := true;
+end;
+
+procedure FindVMapByName(AChunk: TLWChunk; AName: Pointer; var Found: boolean);
+begin
+  if (AChunk is TLWVMap) and (TLWVMap(AChunk).Name = PString(AName)^) then
+    Found := true;
+end;
+
+function VecAdd(v1, v2: TVec12): TVec12;
+begin
+  result[0] := v1[0] + v2[0];
+  result[1] := v1[1] + v2[1];
+  result[2] := v1[2] + v2[2];
+end;
+
+function VecSub(v1, v2: TVec12): TVec12;
+begin
+  result[0] := v1[0] - v2[0];
+  result[1] := v1[1] - v2[1];
+  result[2] := v1[2] - v2[2];
+end;
+
+function VecCross(v1, v2: TVec12): TVec12;
+begin
+  result[0] := v1[1] * v2[2] - v1[2] * v2[1];
+  result[1] := v1[2] * v2[0] - v1[0] * v2[2];
+  result[2] := v1[0] * v2[1] - v1[1] * v2[0];
+end;
+
+function VecDot(v1, v2: TVec12): TF4;
+begin
+  result := v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
+end;
+
+function VecNorm(v: TVec12): TVec12;
+var
+  mag: TF4;
+begin
+  mag := Sqrt(VecDot(v, v));
+
+  if mag > 0 then
+    mag := 1 / mag;
+
+  result[0] := v[0] * mag;
+  result[1] := v[1] * mag;
+  result[2] := v[2] * mag;
+end;
+
+function CalcPlaneNormal(v1, v2, v3: TVec12): TVec12;
+var
+  e1, e2: TVec12;
+begin
+  e1 := VecSub(v2, v1);
+  e2 := VecSub(v3, v1);
+  result := VecCross(e1, e2);
+  result := VecNorm(result);
+end;
+
+procedure FindSurfByName(Chunk: TLWChunk; var Found: boolean);
+begin
+
+end;
+
+(*-----------------------------------------------------------------------------
+  Procedure: GetChunkClasses
+  Date:      08-Aug-2002
+  Arguments: None
+  Result:    TClassList
+
+  Singleton access for the chunk class list.
+  -----------------------------------------------------------------------------*)
+function GetChunkClasses: TList;
+begin
+  if ChunkClasses = nil then
+    ChunkClasses := TList.Create;
+  result := ChunkClasses;
+end;
+
+procedure UnRegisterChunkClasses;
+var
+  i: Integer;
+begin
+  with GetChunkClasses do
+    for i := 0 to Count - 1 do
+      UnregisterClass(TPersistentClass(Items[i]));
+end;
+
+(*-----------------------------------------------------------------------------
+  Procedure: RegisterChunkClass
+  Date:      08-Aug-2002
+  Arguments: ChunkClass: TLWChunkClass
+  Result:    None
+
+  Adds a user defined chunk class to the chunk class list.
+  -----------------------------------------------------------------------------*)
+procedure RegisterChunkClass(ChunkClass: TLWChunkClass);
+begin
+  GetChunkClasses.Add(ChunkClass);
+  // if FindClass(ChunkClass.ClassName) <> nil then
+  // UnRegisterClass(ChunkClass);
+  // RegisterClass(ChunkClass);
+end;
+
+(*-----------------------------------------------------------------------------
+  Procedure: GetChunkClass
+  Date:      08-Aug-2002
+  Arguments: ChunkID: TID4
+  Result:    TLWChunkClass
+
+  Returns the chunk class associated with ChunkID.
+  -----------------------------------------------------------------------------*)
+function GetChunkClass(ChunkID: TID4; ADefault: TLWChunkClass): TLWChunkClass;
+var
+  i: Integer;
+begin
+
+  if ADefault = nil then
+    result := TLWChunk
+  else
+    result := ADefault;
+
+  for i := 0 to ChunkClasses.Count - 1 do
+  begin
+
+    if TLWChunkClass(ChunkClasses.Items[i]).GetID = ChunkID then
+    begin
+
+      result := TLWChunkClass(ChunkClasses.Items[i]);
+      Exit;
+
+    end;
+
+  end;
+
+end;
+
+(*-----------------------------------------------------------------------------
+  Procedure: Tokenize
+  Date:      08-Aug-2002
+  Arguments: const Src: string; Delimiter: Char; Dst: TStrings
+  Result:    None
+
+  Breaks up a string into TStrings items when the Delimiter character is
+  encountered.
+  -----------------------------------------------------------------------------*)
+procedure Tokenize(const Src: string; Delimiter: Char; Dst: TStrings);
+var
+  i, L, SL: Integer;
+  SubStr: string;
+begin
+  if Dst = nil then
+    Exit;
+
+  L := Length(Src);
+  if (L = 0) or (Dst = nil) then
+    Exit;
+  SubStr := '';
+  for i := 1 to L do
+  begin
+    if (Src[i] <> Delimiter) then
+      SubStr := SubStr + Src[i]
+    else
+    begin
+      SL := Length(SubStr);
+      if SL > 0 then
+      begin
+        Dst.Add(SubStr);
+        SubStr := '';
+      end;
+    end;
+  end;
+  if Length(SubStr) > 0 then
+    Dst.Add(SubStr);
+end;
+
+(*-----------------------------------------------------------------------------
+  Procedure: LoadLW0FromStream
+  Date:      08-Aug-2002
+  Arguments: Stream: TStream; ReadCallback: TLWOReadCallback; UserData: Pointer
+  Result:    LongWord
+  -----------------------------------------------------------------------------*)
+function LoadLW0FromStream(Stream: TStream; ReadCallback: TLWOReadCallback;
+  UserData: Pointer): LongWord;
+var
+  Chunk: TLWChunkRec;
+  CurId: TID4;
+  StartPos, CurSize: TU4;
+
+begin
+  try
+    Stream.Read(CurId, 4);
+
+    ReadMotorolaNumber(Stream, @CurSize, 4);
+
+    if UpperCase(string(CurId)) = 'FORM' then
+    begin
+      Stream.Read(CurId, 4);
+    end
+    else
+      raise Exception.Create
+        ('Invalid magic number. Not a valid Lightwave Object');
+    with Stream do
+      while Position < size do
+      begin
+        Read(Chunk, 8);
+        ReverseByteOrder(@Chunk.size, 4);
+        StartPos := Position;
+        GetMem(Chunk.data, Chunk.size);
+        Stream.Read(Chunk.data^, Chunk.size);
+        if Assigned(ReadCallback) then
+          ReadCallback(Chunk, UserData);
+        FreeMem(Chunk.data, Chunk.size);
+        Position := StartPos + Chunk.size + (StartPos + Chunk.size) mod 2;
+      end;
+    Stream.Free;
+    result := High(LongWord);
+  except
+    On E: Exception do
+    begin
+      Stream.Free;
+      result := 0;
+    end;
+  end;
+end;
+
+function LoadLWOFromFile(const AFilename: String;
+  ReadCallback: TLWOReadCallback; UserData: Pointer): LongWord;
+var
+  Stream: TStream;
+begin
+  Stream := TFileStream.Create(AFilename, fmOpenRead);
+  try
+    result := LoadLW0FromStream(Stream, ReadCallback, UserData);
+  finally
+    Stream.Free;
+  end;
+end;
+
+procedure ReverseByteOrder(ValueIn: Pointer; size: Integer; Count: Integer = 1);
+var
+  W: Word;
+  pB: PByte;
+  Blo, Bhi: Byte;
+  L: LongWord;
+  i: Integer;
+begin
+  i := 0;
+
+  case size of
+    2:
+      begin
+
+        while i < Count do
+        begin
+          W := PU2Array(ValueIn)^[i];
+
+          pB := @W;
+          Blo := pB^;
+          Inc(pB);
+          Bhi := pB^;
+          pB^ := Blo;
+          Dec(pB);
+          pB^ := Bhi;
+          PU2Array(ValueIn)^[i] := W;
+
+          Inc(i);
+        end;
+      end;
+
+    4:
+      begin
+        while i < Count do
+        begin
+          L := PU4Array(ValueIn)^[i];
+          pB := @W;
+          Blo := pB^;
+          Inc(pB);
+          Bhi := pB^;
+          pB^ := Blo;
+          Dec(pB);
+          pB^ := Bhi;
+          PU4Array(ValueIn)^[i] := L;
+
+          Inc(i);
+        end;
+      end;
+  else
+    raise Exception.Create('Lightwave.ReverseByteOrder: Invalid Size = ' +
+      IntToStr(size));
+  end;
+end;
+
+procedure ReadMotorolaNumber(Stream: TStream; data: Pointer;
+  ElementSize: Integer; Count: Integer = 1);
+begin
+  Stream.Read(data^, Count * ElementSize);
+
+  if (ElementSize = 2) or (ElementSize = 4) then
+    ReverseByteOrder(data, ElementSize, Count);
+end;
+
+function WriteMotorolaNumber(Stream: TStream; data: Pointer;
+  ElementSize: Integer; Count: Integer = 1): Integer;
+var
+  TempData: Pointer;
+begin
+  result := 0;
+  if data <> nil then
+  begin
+    TempData := AllocMem(ElementSize * Count);
+    try
+      if (ElementSize = 2) or (ElementSize = 4) then
+        ReverseByteOrder(TempData, ElementSize, Count);
+      result := Stream.Write(data, Count * ElementSize);
+    except
+      on E: Exception do
+      begin
+        FreeMem(TempData, Count * ElementSize);
+        raise;
+      end;
+    end;
+  end;
+end;
+
+function ReadS0(Stream: TStream; out Str: string): Integer;
+var
+  Buf: array [0 .. 1] of AnsiChar;
+  StrBuf: string;
+begin
+  Stream.Read(Buf, 2);
+  StrBuf := '';
+  while Buf[1] <> #0 do
+  begin
+    StrBuf := StrBuf + string(Buf);
+    Stream.Read(Buf, 2);
+  end;
+
+  if Buf[0] <> #0 then
+    StrBuf := StrBuf + Char(Buf[0]);
+
+  Str := Copy(StrBuf, 1, Length(StrBuf));
+  result := Length(Str) + 1;
+  result := result + (result mod 2);
+end;
+
+function ValueOfVX(VX: Pointer): TU4;
+var
+  TmpU2: TU2;
+  TmpU4: TU4;
+begin
+  if PU1(VX)^ = $FF then
+  begin
+    TmpU4 := TU4(PU1(VX)^) and $FFFFFFF0;
+    ReverseByteOrder(@TmpU4, 4);
+  end
+  else
+  begin
+    TmpU2 := TU2(PU2(VX)^);
+    ReverseByteOrder(@TmpU2, 2);
+    TmpU4 := TmpU2;
+  end;
+  result := TmpU4;
+end;
+
+function ReadVXAsU4(Stream: TStream; data: Pointer; Count: Integer = 1)
+  : Integer;
+var
+  i, ReadCount: Integer;
+  BufByte: Byte;
+  TempU2: TU2;
+begin
+  ReadCount := 0;
+  for i := 0 to Count - 1 do
+  begin
+
+    Stream.Read(BufByte, 1);
+    Stream.Position := Stream.Position - 1;
+
+    if BufByte = 255 then
+    begin
+      Stream.Read(data^, SizeOf(TU4));
+      PU4Array(data)^[i] := PU4Array(data)^[i] and $FFFFFFF0;
+      ReverseByteOrder(data, SizeOf(TU4));
+      Inc(ReadCount, 4);
+    end
+    else
+    begin
+      Stream.Read(TempU2, SizeOf(TU2));
+      ReverseByteOrder(@TempU2, SizeOf(TU2));
+      PU4Array(data)^[i] := TempU2;
+      Inc(ReadCount, 2);
+    end;
+
+  end;
+  result := ReadCount;
+end;
+
+function ReadVXAsU2(Stream: TStream; data: Pointer; Count: Integer = 1)
+  : Integer;
+var
+  i, ReadCount: Integer;
+  BufByte: Byte;
+  TempU2: TU2;
+begin
+  ReadCount := 0;
+  for i := 0 to Count - 1 do
+  begin
+    Stream.Read(BufByte, 1);
+    Stream.Position := Stream.Position - 1;
+    if BufByte = 255 then
+    begin
+      Stream.Position := Stream.Position + 4;
+      PU2Array(data)^[i] := 0;
+      Inc(ReadCount, 4);
+    end
+    else
+    begin
+      Stream.Read(TempU2, SizeOf(TU2));
+      ReverseByteOrder(@TempU2, SizeOf(TU2));
+      PU2Array(data)^[i] := TempU2;
+      Inc(ReadCount, 2);
+    end;
+  end;
+  result := ReadCount;
+end;
+
+procedure WriteS0(Stream: TStream; data: string);
+begin
+  // ToDo: WriteS0
+end;
+
+procedure WriteU4AsVX(Stream: TStream; data: Pointer; Count: Integer);
+var
+  i: Integer;
+  TempU2: TU2;
+begin
+  for i := 0 to Count - 1 do
+  begin
+    if PU4Array(data)^[i] < 65280 then
+    begin
+      TempU2 := PU4Array(data)^[i];
+      WriteMotorolaNumber(Stream, @TempU2, SizeOf(TU2));
+    end
+    else
+      WriteMotorolaNumber(Stream, data, SizeOf(TU4));
+  end;
+end;
+
+type
+  PInteger = ^Integer;
+
+function ID4ToInt(const id: TID4): Integer;
+var
+  TmpId: AnsiString;
+begin
+
+  TmpId := id;
+
+  TmpId := AnsiString(UpperCase(string(id)));
+
+  result := PInteger(@TmpId)^;
+
+end;
+
+(*********************************** TLWChunk ********************************)
+
+destructor TLWChunk.Destroy;
+begin
+  Clear;
+  inherited;
+end;
+
+procedure TLWChunk.Clear;
+begin
+  FreeMem(FData, FSize);
+  FSize := 0;
+  FData := nil;
+end;
+
+class function TLWChunk.GetID: TID4;
+begin
+  result := #0#0#0#0;
+end;
+
+procedure TLWChunk.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+begin
+  GetMem(FData, DataSize);
+  AStream.Read(PByteArray(FData)^[0], DataSize);
+end;
+
+procedure TLWChunk.LoadFromStream(AStream: TStream);
+var
+  DataStart: Integer;
+  DataSize: TU4;
+begin
+  with AStream do
+  begin
+
+    ReadMotorolaNumber(AStream, @DataSize, 4);
+
+    DataStart := Position;
+
+    FSize := DataSize;
+
+    LoadData(AStream, DataStart, DataSize);
+
+    Position := Cardinal(DataStart) + DataSize +
+      (Cardinal(DataStart) + DataSize) mod 2;
+
+  end;
+end;
+
+
+(********************************* TLWChunkList *******************************)
+
+constructor TLWChunkList.Create(AOwnsItems: boolean; AOwner: TObject);
+begin
+  inherited Create;
+  FOwnsItems := AOwnsItems;
+  FOwner := AOwner;
+end;
+
+destructor TLWChunkList.Destroy;
+begin
+  Clear;
+  inherited;
+end;
+
+procedure TLWChunkList.Clear;
+begin
+  while Count > 0 do
+    Delete(Count - 1);
+  inherited;
+end;
+
+procedure TLWChunkList.Delete(Index: Integer);
+begin
+  if FOwnsItems then
+    Items[Index].Free;
+  inherited Delete(Index);
+end;
+
+function TLWChunkList.GetItem(Index: Integer): TLWChunk;
+begin
+  result := TLWChunk(inherited Items[Index]);
+end;
+
+(******************************** TLWObjectFile *******************************)
+
+constructor TLWObjectFile.Create;
+begin
+
+  inherited;
+
+end;
+
+destructor TLWObjectFile.Destroy;
+begin
+
+  FreeAndNil(FChunks);
+
+  inherited;
+
+end;
+
+function TLWObjectFile.GetChunks: TLWChunkList;
+begin
+  if FChunks = nil then
+    FChunks := TLWChunkList.Create(true, Self);
+  result := FChunks;
+end;
+
+function TLWObjectFile.GetCount: Integer;
+begin
+  result := Chunks.Count;
+end;
+
+function TLWObjectFile.GetSurfaceByName(Index: string): TLWSurf;
+var
+  SurfIdx: Integer;
+begin
+  SurfIdx := Chunks.FindChunk(@FindSurfaceByName, @Index, 0);
+  if SurfIdx <> -1 then
+    result := TLWSurf(Chunks[SurfIdx])
+  else
+    result := nil;
+end;
+
+function TLWObjectFile.GetSurfaceByTag(Index: TU2): TLWSurf;
+var
+  TagName: string;
+begin
+  TagName := TagToName(Index);
+  result := SurfaceByName[TagName];
+end;
+
+procedure TLWObjectFile.LoadFromFile(const AFilename: string);
+var
+  Stream: TMemoryStream;
+begin
+
+  Stream := TMemoryStream.Create;
+  try
+    Stream.LoadFromFile(AFilename);
+
+    LoadFromStream(Stream);
+    Stream.Free;
+    FFileName := AFilename;
+  except
+    on E: Exception do
+    begin
+      Stream.Free;
+      raise;
+    end;
+  end;
+
+end;
+
+procedure TLWObjectFile.LoadFromStream(AStream: TStream);
+var
+  CurId: TID4;
+  CurSize: LongWord;
+  CurPnts, CurPols, CurItems: TLWChunkList;
+begin
+  CurPols := nil;
+  CurPnts := nil;
+
+  AStream.Read(CurId, 4);
+
+  ReadMotorolaNumber(AStream, @CurSize, 4);
+
+  if UpperCase(string(CurId)) = 'FORM' then
+  begin
+
+    AStream.Read(CurId, 4);
+
+    if CurId <> 'LWO2' then
+      raise Exception.Create
+        ('Only Version 6.0+ version objects are supported.');
+
+  end
+  else
+    raise Exception.Create
+      ('Invalid magic number. Not a valid Lightwave Object');
+
+  CurItems := Chunks;
+
+  while AStream.Position < AStream.size do
+  begin
+    AStream.Read(CurId, 4);
+
+    if (CurId = ID_PTAG) then
+    begin
+      CurPols.Add(GetChunkClass(CurId, TLWChunk).Create);
+
+      with CurPols[CurPols.Count - 1] do
+      begin
+        FID := CurId;
+        LoadFromStream(AStream);
+      end;
+    end
+    else if (CurId = ID_VMAP) or (CurId = ID_VMAD) then
+    begin
+      CurPnts.Add(GetChunkClass(CurId, TLWChunk).Create);
+      with CurPnts[CurPnts.Count - 1] do
+      begin
+        FID := CurId;
+        LoadFromStream(AStream);
+      end;
+    end
+    else
+    begin
+      if (CurId = ID_LAYR) or (CurId = ID_SURF) or (CurId = ID_TAGS) or
+        (CurId = ID_CLIP) then
+        CurItems := Chunks;
+      CurItems.Add(GetChunkClass(CurId, TLWChunk).Create);
+      with CurItems[CurItems.Count - 1] do
+      begin
+        FID := CurId;
+        LoadFromStream(AStream);
+      end;
+
+    end;
+
+    if CurId = ID_LAYR then
+      CurItems := TLWParentChunk(CurItems[CurItems.Count - 1]).Items
+    else if CurId = ID_POLS then
+      CurPols := TLWParentChunk(CurItems[CurItems.Count - 1]).Items
+    else if CurId = ID_PNTS then
+      CurPnts := TLWParentChunk(CurItems[CurItems.Count - 1]).Items;
+  end;
+  Chunks.Loaded;
+end;
+
+(*********************************** TLWPnts **********************************)
+
+function TLWPnts.AddPoly(PntIdx, PolyIdx: Integer): Integer;
+var
+  i, L: Integer;
+begin
+  // DONE: Pnts.AddPoly
+
+  for i := 0 to FPntsInfo[PntIdx].npols - 1 do
+  begin
+    if FPntsInfo[PntIdx].pols[i] = PolyIdx then
+    begin
+      result := i;
+      Exit;
+    end;
+  end;
+
+  L := Length(FPntsInfo[PntIdx].pols);
+  SetLength(FPntsInfo[PntIdx].pols, L + 1);
+  FPntsInfo[PntIdx].npols := L + 1;
+  FPntsInfo[PntIdx].pols[L] := PolyIdx;
+  result := L;
+end;
+
+procedure TLWPnts.Clear;
+var
+  i: Integer;
+begin
+  for i := 0 to PntsCount - 1 do
+    SetLength(FPntsInfo[i].pols, 0);
+  SetLength(FPntsInfo, 0);
+  SetLength(FPnts, 0);
+end;
+
+function TLWPnts.GetPntsCount: LongWord;
+begin
+  result := Length(FPnts);
+end;
+
+class function TLWPnts.GetID: TID4;
+begin
+  result := ID_PNTS;
+end;
+
+function TLWPnts.GetVMap(VMapID: TID4; out VMap: TLWVMap): boolean;
+var
+  i: Integer;
+begin
+  result := false;
+  for i := 0 to Items.Count - 1 do
+  begin
+    if (Items[i] is TLWVMap) and (TLWVMap(Items[i]).VMapType = VMapID) then
+    begin
+
+      result := true;
+      VMap := TLWVMap(Items[i]);
+      Exit;
+    end;
+
+  end;
+
+end;
+
+procedure TLWPnts.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+begin
+  SetLength(FPnts, DataSize div 12);
+  // allocate storage for DataSize div 12 points
+  SetLength(FPntsInfo, DataSize div 12); // Point info
+  ReadMotorolaNumber(AStream, @FPnts[0], 4, DataSize div 4);
+  // read the point data
+end;
+
+(*********************************** TLWPols **********************************)
+
+procedure TLWPols.CalcPolsNormals;
+var
+  i, j, PolyIdx: Integer;
+  Pnts: TLWPnts;
+begin
+  if IndiceCount = 0 then
+    Exit;
+
+  with ParentChunk as TLWLayr do
+    Pnts := TLWPnts(Items[Items.FindChunk(@FindChunkById, @ID_PNTS, 0)]);
+
+  for PolyIdx := 0 to FPolsCount - 1 do
+  begin
+    // DONE: call Pnts.AddPoly
+    i := PolsByIndex[PolyIdx];
+    with Pnts do
+    begin
+      for j := 1 to Indices[i] do
+        AddPoly(Indices[i + j], PolyIdx);
+      SetLength(FPolsInfo[PolyIdx].vnorms, Indices[i]);
+      if Indices[PolyIdx] > 2 then
+        FPolsInfo[PolyIdx].norm := CalcPlaneNormal(Pnts[Indices[i + 1]],
+          Pnts[Indices[i + 2]], Pnts[Indices[i + 3]])
+      else
+        FPolsInfo[PolyIdx].norm := VecNorm(Pnts[Indices[i + 1]]);
+    end;
+  end;
+end;
+
+procedure TLWPols.Clear;
+var
+  i: Integer;
+begin
+  for i := 0 to FPolsCount - 1 do
+    SetLength(FPolsInfo[i].vnorms, 0);
+  SetLength(FPolsInfo, 0);
+  SetLength(FPols, 0);
+end;
+
+function TLWPols.GetPolsByIndex(AIndex: TU2): Integer;
+var
+  i, cnt: Cardinal;
+begin
+  result := -1;
+  i := 0;
+  cnt := 0;
+
+  if AIndex = 0 then
+  begin
+    result := 0;
+    Exit;
+  end;
+
+  while (i < IndiceCount - 1) and (cnt <> AIndex) do
+  begin
+    Inc(i, Indices[i] + 1);
+    Inc(cnt);
+  end;
+  if cnt = AIndex then
+    result := i;
+end;
+
+class function TLWPols.GetID: TID4;
+begin
+  result := ID_POLS;
+end;
+
+function TLWPols.GetIndiceCount: TU4;
+begin
+  result := Length(FPols);
+end;
+
+function TLWPols.GetIndice(AIndex: Integer): TU2;
+begin
+  result := FPols[AIndex];
+end;
+
+function TLWPols.GetPolsCount: Integer;
+begin
+  result := FPolsCount;
+end;
+
+procedure TLWPols.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+var
+  EndPos: Integer;
+  Idx: TU4;
+  TmpU2: TU2;
+begin
+
+  Idx := 0;
+  EndPos := DataStart + DataSize;
+
+  with AStream do
+  begin
+
+    Read(FPolsType, 4);
+
+    // To avoid memory manager hits, set an estimate length of indices
+    SetLength(FPols, (DataSize - 4) div 2);
+
+    while Position < EndPos do
+    begin
+
+      ReadMotorolaNumber(AStream, @FPols[Idx], 2);
+      TmpU2 := FPols[Idx] and POLS_VCOUNT_MASK;
+
+      ReadVXAsU2(AStream, @FPols[Idx + 1], TmpU2);
+      Inc(Idx, FPols[Idx] + 1);
+      Inc(FPolsCount);
+    end;
+    // correct length estimate errors if any
+    if (Idx + 1) < Cardinal(Length(FPols)) then
+      SetLength(FPols, Idx + 1);
+  end;
+  SetLength(FPolsInfo, FPolsCount);
+  CalcPolsNormals;
+end;
+
+(*********************************** TLWVMap **********************************)
+
+procedure TLWVMap.Clear;
+var
+  i: Integer;
+begin
+  for i := 0 to Length(FValues) - 1 do
+    SetLength(FValues[i].values, 0);
+  SetLength(FValues, 0);
+end;
+
+class function TLWVMap.GetID: TID4;
+begin
+  result := ID_VMAP;
+end;
+
+function TLWVMap.GetValue(AIndex: TU2): TLWVertexMap;
+begin
+  result := FValues[AIndex];
+end;
+
+function TLWVMap.GetValueCount: Integer;
+begin
+  result := Length(FValues);
+end;
+
+procedure TLWVMap.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+var
+  Idx: TU4;
+begin
+  Idx := 0;
+  with AStream do
+  begin
+    Read(FVMapType, 4);
+    ReadMotorolaNumber(AStream, @FDimensions, 2);
+    ReadS0(AStream, FName);
+    if FDimensions > 0 then
+    begin
+      while Cardinal(Position) < (DataStart + DataSize) do
+      begin
+        SetLength(FValues, Length(FValues) + 1);
+        ReadVXAsU2(AStream, @FValues[Idx].vert, 1);
+        SetLength(FValues[Idx].values, Dimensions * 4);
+        ReadMotorolaNumber(AStream, @FValues[Idx].values[0], 4, Dimensions);
+        Inc(Idx);
+      end;
+    end;
+  end;
+end;
+
+(*********************************** TLWTags **********************************)
+
+destructor TLWTags.Destroy;
+begin
+  inherited;
+end;
+
+procedure TLWTags.Clear;
+begin
+  FreeAndNil(FTags);
+end;
+
+class function TLWTags.GetID: TID4;
+begin
+  result := ID_TAGS;
+end;
+
+function TLWTags.GetTags: TStrings;
+begin
+  if FTags = nil then
+    FTags := TStringList.Create;
+  result := FTags;
+end;
+
+procedure TLWTags.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+var
+  EndPos: TU4;
+  TmpStr: string;
+begin
+  EndPos := DataStart + DataSize;
+  while Cardinal(AStream.Position) < Cardinal(EndPos) do
+  begin
+    ReadS0(AStream, TmpStr);
+    Tags.Add(TmpStr);
+    TmpStr := '';
+  end;
+end;
+
+function TLWTags.TagToName(tag: TU2): string;
+begin
+  result := Tags[tag];
+end;
+
+(********************************* TLWSubChunk ********************************)
+
+procedure TLWSubChunk.LoadFromStream(AStream: TStream);
+var
+  DataStart: Integer;
+  DataSize: TU2;
+begin
+  with AStream do
+  begin
+    ReadMotorolaNumber(AStream, @DataSize, 2);
+    DataStart := Position;
+    FSize := DataSize;
+    LoadData(AStream, DataStart, DataSize);
+    Position := DataStart + DataSize + (DataStart + DataSize) mod 2;
+  end;
+end;
+
+(*********************************** TLWLayr **********************************)
+
+destructor TLWLayr.Destroy;
+begin
+  inherited;
+end;
+
+class function TLWLayr.GetID: TID4;
+begin
+  result := ID_LAYR;
+end;
+
+procedure TLWLayr.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+begin
+  ReadMotorolaNumber(AStream, @FNumber, 2);
+  ReadMotorolaNumber(AStream, @FFlags, 2);
+  ReadMotorolaNumber(AStream, @FPivot, 4, 3);
+  ReadS0(AStream, FName);
+  if ((DataStart + DataSize) - Cardinal(AStream.Position)) > 2 then
+    ReadMotorolaNumber(AStream, @FParent, 2);
+end;
+
+(*********************************** TLWSurf **********************************)
+
+destructor TLWSurf.Destroy;
+begin
+  inherited;
+end;
+
+class function TLWSurf.GetID: TID4;
+begin
+  result := ID_SURF;
+end;
+
+function TLWSurf.GetParamAddr(Param: TID4): Pointer;
+var
+  Idx: Integer;
+  sParam: string;
+begin
+  result := inherited GetParamAddr(Param);
+  if (result = nil) and (Source <> '') then
+  begin
+    sParam := string(Param);
+    Idx := RootChunks.FindChunk(@FindSurfaceByName, @sParam, 0);
+    if Idx <> -1 then
+      result := TLWSurf(RootChunks[Idx]).ParamAddr[Param];
+  end;
+end;
+
+function TLWSurf.GetSurfId: Integer;
+var
+  c, SurfIdx: Integer;
+begin
+  c := 0;
+  SurfIdx := Owner.FindChunk(@FindChunkById, @ID_SURF);
+
+  while (SurfIdx <> -1) and (Owner[SurfIdx] <> Self) do
+  begin
+    SurfIdx := Owner.FindChunk(@FindChunkById, @ID_SURF, SurfIdx + 1);
+    Inc(c);
+  end;
+  result := c;
+end;
+
+procedure TLWSurf.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+var
+  CurId: TID4;
+begin
+  ReadS0(AStream, FName);
+  ReadS0(AStream, FSource);
+  while Cardinal(AStream.Position) < (DataStart + DataSize) do
+  begin
+    AStream.Read(CurId, 4);
+    Items.Add(GetChunkClass(CurId, TLWSubChunk).Create);
+    with Items[Items.Count - 1] do
+    begin
+      FID := CurId;
+      LoadFromStream(AStream);
+    end;
+  end;
+end;
+
+(*********************************** TLWPTag **********************************)
+
+constructor TLWPTag.Create;
+begin
+  inherited;
+end;
+
+function TLWPTag.AddTag(Value: TU2): Integer;
+var
+  i, L: Integer;
+begin
+  result := -1;
+  L := Length(FTags);
+  for i := 0 to L - 1 do
+    if Value = FTags[i] then
+    begin
+      result := i;
+      Exit;
+    end;
+  if result = -1 then
+  begin
+    SetLength(FTags, L + 1);
+    FTags[L] := Value;
+    result := L;
+  end;
+end;
+
+procedure TLWPTag.Clear;
+begin
+  SetLength(FTagMaps, 0);
+  SetLength(FTags, 0);
+end;
+
+function TLWPTag.GetPolsByTag(tag: TU2; var PolyIndices: TU2DynArray): Integer;
+var
+  i: Integer;
+
+  procedure AddPoly(Value: TU2);
+  var
+    L: Integer;
+  begin
+    L := Length(PolyIndices);
+    SetLength(PolyIndices, L + 1);
+    PolyIndices[L] := Value;
+  end;
+begin
+  for i := 0 to TagMapCount - 1 do
+    if TagMaps[i].tag = tag then
+      AddPoly(TagMaps[i].poly);
+  result := Length(PolyIndices);
+end;
+
+class function TLWPTag.GetID: TID4;
+begin
+  result := ID_PTAG;
+end;
+
+function TLWPTag.GetTag(AIndex: Integer): TU2;
+begin
+  ValidateTagInfo;
+  result := FTags[AIndex];
+end;
+
+function TLWPTag.GetTagCount: Integer;
+begin
+  ValidateTagInfo;
+  result := Length(FTags);
+end;
+
+function TLWPTag.GetTagMapCount: Integer;
+begin
+  result := Length(FTagMaps) div 2;
+end;
+
+function TLWPTag.GetTagMaps(AIndex: Integer): TLWPolyTagMap;
+begin
+  result := PLWPolyTagMap(@FTagMaps[AIndex * 2])^;
+end;
+
+procedure TLWPTag.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+var
+  Idx: Integer;
+begin
+  Idx := 0;
+  with AStream do
+  begin
+    Read(FMapType, 4);
+    SetLength(FTagMaps, (DataSize - 4) div 2);
+    while Cardinal(Position) < (DataStart + DataSize) do
+    begin
+      ReadVXAsU2(AStream, @FTagMaps[Idx]);
+      ReadMotorolaNumber(AStream, @FTagMaps[Idx + 1], 2);
+      Inc(Idx, 2);
+    end;
+    // correct length guestimate errors if any
+    if (Idx + 1) < Length(FTagMaps) then
+      SetLength(FTagMaps, Idx + 1);
+  end;
+end;
+
+procedure TLWPTag.ValidateTagInfo;
+var
+  i: Integer;
+begin
+  if Length(FTags) > 0 then
+    Exit;
+  for i := 0 to TagMapCount - 1 do
+    AddTag(TagMaps[i].tag);
+end;
+
+(******************************** TLWParentChunk ******************************)
+
+procedure TLWParentChunk.Clear;
+begin
+  FreeAndNil(FItems);
+  inherited;
+end;
+
+function TLWParentChunk.GetFloatParam(Param: TID4): Single;
+var
+  pdata: Pointer;
+begin
+  pdata := ParamAddr[Param];
+  if pdata <> nil then
+  begin
+
+    result := PF4(pdata)^;
+    ReverseByteOrder(@result, 4);
+
+  end
+  else
+    result := 0.0;
+end;
+
+function TLWParentChunk.GetItems: TLWChunkList;
+begin
+  if FItems = nil then
+    FItems := TLWChunkList.Create(true, Self);
+  result := FItems;
+end;
+
+function TLWParentChunk.GetLongParam(Param: TID4): LongWord;
+var
+  pdata: Pointer;
+begin
+  pdata := ParamAddr[Param];
+  if pdata <> nil then
+  begin
+
+    result := PU4(pdata)^;
+    ReverseByteOrder(@result, 4);
+  end
+  else
+    result := 0;
+end;
+
+function TLWParentChunk.GetParamAddr(Param: TID4): Pointer;
+var
+  Idx: Integer;
+begin
+  result := nil;
+  Idx := Items.FindChunk(@FindChunkById, @Param, 0);
+  if Idx <> -1 then
+    result := Items[Idx].data;
+end;
+
+function TLWPols.GetPolsByPntIdx(VertIdx: TU2;
+  var VertPolys: TU2DynArray): Integer;
+var
+  i, j, L: Integer;
+begin
+  L := 0;
+  if Length(VertPolys) > 0 then
+    SetLength(VertPolys, 0);
+  for i := 0 to PolsCount - 1 do
+  begin
+    for j := 1 to Indices[PolsByIndex[i]] do
+    begin
+      if Indices[PolsByIndex[i] + j] = VertIdx then
+      begin
+        L := Length(VertPolys);
+        SetLength(VertPolys, L + 1);
+        VertPolys[L] := i;
+      end;
+    end;
+  end;
+  result := L;
+end;
+
+function TLWChunkList.Add(AChunk: TLWChunk): Integer;
+begin
+  if (FOwner <> nil) and (FOwner is TLWParentChunk) then
+    AChunk.FParentChunk := TLWParentChunk(FOwner);
+
+  AChunk.FOwner := Self;
+  result := inherited Add(AChunk);
+end;
+
+procedure TLWPols.CalcPntsNormals;
+var
+  i, j, k, PntIdx, PolyIdx, SurfIdx: Integer;
+  Pnts: TLWPnts;
+  // PTags: TLWPTag;
+  TmpAddr: Pointer;
+  sman: TF4;
+begin
+  // Todo: CalcPntsNormals
+  if IndiceCount = 0 then
+    Exit;
+  with ParentChunk as TLWLayr do
+    Pnts := TLWPnts(Items[Items.FindChunk(@FindChunkById, @ID_PNTS, 0)]);
+  for PolyIdx := 0 to PolsCount - 1 do
+  begin
+    i := PolsByIndex[PolyIdx];
+    SurfIdx := RootChunks.FindChunk(@FindSurfaceByTag,
+      @FPolsInfo[PolyIdx].surfid);
+    TmpAddr := TLWSurf(RootChunks[SurfIdx]).ParamAddr[ID_SMAN];
+    if TmpAddr <> nil then
+    begin
+      sman := PF4(TmpAddr)^;
+      ReverseByteOrder(@sman, 4);
+    end
+    else
+      sman := 0;
+    for j := 1 to Indices[i] do
+    begin
+      FPolsInfo[PolyIdx].vnorms[j - 1] := FPolsInfo[PolyIdx].norm;
+      if sman <= 0 then
+        continue;
+      PntIdx := Indices[i + j];
+      for k := 0 to Pnts.PntsInfo[PntIdx].npols - 1 do
+      begin
+        if Pnts.PntsInfo[PntIdx].pols[k] = PolyIdx then
+          continue;
+        if ArcCos(VecDot(FPolsInfo[PolyIdx].norm,
+          FPolsInfo[Pnts.PntsInfo[PntIdx].pols[k]].norm)) > sman then
+          continue;
+        FPolsInfo[PolyIdx].vnorms[j - 1] :=
+          VecAdd(FPolsInfo[PolyIdx].vnorms[j - 1],
+          FPolsInfo[Pnts.PntsInfo[PntIdx].pols[k]].norm);
+      end;
+      FPolsInfo[PolyIdx].vnorms[j - 1] :=
+        VecNorm(FPolsInfo[PolyIdx].vnorms[j - 1]);
+    end;
+  end;
+end;
+
+function TLWChunk.GetRootChunks: TLWChunkList;
+var
+  Parent: TLWParentChunk;
+begin
+  result := nil;
+  if (FParentChunk = nil) then
+  begin
+
+    if (FOwner is TLWChunkList) then
+    begin
+      result := FOwner;
+      Exit;
+    end;
+
+  end
+  else
+  begin
+    Parent := FParentChunk;
+    while not(Parent.ParentChunk = nil) do
+      Parent := Parent.ParentChunk;
+    result := Parent.Owner;
+  end;
+end;
+
+function TLWChunkList.FindChunk(ChunkFind: TLWChunkFind; Criteria: Pointer;
+  StartIndex: Integer): Integer;
+var
+  Found: boolean;
+begin
+  Found := false;
+  result := -1;
+  while (StartIndex < Count) and (not Found) do
+  begin
+    ChunkFind(Items[StartIndex], Criteria, Found);
+    if Found then
+    begin
+      result := StartIndex;
+      Exit;
+    end;
+    Inc(StartIndex);
+  end;
+end;
+
+function TLWChunk.GetIndex: Integer;
+begin
+  result := Owner.IndexOf(Self);
+end;
+
+procedure TLWChunk.Loaded;
+begin
+  // do nothing
+end;
+
+procedure TLWChunkList.Loaded;
+var
+  i: Integer;
+begin
+  for i := 0 to Count - 1 do
+  begin
+    Items[i].Loaded;
+  end;
+end;
+
+function TLWParentChunk.GetVec3Param(Param: TID4): TVec12;
+var
+  pdata: Pointer;
+begin
+  pdata := ParamAddr[Param];
+  if pdata <> nil then
+  begin
+
+    result := PVec12(pdata)^;
+    ReverseByteOrder(@result, 4, 3);
+
+  end
+  else
+  begin
+    result[0] := 0;
+    result[1] := 1;
+    result[2] := 2;
+  end;
+end;
+
+function TLWParentChunk.GetVXParam(Param: TID4): Word;
+var
+  pdata: Pointer;
+begin
+  pdata := ParamAddr[Param];
+  if pdata <> nil then
+    result := ValueOfVX(pdata)
+  else
+    result := 0;
+end;
+
+function TLWParentChunk.GetWordParam(Param: TID4): Word;
+var
+  pdata: Pointer;
+begin
+  pdata := ParamAddr[Param];
+  if pdata <> nil then
+  begin
+    result := PU4(pdata)^;
+    ReverseByteOrder(@result, 2);
+  end
+  else
+    result := 0;
+end;
+
+procedure TLWParentChunk.Loaded;
+begin
+  Items.Loaded;
+end;
+
+procedure TLWPols.Loaded;
+begin
+  inherited;
+  CalcPntsNormals;
+end;
+
+function TLWObjectFile.TagToName(tag: TU2): string;
+var
+  TagsIdx: Integer;
+begin
+  TagsIdx := Chunks.FindChunk(@FindChunkById, @ID_TAGS);
+  if TagsIdx <> -1 then
+    result := TLWTags(Chunks[TagsIdx]).TagToName(tag);
+end;
+
+
+(******************** TLWClip ********************)
+
+class function TLWClip.GetID: TID4;
+begin
+  result := ID_CLIP;
+end;
+
+procedure TLWClip.LoadData(AStream: TStream; DataStart, DataSize: LongWord);
+var
+  CurId: TID4;
+begin
+  ReadMotorolaNumber(AStream, @FClipIndex, 4);
+  while Cardinal(AStream.Position) < (DataStart + DataSize) do
+  begin
+
+    AStream.Read(CurId, 4);
+
+    Items.Add(GetChunkClass(CurId, TLWSubChunk).Create);
+
+    with Items[Items.Count - 1] do
+    begin
+
+      FID := CurId;
+      LoadFromStream(AStream);
+
+    end;
+
+  end;
+
+end;
+
+// TLWContentDir
+
+(* function TLWContentDir.ContentSearch(AFilename: string): string;
+  var
+  i: Integer;
+  begin
+
+  if not FileExists(AFilename) then
+  begin
+
+  result := ExtractFileName(AFilename);
+
+  if not FileExists(result) then
+  begin
+
+  for i := 0 to SubDirs.Count - 1 do
+  begin
+
+  if FileExists(Root+'\'+SubDirs[i]+'\'+result) then
+  begin
+  result:=Root+'\'+SubDirs[i]+'\'+result;
+  Exit;
+  end;
+
+  end;
+  result := '';
+
+  end;
+
+  end;
+  end;
+*)
+
+destructor TLWContentDir.Destroy;
+begin
+  FreeAndNil(FSubDirs);
+  inherited;
+end;
+
+function TLWContentDir.FindContent(AFilename: string): string;
+var
+  i: Integer;
+begin
+
+  if not FileExists(AFilename) then
+  begin
+
+    result := ExtractFileName(AFilename);
+
+    if not FileExists(result) then
+    begin
+
+      for i := 0 to SubDirs.Count - 1 do
+      begin
+
+        if FileExists(Root + '\' + SubDirs[i] + '\' + result) then
+        begin
+          result := Root + '\' + SubDirs[i] + '\' + result;
+          Exit;
+        end;
+
+      end;
+      result := '';
+
+    end;
+
+  end;
+end;
+
+function TLWContentDir.GetSubDirs: TStrings;
+begin
+  if FSubDirs = nil then
+    FSubDirs := TStringList.Create;
+  result := FSubDirs;
+end;
+
+procedure TLWContentDir.SetRoot(const Value: string);
+begin
+  FRoot := Value;
+end;
+
+procedure TLWContentDir.SetSubDirs(const Value: TStrings);
+begin
+  SubDirs.Assign(Value);
+end;
+
+initialization
+
+// Pnts
+RegisterChunkClass(TLWPnts);
+
+// Pols
+RegisterChunkClass(TLWPols);
+
+// VMap
+RegisterChunkClass(TLWVMap);
+
+// Tags
+RegisterChunkClass(TLWTags);
+
+// PTAG
+RegisterChunkClass(TLWPTag);
+
+// SURF
+RegisterChunkClass(TLWSurf);
+
+// LAYR
+RegisterChunkClass(TLWLayr);
+
+// CLIP
+RegisterChunkClass(TLWClip);
+
+finalization
+
+// UnRegisterChunkClasses;
+FreeAndNil(ChunkClasses);
+FreeAndNil(ContentDir);
+
+end.

+ 4643 - 4683
Source/FileVFW.pas → Source/Formats.FileVFW.pas

@@ -1,4683 +1,4643 @@
-//
-// This unit is part of the GLScene Engine, http://glscene.org
-//
-
-unit FileVFW;
-
-(*  Video for windows *)
-
-interface
-
-{.$UNDEF UNICODE}
-{$I GLScene.inc}
-
-(****************************************************************************
- *
- *      VfW.H - Video for windows include file for WIN32
- *
- *      Copyright (c) 1991-1999, Microsoft Corp.  All rights reserved.
- *
- *      This include files defines interfaces to the following
- *      video components
- *
- *          COMPMAN         - Installable Compression Manager.
- *          DRAWDIB         - Routines for drawing to the display.
- *          VIDEO           - Video Capture Driver Interface
- *
- *          AVIFMT          - AVI File Format structure definitions.
- *          MMREG           - FOURCC and other things
- *
- *          AVIFile         - Interface for reading AVI Files and AVI Streams
- *          MCIWND          - MCI/AVI window class
- *          AVICAP          - AVI Capture Window class
- *
- *          MSACM           - Audio compression manager.
- *
- *      The following symbols control inclusion of various parts of this file:
- *
- *          NOCOMPMAN       - dont include COMPMAN
- *          NODRAWDIB       - dont include DRAWDIB
- *          NOVIDEO         - dont include video capture interface
- *
- *          NOAVIFMT        - dont include AVI file format structs
- *          NOMMREG         - dont include MMREG
- *
- *          NOAVIFILE       - dont include AVIFile interface
- *          NOMCIWND        - dont include AVIWnd class.
- *          NOAVICAP        - dont include AVICap class.
- *
- *          NOMSACM         - dont include ACM stuff.
- *
- ****************************************************************************)
-
-(******************************************************************************)
-(*                                                                            *)
-(*  VFW.PAS Conversion by Ronald Dittrich                                     *)
-(*                                                                            *)
-(*  E-Mail: [email protected]                                                 *)
-(*  http://www.swiftsoft.de                                                   *)
-(*                                                                            *)
-(******************************************************************************)
-
-(******************************************************************************)
-(*                                                                            *)
-(*  Modyfied: 25.April.2000                                                   *)
-(*                                                                            *)
-(*  E-Mail:                                                                   *)
-(*  Ivo Steinmann: [email protected]                                      *)
-(*                                                                            *)
-(*  Please send all messages regarding specific errors and lacks of this unit *)
-(*  to Ivo Steinmann                                                          *)
-(*                                                                            *)
-(******************************************************************************)
-
-(******************************************************************************)
-(*                                                                            *)
-(*  Modyfied: 2000-12-07                                                      *)
-(*                                                                            *)
-(*  E-Mail:                                                                   *)
-(*  Peter Haas: [email protected]                                        *)
-(*                                                                            *)
-(*  Only modified line 1380  ( TAVIPALCHANGE.peNew )                          *)
-(*                                                                            *)
-(******************************************************************************)
-
-uses
-    Winapi.Windows,
-    Winapi.MMSystem,
-    Winapi.Messages,
-    Winapi.CommDlg,
-    Winapi.ActiveX;
-
-(****************************************************************************
- *
- *  types
- *
- ***************************************************************************)
-
-type
-  PVOID = pointer;
-  LONG  = longint;
-  PLONG = ^LONG;
-  int   = integer;
-
-(****************************************************************************
- *
- *  VideoForWindowsVersion() - returns version of VfW
- *
- ***************************************************************************)
-
-function VideoForWindowsVersion: DWORD; pascal;
-
-(****************************************************************************
- *
- *  call these to start stop using VfW from your app.
- *
- ***************************************************************************)
-                                {
-function InitVFW: LONG; stdcall;
-function TermVFW: LONG; stdcall;  }
-
-(****************************************************************************/
-/*                                                                          */
-/*        Macros                                                            */
-/*                                                                          */
-/*  should we define this??                                                 */
-/*                                                                          */
-/****************************************************************************)
-
-function MKFOURCC(ch0, ch1, ch2, ch3: AnsiChar): FOURCC;
-
-(****************************************************************************
- *
- *  COMPMAN - Installable Compression Manager.
- *
- ****************************************************************************)
-
-const
-  ICVERSION                   = $0104 ;
-
-type
-  HIC                         = THandle;  // Handle to an Installable Compressor
-
-//
-// this code in biCompression means the DIB must be accesed via
-// 48 bit pointers! using *ONLY* the selector given.
-//
-const
-  BI_1632                     = $32333631;    // '1632'
-
-function mmioFOURCC(ch0, ch1, ch2, ch3: AnsiChar): FOURCC;
-
-type
-  TWOCC                       = word;
-
-function aviTWOCC(ch0, ch1: AnsiChar): TWOCC;
-
-const
-  ICTYPE_VIDEO                = $63646976;  {vidc}
-  ICTYPE_AUDIO                = $63647561;  {audc}
-
-const
-  ICERR_OK                    = 0 ;
-  ICERR_DONTDRAW              = 1 ;
-  ICERR_NEWPALETTE            = 2 ;
-  ICERR_GOTOKEYFRAME          = 3 ;
-  ICERR_STOPDRAWING           = 4 ;
-
-  ICERR_UNSUPPORTED           = -1 ;
-  ICERR_BADFORMAT             = -2 ;
-  ICERR_MEMORY                = -3 ;
-  ICERR_INTERNAL              = -4 ;
-  ICERR_BADFLAGS              = -5 ;
-  ICERR_BADPARAM              = -6 ;
-  ICERR_BADSIZE               = -7 ;
-  ICERR_BADHANDLE             = -8 ;
-  ICERR_CANTUPDATE            = -9 ;
-  ICERR_ABORT                 = -10 ;
-  ICERR_ERROR                 = -100 ;
-  ICERR_BADBITDEPTH           = -200 ;
-  ICERR_BADIMAGESIZE          = -201 ;
-
-  ICERR_CUSTOM                = -400 ;    // errors less than ICERR_CUSTOM...
-
-{-- Values for dwFlags of ICOpen() -------------------------------------------}
-
-  ICMODE_COMPRESS             = 1 ;
-  ICMODE_DECOMPRESS           = 2 ;
-  ICMODE_FASTDECOMPRESS       = 3 ;
-  ICMODE_QUERY                = 4 ;
-  ICMODE_FASTCOMPRESS         = 5 ;
-  ICMODE_DRAW                 = 8 ;
-
-{-- Flags for AVI file index -------------------------------------------------}
-
-  AVIIF_LIST                  = $00000001 ;
-  AVIIF_TWOCC                 = $00000002 ;
-  AVIIF_KEYFRAME              = $00000010 ;
-
-{-- quality flags ------------------------------------------------------------}
-
-  ICQUALITY_LOW               = 0 ;
-  ICQUALITY_HIGH              = 10000 ;
-  ICQUALITY_DEFAULT           = -1 ;
-
-(************************************************************************
-************************************************************************)
-
-  ICM_USER                    = (DRV_USER+$0000) ;
-
-  ICM_RESERVED_LOW            = (DRV_USER+$1000) ;
-  ICM_RESERVED_HIGH           = (DRV_USER+$2000) ;
-  ICM_RESERVED                = ICM_RESERVED_LOW ;
-
-(************************************************************************
-
-    messages.
-
-************************************************************************)
-
-  ICM_GETSTATE                = (ICM_RESERVED+0) ;    // Get compressor state
-  ICM_SETSTATE                = (ICM_RESERVED+1) ;    // Set compressor state
-  ICM_GETINFO                 = (ICM_RESERVED+2) ;    // Query info about the compressor
-
-  ICM_CONFIGURE               = (ICM_RESERVED+10);    // show the configure dialog
-  ICM_ABOUT                   = (ICM_RESERVED+11);    // show the about box
-
-  ICM_GETDEFAULTQUALITY       = (ICM_RESERVED+30);    // get the default value for quality
-  ICM_GETQUALITY              = (ICM_RESERVED+31);    // get the current value for quality
-  ICM_SETQUALITY              = (ICM_RESERVED+32);    // set the default value for quality
-
-  ICM_SET                     = (ICM_RESERVED+40);    // Tell the driver something
-  ICM_GET                     = (ICM_RESERVED+41);    // Ask the driver something
-
-{-- Constants for ICM_SET: ---------------------------------------------------}
-
-  ICM_FRAMERATE               = $526D7246;  {FrmR}
-  ICM_KEYFRAMERATE            = $5279654B;  {KeyR}
-
-(************************************************************************
-
-    ICM specific messages.
-
-************************************************************************)
-
-  ICM_COMPRESS_GET_FORMAT     = (ICM_USER+4)  ;   // get compress format or size
-  ICM_COMPRESS_GET_SIZE       = (ICM_USER+5)  ;   // get output size
-  ICM_COMPRESS_QUERY          = (ICM_USER+6)  ;   // query support for compress
-  ICM_COMPRESS_BEGIN          = (ICM_USER+7)  ;   // begin a series of compress calls.
-  ICM_COMPRESS                = (ICM_USER+8)  ;   // compress a frame
-  ICM_COMPRESS_END            = (ICM_USER+9)  ;   // end of a series of compress calls.
-
-  ICM_DECOMPRESS_GET_FORMAT   = (ICM_USER+10) ;   // get decompress format or size
-  ICM_DECOMPRESS_QUERY        = (ICM_USER+11) ;   // query support for dempress
-  ICM_DECOMPRESS_BEGIN        = (ICM_USER+12) ;   // start a series of decompress calls
-  ICM_DECOMPRESS              = (ICM_USER+13) ;   // decompress a frame
-  ICM_DECOMPRESS_END          = (ICM_USER+14) ;   // end a series of decompress calls
-  ICM_DECOMPRESS_SET_PALETTE  = (ICM_USER+29) ;   // fill in the DIB color table
-  ICM_DECOMPRESS_GET_PALETTE  = (ICM_USER+30) ;   // fill in the DIB color table
-
-  ICM_DRAW_QUERY              = (ICM_USER+31) ;   // query support for dempress
-  ICM_DRAW_BEGIN              = (ICM_USER+15) ;   // start a series of draw calls
-  ICM_DRAW_GET_PALETTE        = (ICM_USER+16) ;   // get the palette needed for drawing
-  ICM_DRAW_START              = (ICM_USER+18) ;   // start decompress clock
-  ICM_DRAW_STOP               = (ICM_USER+19) ;   // stop decompress clock
-  ICM_DRAW_END                = (ICM_USER+21) ;   // end a series of draw calls
-  ICM_DRAW_GETTIME            = (ICM_USER+32) ;   // get value of decompress clock
-  ICM_DRAW                    = (ICM_USER+33) ;   // generalized "render" message
-  ICM_DRAW_WINDOW             = (ICM_USER+34) ;   // drawing window has moved or hidden
-  ICM_DRAW_SETTIME            = (ICM_USER+35) ;   // set correct value for decompress clock
-  ICM_DRAW_REALIZE            = (ICM_USER+36) ;   // realize palette for drawing
-  ICM_DRAW_FLUSH              = (ICM_USER+37) ;   // clear out buffered frames
-  ICM_DRAW_RENDERBUFFER       = (ICM_USER+38) ;   // draw undrawn things in queue
-
-  ICM_DRAW_START_PLAY         = (ICM_USER+39) ;   // start of a play
-  ICM_DRAW_STOP_PLAY          = (ICM_USER+40) ;   // end of a play
-
-  ICM_DRAW_SUGGESTFORMAT      = (ICM_USER+50) ;   // Like ICGetDisplayFormat
-  ICM_DRAW_CHANGEPALETTE      = (ICM_USER+51) ;   // for animating palette
-
-  ICM_GETBUFFERSWANTED        = (ICM_USER+41) ;   // ask about prebuffering
-
-  ICM_GETDEFAULTKEYFRAMERATE  = (ICM_USER+42) ;   // get the default value for key frames
-
-  ICM_DECOMPRESSEX_BEGIN      = (ICM_USER+60) ;   // start a series of decompress calls
-  ICM_DECOMPRESSEX_QUERY      = (ICM_USER+61) ;   // start a series of decompress calls
-  ICM_DECOMPRESSEX            = (ICM_USER+62) ;   // decompress a frame
-  ICM_DECOMPRESSEX_END        = (ICM_USER+63) ;   // end a series of decompress calls
-
-  ICM_COMPRESS_FRAMES_INFO    = (ICM_USER+70) ;   // tell about compress to come
-  ICM_SET_STATUS_PROC         = (ICM_USER+72) ;   // set status callback
-
-(************************************************************************
-************************************************************************)
-
-type
-  PICOPEN = ^TICOPEN;
-  TICOPEN = packed record
-    dwSize                  : DWORD   ; // sizeof(ICOPEN)
-    fccType                 : DWORD   ; // 'vidc'
-    fccHandler              : DWORD   ; //
-    dwVersion               : DWORD   ; // version of compman opening you
-    dwFlags                 : DWORD   ; // LOWORD is type specific
-    dwError                 : DWORD   ; // error return.
-    pV1Reserved             : PVOID   ; // Reserved
-    pV2Reserved             : PVOID   ; // Reserved
-    dnDevNode               : DWORD   ; // Devnode for PnP devices
-  end;
-
-(************************************************************************
-************************************************************************)
-
-  PICINFO = ^TICINFO;
-  TICINFO = packed record
-    dwSize                  : DWORD;    // sizeof(ICINFO)
-    fccType                 : DWORD;    // compressor type     'vidc' 'audc'
-    fccHandler              : DWORD;    // compressor sub-type 'rle ' 'jpeg' 'pcm '
-    dwFlags                 : DWORD;    // flags LOWORD is type specific
-    dwVersion               : DWORD;    // version of the driver
-    dwVersionICM            : DWORD;    // version of the ICM used
-    //
-    // under Win32, the driver always returns UNICODE strings.
-    //
-    szName                  : array[0..15] of WChar  ; // short name
-    szDescription           : array[0..127] of WChar ; // DWORD name
-    szDriver                : array[0..127] of WChar ; // driver that contains compressor
-  end;
-
-{-- Flags for the <dwFlags> field of the <ICINFO> structure. ------------}
-
-const
-  VIDCF_QUALITY               = $0001 ;  // supports quality
-  VIDCF_CRUNCH                = $0002 ;  // supports crunching to a frame size
-  VIDCF_TEMPORAL              = $0004 ;  // supports inter-frame compress
-  VIDCF_COMPRESSFRAMES        = $0008 ;  // wants the compress all frames message
-  VIDCF_DRAW                  = $0010 ;  // supports drawing
-  VIDCF_FASTTEMPORALC         = $0020 ;  // does not need prev frame on compress
-  VIDCF_FASTTEMPORALD         = $0080 ;  // does not need prev frame on decompress
-  //VIDCF_QUALITYTIME         = $0040 ;  // supports temporal quality
-
-  //VIDCF_FASTTEMPORAL        = (VIDCF_FASTTEMPORALC or VIDCF_FASTTEMPORALD)
-
-(************************************************************************
-************************************************************************)
-
-  ICCOMPRESS_KEYFRAME         = $00000001;
-
-type
-  PICCOMPRESS = ^TICCOMPRESS;
-  TICCOMPRESS = packed record
-    dwFlags                 : DWORD;                // flags
-
-    lpbiOutput              : PBITMAPINFOHEADER ;   // output format
-    lpOutput                : PVOID ;               // output data
-
-    lpbiInput               : PBITMAPINFOHEADER ;   // format of frame to compress
-    lpInput                 : PVOID ;               // frame data to compress
-
-    lpckid                  : PDWORD ;              // ckid for data in AVI file
-    lpdwFlags               : PDWORD;               // flags in the AVI index.
-    lFrameNum               : LONG ;               // frame number of seq.
-    dwFrameSize             : DWORD ;               // reqested size in bytes. (if non zero)
-
-    dwQuality               : DWORD ;               // quality
-
-    // these are new fields
-
-    lpbiPrev                : PBITMAPINFOHEADER ;   // format of previous frame
-    lpPrev                  : PVOID ;               // previous frame
-  end;
-
-(************************************************************************
-************************************************************************)
-
-const
-  ICCOMPRESSFRAMES_PADDING    = $00000001 ;
-
-type
-  TICCompressProc    = function(lInputOutput: LPARAM; lFrame: DWORD; lpBits: PVOID; len: LONG): LONG; stdcall;
-
-  PICCOMPRESSFRAMES  = ^TICCOMPRESSFRAMES;
-  TICCOMPRESSFRAMES  = packed record
-    dwFlags                 : DWORD ;               // flags
-
-    lpbiOutput              : PBITMAPINFOHEADER ;   // output format
-    lOutput                 : LPARAM ;              // output identifier
-
-    lpbiInput               : PBITMAPINFOHEADER ;   // format of frame to compress
-    lInput                  : LPARAM ;              // input identifier
-
-    lStartFrame             : LONG ;                // start frame
-    lFrameCount             : LONG ;                // # of frames
-
-    lQuality                : LONG ;                // quality
-    lDataRate               : LONG ;                // data rate
-    lKeyRate                : LONG ;                // key frame rate
-
-    dwRate                  : DWORD ;               // frame rate, as always
-    dwScale                 : DWORD ;
-
-    dwOverheadPerFrame      : DWORD ;
-    dwReserved2             : DWORD ;
-
-    GetData                 : TICCompressProc;
-    PutData                 : TICCompressProc;
-  end;
-
-{-- Messages for Status callback ---------------------------------------------}
-
-const
-    ICSTATUS_START              = 0 ;
-    ICSTATUS_STATUS             = 1 ;   // l = % done
-    ICSTATUS_END                = 2 ;
-    ICSTATUS_ERROR              = 3 ;   // l = error string (LPSTR)
-    ICSTATUS_YIELD              = 4 ;
-
-type
-  // return nonzero means abort operation in progress
-  TICStatusProc    = function(lParam: LPARAM; message: UINT; l: LONG): LONG; stdcall;
-
-  PICSETSTATUSPROC = ^TICSETSTATUSPROC;
-  TICSETSTATUSPROC = packed record
-    dwFlags                 : DWORD ;
-    lParam                  : LPARAM ;
-    Status                  : TICStatusProc;
-  end;
-
-(************************************************************************
-************************************************************************)
-
-const
-    ICDECOMPRESS_HURRYUP        = $80000000 ;   // don't draw just buffer (hurry up!)
-    ICDECOMPRESS_UPDATE         = $40000000 ;   // don't draw just update screen
-    ICDECOMPRESS_PREROLL        = $20000000 ;   // this frame is before real start
-    ICDECOMPRESS_NULLFRAME      = $10000000 ;   // repeat last frame
-    ICDECOMPRESS_NOTKEYFRAME    = $08000000 ;   // this frame is not a key frame
-
-type
-  PICDECOMPRESS = ^TICDECOMPRESS;
-  TICDECOMPRESS = packed record
-    dwFlags                 : DWORD ;               // flags (from AVI index...)
-    lpbiInput               : PBITMAPINFOHEADER ;   // BITMAPINFO of compressed data
-                                                        // biSizeImage has the chunk size
-    lpInput                 : PVOID ;               // compressed data
-    lpbiOutput              : PBITMAPINFOHEADER ;   // DIB to decompress to
-    lpOutput                : PVOID ;
-    ckid                    : DWORD ;               // ckid from AVI file
-  end;
-
-  PICDECOMPRESSEX = ^TICDECOMPRESSEX;
-  TICDECOMPRESSEX = packed record
-
-    //
-    // same as ICM_DECOMPRESS
-    //
-
-    dwFlags                 : DWORD;
-    lpbiSrc                 : PBITMAPINFOHEADER;    // BITMAPINFO of compressed data
-    lpSrc                   : PVOID;                // compressed data
-    lpbiDst                 : PBITMAPINFOHEADER;    // DIB to decompress to
-    lpDst                   : PVOID;                // output data
-
-    //
-    // new for ICM_DECOMPRESSEX
-    //
-
-    xDst                    : int; // destination rectangle
-    yDst                    : int;
-    dxDst                   : int;
-    dyDst                   : int;
-
-    xSrc                    : int; // source rectangle
-    ySrc                    : int;
-    dxSrc                   : int;
-    dySrc                   : int;
-  end;
-
-(************************************************************************
-************************************************************************)
-
-const
-    ICDRAW_QUERY                = $00000001 ; // test for support
-    ICDRAW_FULLSCREEN           = $00000002 ; // draw to full screen
-    ICDRAW_HDC                  = $00000004 ; // draw to a HDC/HWND
-    ICDRAW_ANIMATE              = $00000008 ;   // expect palette animation
-    ICDRAW_CONTINUE             = $00000010 ;   // draw is a continuation of previous draw
-    ICDRAW_MEMORYDC             = $00000020 ;   // DC is offscreen, by the way
-    ICDRAW_UPDATING             = $00000040 ;   // We're updating, as opposed to playing
-    ICDRAW_RENDER               = $00000080 ; // used to render data not draw it
-    ICDRAW_BUFFER               = $00000100 ; // please buffer this data offscreen, we will need to update it
-
-type
-  PICDRAWBEGIN = ^TICDRAWBEGIN;
-  TICDRAWBEGIN = packed record
-    dwFlags                 : DWORD ;       // flags
-
-    hpal                    : HPALETTE ;    // palette to draw with
-    hwnd                    : HWND ;        // window to draw to
-    hdc                     : HDC ;         // HDC to draw to
-
-    xDst                    : int ;         // destination rectangle
-    yDst                    : int ;
-    dxDst                   : int ;
-    dyDst                   : int ;
-
-    lpbi                    : PBITMAPINFOHEADER ;
-                                                // format of frame to draw
-
-    xSrc                    : int ;         // source rectangle
-    ySrc                    : int ;
-    dxSrc                   : int ;
-    dySrc                   : int ;
-
-    dwRate                  : DWORD ;       // frames/second = (dwRate/dwScale)
-    dwScale                 : DWORD ;
-  end;
-
-(************************************************************************
-************************************************************************)
-
-const
-    ICDRAW_HURRYUP              = $80000000 ;   // don't draw just buffer (hurry up!)
-    ICDRAW_UPDATE               = $40000000 ;   // don't draw just update screen
-    ICDRAW_PREROLL              = $20000000 ;   // this frame is before real start
-    ICDRAW_NULLFRAME            = $10000000 ;   // repeat last frame
-    ICDRAW_NOTKEYFRAME          = $08000000 ;   // this frame is not a key frame
-
-type
-    PICDRAW                     = ^TICDRAW;
-    TICDRAW                     = packed record
-        dwFlags                 : DWORD ;   // flags
-        lpFormat                : PVOID ;   // format of frame to decompress
-        lpData                  : PVOID ;   // frame data to decompress
-        cbData                  : DWORD ;
-        lTime                   : LONG  ;   // time in drawbegin units (see dwRate and dwScale)
-    end;
-
-    PICDRAWSUGGEST              = ^TICDRAWSUGGEST;
-    TICDRAWSUGGEST              = packed record
-        lpbiIn                  : PBITMAPINFOHEADER ;   // format to be drawn
-        lpbiSuggest             : PBITMAPINFOHEADER ;   // location for suggested format (or NULL to get size)
-        dxSrc                   : int ;                 // source extent or 0
-        dySrc                   : int ;
-        dxDst                   : int ;                 // dest extent or 0
-        dyDst                   : int ;
-        hicDecompressor         : HIC ;                 // decompressor you can talk to
-    end;
-
-(************************************************************************
-************************************************************************)
-
-    PICPALETTE                  = ^TICPALETTE;
-    TICPALETTE                  = packed record
-        dwFlags                 : DWORD ;           // flags (from AVI index...)
-        iStart                  : int ;             // first palette to change
-        iLen                    : int ;             // count of entries to change.
-        lppe                    : PPALETTEENTRY ;   // palette
-    end;
-
-(************************************************************************
-
-    ICM function declarations
-
-************************************************************************)
-
-function    ICInfo(fccType, fccHandler: DWORD; lpicinfo: PICINFO) : BOOL ; stdcall ;
-function    ICInstall(fccType, fccHandler: DWORD; lParam: LPARAM; szDesc: LPSTR; wFlags: UINT) : BOOL ; stdcall ;
-function    ICRemove(fccType, fccHandler: DWORD; wFlags: UINT) : BOOL ; stdcall ;
-function    ICGetInfo(hic: HIC; picinfo: PICINFO; cb: DWORD) : DWORD ; stdcall ;
-
-function    ICOpen(fccType, fccHandler: DWORD; wMode: UINT) : HIC ; stdcall ;
-function    ICOpenFunction(fccType, fccHandler: DWORD; wMode: UINT; lpfnHandler: TFarProc) : HIC ; stdcall ;
-function    ICClose(hic: HIC) : DWORD; stdcall ;
-
-function    ICSendMessage(hic: HIC; msg: UINT; dw1, dw2: DWORD) : DWORD ; stdcall ;
-
-{-- Values for wFlags of ICInstall -------------------------------------------}
-
-const
-    ICINSTALL_UNICODE           = $8000 ;
-
-    ICINSTALL_FUNCTION          = $0001 ; // lParam is a DriverProc (function ptr)
-    ICINSTALL_DRIVER            = $0002 ; // lParam is a driver name (string)
-    ICINSTALL_HDRV              = $0004 ; // lParam is a HDRVR (driver handle)
-
-    ICINSTALL_DRIVERW           = $8002 ; // lParam is a unicode driver name
-
-{-- Query macros -------------------------------------------------------------}
-
-    ICMF_CONFIGURE_QUERY        = $00000001 ;
-    ICMF_ABOUT_QUERY            = $00000001 ;
-
-function    ICQueryAbout(hic: HIC): BOOL;
-function    ICAbout(hic: HIC; hwnd: HWND): DWORD;
-function    ICQueryConfigure(hic: HIC): BOOL;
-function    ICConfigure(hic: HIC; hwnd: HWND): DWORD;
-
-{-- Get/Set state macros -----------------------------------------------------}
-
-function    ICGetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
-function    ICSetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
-function    ICGetStateSize(hic: HIC): DWORD;
-
-{-- Get value macros ---------------------------------------------------------}
-
-function    ICGetDefaultQuality(hic: HIC): DWORD;
-function    ICGetDefaultKeyFrameRate(hic: HIC): DWORD;
-
-{-- Draw window macro --------------------------------------------------------}
-
-function    ICDrawWindow(hic: HIC; prc: PRECT): DWORD;
-
-(************************************************************************
-
-    compression functions
-
-************************************************************************/
-/*
- *  ICCompress()
- *
- *  compress a single frame
- *
- *)
-function ICCompress(
-    hic             : HIC;
-    dwFlags         : DWORD;                // flags
-    lpbiOutput      : PBITMAPINFOHEADER;    // output format
-    lpData          : PVOID;                // output data
-    lpbiInput       : PBITMAPINFOHEADER;    // format of frame to compress
-    lpBits          : PVOID;                // frame data to compress
-    lpckid          : PDWORD;               // ckid for data in AVI file
-    lpdwFlags       : PDWORD;               // flags in the AVI index.
-    lFrameNum       : DWORD;                 // frame number of seq.
-    dwFrameSize     : DWORD;                // reqested size in bytes. (if non zero)
-    dwQuality       : DWORD;                // quality within one frame
-    lpbiPrev        : PBITMAPINFOHEADER;    // format of previous frame
-    lpPrev          : PVOID                 // previous frame
-    ): DWORD; cdecl;
-
-(*
- *  ICCompressBegin()
- *
- *  start compression from a source format (lpbiInput) to a dest
- *  format (lpbiOuput) is supported.
- *
- *)
-
-function    ICCompressBegin(hic: HIC; lpbiInput: PBITMAPINFOHEADER; lpbiOutput: PBITMAPINFOHEADER): DWORD;
-
-(*
- *  ICCompressQuery()
- *
- *  determines if compression from a source format (lpbiInput) to a dest
- *  format (lpbiOuput) is supported.
- *
- *)
-
-function    ICCompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-
-(*
- *  ICCompressGetFormat()
- *
- *  get the output format, (format of compressed data)
- *  if lpbiOutput is NULL return the size in bytes needed for format.
- *
- *)
-
-function    ICCompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-function    ICCompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
-
-(*
- *  ICCompressSize()
- *
- *  return the maximal size of a compressed frame
- *
- *)
-
-function    ICCompressGetSize(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-function    ICCompressEnd(hic: HIC): DWORD;
-
-(************************************************************************
-
-    decompression functions
-
-************************************************************************)
-
-(*
- *  ICDecompress()
- *
- *  decompress a single frame
- *
- *)
-
-function    ICDecompress(
-    hic             : HIC;
-    dwFlags         : DWORD;                // flags (from AVI index...)
-    lpbiFormat      : PBITMAPINFOHEADER;    // BITMAPINFO of compressed data
-                                            // biSizeImage has the chunk size
-    lpData          : PVOID;                // data
-    lpbi            : PBITMAPINFOHEADER;    // DIB to decompress to
-    lpBits          : PVOID
-    ): DWORD; cdecl;
-
-(*
- *  ICDecompressBegin()
- *
- *  start compression from a source format (lpbiInput) to a dest
- *  format (lpbiOutput) is supported.
- *
- *)
-
-function    ICDecompressBegin(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-
-(*
- *  ICDecompressQuery()
- *
- *  determines if compression from a source format (lpbiInput) to a dest
- *  format (lpbiOutput) is supported.
- *
- *)
-
-function    ICDecompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-
-(*
- *  ICDecompressGetFormat()
- *
- *  get the output format, (format of un-compressed data)
- *  if lpbiOutput is NULL return the size in bytes needed for format.
- *
- *)
-
-function    ICDecompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-function    ICDecompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
-
-(*
- *  ICDecompressGetPalette()
- *
- *  get the output palette
- *
- *)
-
-function    ICDecompressGetPalette(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-function    ICDecompressSetPalette(hic: HIC; lpbiPalette: PBITMAPINFOHEADER): DWORD;
-
-function    ICDecompressEnd(hic: HIC): DWORD;
-
-(************************************************************************
-
-    decompression (ex) functions
-
-************************************************************************)
-
-//
-// on Win16 these functions are macros that call ICMessage. ICMessage will
-// not work on NT. rather than add new entrypoints we have given
-// them as static inline functions
-//
-
-(*
- *  ICDecompressEx()
- *
- *  decompress a single frame
- *
- *)
-
-function    ICDecompressEx(
-    hic         : HIC;
-    dwFlags     : DWORD;
-    lpbiSrc     : PBITMAPINFOHEADER;
-    lpSrc       : PVOID;
-    xSrc        : int;
-    ySrc        : int;
-    dxSrc       : int;
-    dySrc       : int;
-    lpbiDst     : PBITMAPINFOHEADER;
-    lpDst       : PVOID;
-    xDst        : int;
-    yDst        : int;
-    dxDst       : int;
-    dyDst       : int
-    ): DWORD; stdcall;
-
-(*
- *  ICDecompressExBegin()
- *
- *  start compression from a source format (lpbiInput) to a dest
- *  format (lpbiOutput) is supported.
- *
- *)
-
-function    ICDecompressExBegin(
-    hic         : HIC;
-    dwFlags     : DWORD;
-    lpbiSrc     : PBITMAPINFOHEADER;
-    lpSrc       : PVOID;
-    xSrc        : int;
-    ySrc        : int;
-    dxSrc       : int;
-    dySrc       : int;
-    lpbiDst     : PBITMAPINFOHEADER;
-    lpDst       : PVOID;
-    xDst        : int;
-    yDst        : int;
-    dxDst       : int;
-    dyDst       : int
-    ): DWORD; stdcall;
-
-(*
- *  ICDecompressExQuery()
- *
- *)
-
-function    ICDecompressExQuery(
-    hic         : HIC;
-    dwFlags     : DWORD;
-    lpbiSrc     : PBITMAPINFOHEADER;
-    lpSrc       : PVOID;
-    xSrc        : int;
-    ySrc        : int;
-    dxSrc       : int;
-    dySrc       : int;
-    lpbiDst     : PBITMAPINFOHEADER;
-    lpDst       : PVOID;
-    xDst        : int;
-    yDst        : int;
-    dxDst       : int;
-    dyDst       : int
-    ): DWORD; stdcall;
-
-function ICDecompressExEnd(hic: HIC): DWORD;
-
-(************************************************************************
-
-    drawing functions
-
-************************************************************************)
-
-(*
- *  ICDrawBegin()
- *
- *  start decompressing data with format (lpbiInput) directly to the screen
- *
- *  return zero if the decompressor supports drawing.
- *
- *)
-
-function    ICDrawBegin(
-    hic         : HIC;
-    dwFlags     : DWORD;                // flags
-    hpal        : HPALETTE;             // palette to draw with
-    hwnd        : HWND;                 // window to draw to
-    hdc         : HDC;                  // HDC to draw to
-    xDst        : int;                  // destination rectangle
-    yDst        : int;
-    dxDst       : int;
-    dyDst       : int;
-    lpbi        : PBITMAPINFOHEADER;    // format of frame to draw
-    xSrc        : int;                  // source rectangle
-    ySrc        : int;
-    dxSrc       : int;
-    dySrc       : int;
-    dwRate      : DWORD;                // frames/second = (dwRate/dwScale)
-    dwScale     : DWORD
-    ): DWORD; cdecl;
-
-(*
- *  ICDraw()
- *
- *  decompress data directly to the screen
- *
- *)
-
-function    ICDraw(
-    hic         : HIC;
-    dwFlags     : DWORD;                // flags
-    lpFormat    : PVOID;                // format of frame to decompress
-    lpData      : PVOID;                // frame data to decompress
-    cbData      : DWORD;                // size of data
-    lTime       : DWORD                  // time to draw this frame
-    ): DWORD; cdecl;
-
-// ICMessage is not supported on Win32, so provide a static inline function
-// to do the same job
-function    ICDrawSuggestFormat(
-    hic         : HIC;
-    lpbiIn      : PBITMAPINFOHEADER;
-    lpbiOut     : PBITMAPINFOHEADER;
-    dxSrc       : int;
-    dySrc       : int;
-    dxDst       : int;
-    dyDst       : int;
-    hicDecomp   : HIC
-    ): DWORD; stdcall;
-
-(*
- *  ICDrawQuery()
- *
- *  determines if the compressor is willing to render the specified format.
- *
- *)
-
-function    ICDrawQuery(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
-function    ICDrawChangePalette(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
-function    ICGetBuffersWanted(hic: HIC; lpdwBuffers: PDWORD): DWORD;
-function    ICDrawEnd(hic: HIC): DWORD;
-function    ICDrawStart(hic: HIC): DWORD;
-function    ICDrawStartPlay(hic: HIC; lFrom, lTo: DWORD): DWORD;
-function    ICDrawStop(hic: HIC): DWORD;
-function    ICDrawStopPlay(hic: HIC): DWORD;
-function    ICDrawGetTime(hic: HIC; lplTime: PDWORD): DWORD;
-function    ICDrawSetTime(hic: HIC; lTime: DWORD): DWORD;
-function    ICDrawRealize(hic: HIC; hdc: HDC; fBackground: BOOL): DWORD;
-function    ICDrawFlush(hic: HIC): DWORD;
-function    ICDrawRenderBuffer(hic: HIC): DWORD;
-
-(************************************************************************
-
-    Status callback functions
-
-************************************************************************/
-
-/*
- *  ICSetStatusProc()
- *
- *  Set the status callback function
- *
- *)
-
-
-// ICMessage is not supported on NT
-function    ICSetStatusProc(
-    hic         : HIC;
-    dwFlags     : DWORD;
-    lParam      : DWORD;
-    fpfnStatus  : TICStatusProc
-    ): DWORD; stdcall;
-
-(************************************************************************
-
-helper routines for DrawDib and MCIAVI...
-
-************************************************************************)
-
-function    ICLocate(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER; wFlags: WORD): HIC; stdcall;
-function    ICGetDisplayFormat(hic: HIC; lpbiIn, lpbiOut: PBITMAPINFOHEADER; BitDepth: int; dx, dy: int): HIC; stdcall;
-
-function    ICDecompressOpen(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER): HIC;
-function    ICDrawOpen(fccType, fccHandler: DWORD; lpbiIn: PBITMAPINFOHEADER): HIC;
-
-(************************************************************************
-Higher level functions
-************************************************************************)
-
-function    ICImageCompress(
-    hic         : HIC;                  // compressor to use
-    uiFlags     : UINT;                 // flags (none yet)
-    lpbiIn      : PBITMAPINFO;          // format to compress from
-    lpBits      : PVOID;                // data to compress
-    lpbiOut     : PBITMAPINFO;          // compress to this (NULL ==> default)
-    lQuality    : LONG;                 // quality to use
-    plSize      : PDWORD                 // compress to this size (0=whatever)
-    ): THANDLE; stdcall;
-
-function    ICImageDecompress(
-    hic         : HIC;                  // compressor to use
-    uiFlags     : UINT;                 // flags (none yet)
-    lpbiIn      : PBITMAPINFO;          // format to decompress from
-    lpBits      : PVOID;                // data to decompress
-    lpbiOut     : PBITMAPINFO           // decompress to this (NULL ==> default)
-    ): THANDLE; stdcall;
-
-{-- TCompVars ----------------------------------------------------------------}
-
-//
-// Structure used by ICSeqCompressFrame and ICCompressorChoose routines
-// Make sure this matches the autodoc in icm.c!
-//
-
-type
-  PCOMPVARS       = ^TCOMPVARS;
-  TCOMPVARS       = packed record
-        cbSize      : DWORD;            // set to sizeof(COMPVARS) before
-                                        // calling ICCompressorChoose
-        dwFlags     : DWORD;            // see below...
-        hic         : HIC;              // HIC of chosen compressor
-        fccType     : DWORD;            // basically ICTYPE_VIDEO
-        fccHandler  : DWORD;            // handler of chosen compressor or
-                                        // "" or "DIB "
-        lpbiIn      : PBITMAPINFO;      // input format
-        lpbiOut     : PBITMAPINFO;      // output format - will compress to this
-        lpBitsOut   : PVOID;
-        lpBitsPrev  : PVOID;
-        lFrame      : LONG;
-        lKey        : LONG;             // key frames how often?
-        lDataRate   : LONG;             // desired data rate KB/Sec
-        lQ          : LONG;             // desired quality
-        lKeyCount   : LONG;
-        lpState     : PVOID;            // state of compressor
-        cbState     : LONG;             // size of the state
-    end;
-
-// FLAGS for dwFlags element of COMPVARS structure:
-// set this flag if you initialize COMPVARS before calling ICCompressorChoose
-
-const
-    ICMF_COMPVARS_VALID         = $00000001;    // COMPVARS contains valid data
-
-//
-//  allows user to choose compressor, quality etc...
-//
-function    ICCompressorChoose(
-    hwnd        : HWND;                     // parent window for dialog
-    uiFlags     : UINT;                     // flags
-    pvIn        : PVOID;                    // input format (optional)
-    lpData      : PVOID;                    // input data (optional)
-    pc          : PCOMPVARS;                // data about the compressor/dlg
-    lpszTitle   : LPSTR                     // dialog title (optional)
-    ): BOOL; stdcall;
-
-// defines for uiFlags
-
-const
-    ICMF_CHOOSE_KEYFRAME        = $0001;    // show KeyFrame Every box
-    ICMF_CHOOSE_DATARATE        = $0002;    // show DataRate box
-    ICMF_CHOOSE_PREVIEW         = $0004;    // allow expanded preview dialog
-    ICMF_CHOOSE_ALLCOMPRESSORS  = $0008;    // don't only show those that
-                                            // can handle the input format
-                                            // or input data
-
-function    ICSeqCompressFrameStart(pc: PCOMPVARS; lpbiIn: PBITMAPINFO): BOOL; stdcall;
-procedure   ICSeqCompressFrameEnd(pc: PCOMPVARS); stdcall;
-
-function    ICSeqCompressFrame(
-    pc          : PCOMPVARS;                // set by ICCompressorChoose
-    uiFlags     : UINT;                     // flags
-    lpBits      : PVOID;                    // input DIB bits
-    pfKey       : PBOOL;                    // did it end up being a key frame?
-    plSize      : PDWORD                     // size to compress to/of returned image
-    ): PVOID; stdcall;
-
-procedure   ICCompressorFree(pc: PCOMPVARS); stdcall;
-
-
-(**************************************************************************
- *
- *  DRAWDIB - Routines for drawing to the display.
- *
- *************************************************************************)
-
-type
-    HDRAWDIB                    = THandle;  // hdd
-
-(*********************************************************************
-
-  DrawDib Flags
-
-**********************************************************************)
-
-const
-    DDF_UPDATE                  = $0002;    // re-draw the last DIB
-    DDF_SAME_HDC                = $0004;    // HDC same as last call (all setup)
-    DDF_SAME_DRAW               = $0008;    // draw params are the same
-    DDF_DONTDRAW                = $0010;    // dont draw frame, just decompress
-    DDF_ANIMATE                 = $0020;    // allow palette animation
-    DDF_BUFFER                  = $0040;    // always buffer image
-    DDF_JUSTDRAWIT              = $0080;    // just draw it with GDI
-    DDF_FULLSCREEN              = $0100;    // use DisplayDib
-    DDF_BACKGROUNDPAL           = $0200;    // Realize palette in background
-    DDF_NOTKEYFRAME             = $0400;    // this is a partial frame update, hint
-    DDF_HURRYUP                 = $0800;    // hurry up please!
-    DDF_HALFTONE                = $1000;    // always halftone
-
-    DDF_PREROLL                 = DDF_DONTDRAW; // Builing up a non-keyframe
-    DDF_SAME_DIB                = DDF_SAME_DRAW;
-    DDF_SAME_SIZE               = DDF_SAME_DRAW;
-
-(*********************************************************************
-
-    DrawDib functions
-
-*********************************************************************)
-
-{-- DrawDibOpen() ------------------------------------------------------------}
-
-function    DrawDibOpen: HDRAWDIB; stdcall;
-
-{-- DrawDibClose() -----------------------------------------------------------}
-
-function    DrawDibClose(hdd: HDRAWDIB): BOOL; stdcall;
-
-{-- DrawDibGetBuffer() -------------------------------------------------------}
-
-function    DrawDibGetBuffer(hdd: HDRAWDIB; lpbi: PBITMAPINFOHEADER; dwSize: DWORD; dwFlags: DWORD): PVOID; stdcall;
-
-{-- DrawDibGetPalette() - get the palette used for drawing DIBs --------------}
-
-function    DrawDibGetPalette(hdd: HDRAWDIB): HPALETTE; stdcall;
-
-{-- DrawDibSetPalette() - set the palette used for drawing DIBs --------------}
-
-function    DrawDibSetPalette(hdd: HDRAWDIB; hpal: HPALETTE): BOOL; stdcall;
-
-{-- DrawDibChangePalette() ---------------------------------------------------}
-
-function    DrawDibChangePalette(hdd: HDRAWDIB; iStart, iLen: int; lppe: PPALETTEENTRY): BOOL; stdcall;
-
-{-- DrawDibRealize() - realize the palette in a HDD --------------------------}
-
-function    DrawDibRealize(hdd: HDRAWDIB; hdc: HDC; fBackground: BOOL): UINT; stdcall;
-
-{-- DrawDibStart() - start of streaming playback -----------------------------}
-
-function    DrawDibStart(hdd: HDRAWDIB; rate: DWORD): BOOL; stdcall;
-
-{-- DrawDibStop() - start of streaming playback ------------------------------}
-
-function    DrawDibStop(hdd: HDRAWDIB): BOOL; stdcall;
-
-{-- DrawDibBegin() - prepare to draw -----------------------------------------}
-
-function    DrawDibBegin(
-    hdd         : HDRAWDIB;
-    hdc         : HDC;
-    dxDst       : int;
-    dyDst       : int;
-    lpbi        : PBITMAPINFOHEADER;
-    dxSrc       : int;
-    dySrc       : int;
-    wFlags      : UINT
-    ): BOOL; stdcall;
-
-{-- DrawDibDraw() - actually draw a DIB to the screen ------------------------}
-
-function    DrawDibDraw(
-    hdd         : HDRAWDIB;
-    hdc         : HDC;
-    xDst        : int;
-    yDst        : int;
-    dxDst       : int;
-    dyDst       : int;
-    lpbi        : PBITMAPINFOHEADER;
-    lpBits      : PVOID;
-    xSrc        : int;
-    ySrc        : int;
-    dxSrc       : int;
-    dySrc       : int;
-    wFlags      : UINT
-    ): BOOL; stdcall;
-
-{-- DrawDibUpdate() - redraw last image (may only be valid with DDF_BUFFER) --}
-
-function    DrawDibUpdate(hdd: HDRAWDIB; hdc: HDC; x, y: int): BOOL;
-
-{-- DrawDibEnd() -------------------------------------------------------------}
-
-function    DrawDibEnd(hdd: HDRAWDIB): BOOL; stdcall;
-
-{-- DrawDibTime() - for debugging purposes only ------------------------------}
-
-type
-    PDRAWDIBTIME        = ^TDRAWDIBTIME;
-    TDRAWDIBTIME        = packed record
-        timeCount       : LONG;
-        timeDraw        : LONG;
-        timeDecompress  : LONG;
-        timeDither      : LONG;
-        timeStretch     : LONG;
-        timeBlt         : LONG;
-        timeSetDIBits   : LONG;
-    end;
-
-function    DrawDibTime(hdd: HDRAWDIB; lpddtime: PDRAWDIBTIME): BOOL; stdcall;
-
-{-- Display profiling --------------------------------------------------------}
-
-const
-    PD_CAN_DRAW_DIB             = $0001;    // if you can draw at all
-    PD_CAN_STRETCHDIB           = $0002;    // basicly RC_STRETCHDIB
-    PD_STRETCHDIB_1_1_OK        = $0004;    // is it fast?
-    PD_STRETCHDIB_1_2_OK        = $0008;    // ...
-    PD_STRETCHDIB_1_N_OK        = $0010;    // ...
-
-function    DrawDibProfileDisplay(lpbi: PBITMAPINFOHEADER): DWORD; stdcall;
-
-(****************************************************************************
- *
- *  AVIFMT - AVI file format definitions
- *
- ****************************************************************************)
-
-//
-// The following is a short description of the AVI file format.  Please
-// see the accompanying documentation for a full explanation.
-//
-// An AVI file is the following RIFF form:
-//
-//  RIFF('AVI'
-//        LIST('hdrl'
-//          avih(<MainAVIHeader>)
-//                  LIST ('strl'
-//                      strh(<Stream header>)
-//                      strf(<Stream format>)
-//                      ... additional header data
-//            LIST('movi'
-//            { LIST('rec'
-//                    SubChunk...
-//                 )
-//                | SubChunk } ....
-//            )
-//            [ <AVIIndex> ]
-//      )
-//
-//  The main file header specifies how many streams are present.  For
-//  each one, there must be a stream header chunk and a stream format
-//  chunk, enlosed in a 'strl' LIST chunk.  The 'strf' chunk contains
-//  type-specific format information; for a video stream, this should
-//  be a BITMAPINFO structure, including palette.  For an audio stream,
-//  this should be a WAVEFORMAT (or PCMWAVEFORMAT) structure.
-//
-//  The actual data is contained in subchunks within the 'movi' LIST
-//  chunk.  The first two characters of each data chunk are the
-//  stream number with which that data is associated.
-//
-//  Some defined chunk types:
-//           Video Streams:
-//                  ##db:   RGB DIB bits
-//                  ##dc:   RLE8 compressed DIB bits
-//                  ##pc:   Palette Change
-//
-//           Audio Streams:
-//                  ##wb:   waveform audio bytes
-//
-// The grouping into LIST 'rec' chunks implies only that the contents of
-//   the chunk should be read into memory at the same time.  This
-//   grouping is used for files specifically intended to be played from
-//   CD-ROM.
-//
-// The index chunk at the end of the file should contain one entry for
-//   each data chunk in the file.
-//
-// Limitations for the current software:
-//  Only one video stream and one audio stream are allowed.
-//  The streams must start at the beginning of the file.
-//
-//
-// To register codec types please obtain a copy of the Multimedia
-// Developer Registration Kit from:
-//
-//  Microsoft Corporation
-//  Multimedia Systems Group
-//  Product Marketing
-//  One Microsoft Way
-//  Redmond, WA 98052-6399
-//
-
-{-- form types, list types and chunk types -----------------------------------}
-
-const
-    formtypeAVI                 = $20495641; // mmioFOURCC('A', 'V', 'I', ' ')
-    listtypeAVIHEADER           = $6C726468; // mmioFOURCC('h', 'd', 'r', 'l')
-    ckidAVIMAINHDR              = $68697661; // mmioFOURCC('a', 'v', 'i', 'h')
-    listtypeSTREAMHEADER        = $6C727473; // mmioFOURCC('s', 't', 'r', 'l')
-    ckidSTREAMHEADER            = $68727473; // mmioFOURCC('s', 't', 'r', 'h')
-    ckidSTREAMFORMAT            = $66727473; // mmioFOURCC('s', 't', 'r', 'f')
-    ckidSTREAMHANDLERDATA       = $64727473; // mmioFOURCC('s', 't', 'r', 'd')
-    ckidSTREAMNAME              = $6E727473; // mmioFOURCC('s', 't', 'r', 'n')
-
-    listtypeAVIMOVIE            = $69766F6D; // mmioFOURCC('m', 'o', 'v', 'i')
-    listtypeAVIRECORD           = $20636572; // mmioFOURCC('r', 'e', 'c', ' ')
-
-    ckidAVINEWINDEX             = $31786469; // mmioFOURCC('i', 'd', 'x', '1')
-
-{-- Stream types for the <fccType> field of the stream header ----------------}
-
-    streamtypeVIDEO             = $73646976; // mmioFOURCC('v', 'i', 'd', 's')
-    streamtypeAUDIO             = $73647561; // mmioFOURCC('a', 'u', 'd', 's')
-    streamtypeMIDI              = $7364696D; // mmioFOURCC('m', 'i', 'd', 's')
-    streamtypeTEXT              = $73747874; // mmioFOURCC('t', 'x', 't', 's')
-
-{-- Basic chunk types --------------------------------------------------------}
-
-    cktypeDIBbits               = $6264; // aviTWOCC('d', 'b')
-    cktypeDIBcompressed         = $6364; // aviTWOCC('d', 'c')
-    cktypePALchange             = $6370; // aviTWOCC('p', 'c')
-    cktypeWAVEbytes             = $6277; // aviTWOCC('w', 'b')
-
-{-- Chunk id to use for extra chunks for padding -----------------------------}
-
-    ckidAVIPADDING              = $4B4E554A; // mmioFOURCC('J', 'U', 'N', 'K')
-
-(*
-** Useful macros
-**
-** Warning: These are nasty macro, and MS C 6.0 compiles some of them
-** incorrectly if optimizations are on.  Ack.
-*)
-
-{-- Macro to get stream number out of a FOURCC ckid --------------------------}
-
-function    FromHex(n: BYTE): BYTE;
-function    StreamFromFOURCC(fcc: DWORD): BYTE;
-
-{-- Macro to get TWOCC chunk type out of a FOURCC ckid -----------------------}
-
-function    TWOCCFromFOURCC(fcc: DWORD): WORD;
-
-{-- Macro to make a ckid for a chunk out of a TWOCC and a stream num (0-255) -}
-
-function    ToHex(n: BYTE): BYTE;
-function    MAKEAVICKID(tcc: WORD; stream: BYTE): DWORD;
-
-{-- Main AVI file header -----------------------------------------------------}
-
-{-- flags for use in <dwFlags> in AVIFileHdr ---------------------------------}
-
-const
-    AVIF_HASINDEX               = $00000010;    // Index at end of file?
-    AVIF_MUSTUSEINDEX           = $00000020;
-    AVIF_ISINTERLEAVED          = $00000100;
-    AVIF_TRUSTCKTYPE            = $00000800;    // Use CKType to find key frames?
-    AVIF_WASCAPTUREFILE         = $00010000;
-    AVIF_COPYRIGHTED            = $00020000;
-
-{-- The AVI File Header LIST chunk should be padded to this size -------------}
-
-const
-    AVI_HEADERSIZE              = 2048;         // size of AVI header list
-
-type
-    PMainAVIHeader              = ^TMainAVIHeader;
-    TMainAVIHeader              = packed record
-        dwMicroSecPerFrame      : DWORD;        // frame display rate (or 0L)
-        dwMaxBytesPerSec        : DWORD;        // max. transfer rate
-        dwPaddingGranularity    : DWORD;        // pad to multiples of this
-                                                // size; normally 2K.
-        dwFlags                 : DWORD;        // the ever-present flags
-        dwTotalFrames           : DWORD;        // # frames in file
-        dwInitialFrames         : DWORD;
-        dwStreams               : DWORD;
-        dwSuggestedBufferSize   : DWORD;
-
-        dwWidth                 : DWORD;
-        dwHeight                : DWORD;
-
-        dwReserved              : array[0..3] of DWORD;
-    end;
-
-{-- Stream header ------------------------------------------------------------}
-
-const
-    AVISF_DISABLED              = $00000001;
-
-    AVISF_VIDEO_PALCHANGES      = $00010000;
-
-type
-    PAVIStreamHeader            = ^TAVIStreamHeader;
-    TAVIStreamHeader            = packed record
-        fccType                 : FOURCC;
-        fccHandler              : FOURCC;
-        dwFlags                 : DWORD;        // Contains AVITF_* flags
-        wPriority               : WORD;
-        wLanguage               : WORD;
-        dwInitialFrames         : DWORD;
-        dwScale                 : DWORD;
-        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
-        dwStart                 : DWORD;
-        dwLength                : DWORD;        // In units above...
-        dwSuggestedBufferSize   : DWORD;
-        dwQuality               : DWORD;
-        dwSampleSize            : DWORD;
-        rcFrame                 : TRECT;
-    end;
-
-{-- Flags for index ----------------------------------------------------------}
-
-const
-    AVIIF_NOTIME                = $00000100;    // this frame doesn't take any time
-    AVIIF_COMPUSE               = $0FFF0000;    // these bits are for compressor use
-
-type
-    PAVIINDEXENTRY              = ^TAVIINDEXENTRY;
-    TAVIINDEXENTRY              = packed record
-        ckid                    : DWORD;
-        dwFlags                 : DWORD;
-        dwChunkOffset           : DWORD;        // Position of chunk
-        dwChunkLength           : DWORD;        // Length of chunk
-    end;
-
-{-- Palette change chunk (used in video streams) -----------------------------}
-
-    PAVIPALCHANGE               = ^TAVIPALCHANGE;
-    TAVIPALCHANGE               = packed record
-        bFirstEntry             : BYTE;         // first entry to change
-        bNumEntries             : BYTE;         // # entries to change (0 if 256)
-        wFlags                  : WORD;         // Mostly to preserve alignment...
-        peNew                   : array[0..0] of TPALETTEENTRY; // New color specifications
-    end;
-
-(****************************************************************************
- *
- *  AVIFile - routines for reading/writing standard AVI files
- *
- ***************************************************************************)
-
-//
-// Ansi - Unicode thunking.
-//
-// Unicode or Ansi-only apps can call the avifile APIs.
-// any Win32 app who wants to use
-// any of the AVI COM interfaces must be UNICODE - the AVISTREAMINFO and
-// AVIFILEINFO structures used in the Info methods of these interfaces are
-// the unicode variants, and no thunking to or from ansi takes place
-// except in the AVIFILE api entrypoints.
-//
-// For Ansi/Unicode thunking: for each entrypoint or structure that
-// uses chars or strings, two versions are declared in the Win32 version,
-// ApiNameW and ApiNameA. The default name ApiName is #defined to one or
-// other of these depending on whether UNICODE is defined (during
-// compilation of the app that is including this header). The source will
-// contain ApiName and ApiNameA (with ApiName being the Win16 implementation,
-// and also #defined to ApiNameW, and ApiNameA being the thunk entrypoint).
-//
-
-// For GetFrame::SetFormat - use the best format for the display
-
-const
-    AVIGETFRAMEF_BESTDISPLAYFMT = 1;
-
-//
-// Structures used by AVIStreamInfo & AVIFileInfo.
-//
-// These are related to, but not identical to, the header chunks
-// in an AVI file.
-//
-
-{-- AVISTREAMINFO ------------------------------------------------------------}
-
-// for Unicode/Ansi thunking we need to declare three versions of this!
-
-type
-    PAVIStreamInfoW             = ^TAVIStreamInfoW;
-    TAVIStreamInfoW             = packed record
-        fccType                 : DWORD;
-        fccHandler              : DWORD;
-        dwFlags                 : DWORD;        // Contains AVITF_* flags
-        dwCaps                  : DWORD;
-        wPriority               : WORD;
-        wLanguage               : WORD;
-        dwScale                 : DWORD;
-        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
-        dwStart                 : DWORD;
-        dwLength                : DWORD;        // In units above...
-        dwInitialFrames         : DWORD;
-        dwSuggestedBufferSize   : DWORD;
-        dwQuality               : DWORD;
-        dwSampleSize            : DWORD;
-        rcFrame                 : TRECT;
-        dwEditCount             : DWORD;
-        dwFormatChangeCount     : DWORD;
-        szName                  : array[0..63] of WideChar;
-    end;
-
-    PAVIStreamInfoA             = ^TAVIStreamInfoA;
-    TAVIStreamInfoA             = packed record
-        fccType                 : DWORD;
-        fccHandler              : DWORD;
-        dwFlags                 : DWORD;        // Contains AVITF_* flags
-        dwCaps                  : DWORD;
-        wPriority               : WORD;
-        wLanguage               : WORD;
-        dwScale                 : DWORD;
-        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
-        dwStart                 : DWORD;
-        dwLength                : DWORD;        // In units above...
-        dwInitialFrames         : DWORD;
-        dwSuggestedBufferSize   : DWORD;
-        dwQuality               : DWORD;
-        dwSampleSize            : DWORD;
-        rcFrame                 : TRECT;
-        dwEditCount             : DWORD;
-        dwFormatChangeCount     : DWORD;
-        szName                  : array[0..63] of AnsiChar;
-    end;
-
-  PAVIStreamInfo = ^TAVIStreamInfo;
-{$IFDEF UNICODE}
-  TAVIStreamInfo = TAVIStreamInfoW;
-{$ELSE}
-  TAVIStreamInfo = TAVIStreamInfoA;
-{$ENDIF}
-
-const
-    AVISTREAMINFO_DISABLED      = $00000001;
-    AVISTREAMINFO_FORMATCHANGES = $00010000;
-
-{-- AVIFILEINFO --------------------------------------------------------------}
-
-type
-    PAVIFileInfoW               = ^TAVIFileInfoW;
-    TAVIFileInfoW               = packed record
-        dwMaxBytesPerSec        : DWORD;        // max. transfer rate
-        dwFlags                 : DWORD;        // the ever-present flags
-        dwCaps                  : DWORD;
-        dwStreams               : DWORD;
-        dwSuggestedBufferSize   : DWORD;
-
-        dwWidth                 : DWORD;
-        dwHeight                : DWORD;
-
-        dwScale                 : DWORD;
-        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
-        dwLength                : DWORD;
-
-        dwEditCount             : DWORD;
-
-        szFileType              : array[0..63] of WideChar;
-                                                // descriptive string for file type?
-    end;
-
-    PAVIFileInfoA               = ^TAVIFileInfoA;
-    TAVIFileInfoA               = packed record
-        dwMaxBytesPerSec        : DWORD;        // max. transfer rate
-        dwFlags                 : DWORD;        // the ever-present flags
-        dwCaps                  : DWORD;
-        dwStreams               : DWORD;
-        dwSuggestedBufferSize   : DWORD;
-
-        dwWidth                 : DWORD;
-        dwHeight                : DWORD;
-
-        dwScale                 : DWORD;
-        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
-        dwLength                : DWORD;
-
-        dwEditCount             : DWORD;
-
-        szFileType              : array[0..63] of AnsiChar;
-                                                // descriptive string for file type?
-    end;
-
-  PAVIFileInfo = ^TAVIFileInfo;
-{$IFDEF UNICODE}
-  TAVIFileInfo = TAVIFileInfoW;
-{$ELSE}
-  TAVIFileInfo = TAVIFileInfoA;
-{$ENDIF}
-
-{-- Flags for dwFlags --------------------------------------------------------}
-
-const
-    AVIFILEINFO_HASINDEX            = $00000010;
-    AVIFILEINFO_MUSTUSEINDEX        = $00000020;
-    AVIFILEINFO_ISINTERLEAVED       = $00000100;
-    AVIFILEINFO_WASCAPTUREFILE      = $00010000;
-    AVIFILEINFO_COPYRIGHTED         = $00020000;
-
-{-- Flags for dwCaps ---------------------------------------------------------}
-
-    AVIFILECAPS_CANREAD             = $00000001;
-    AVIFILECAPS_CANWRITE            = $00000002;
-    AVIFILECAPS_ALLKEYFRAMES        = $00000010;
-    AVIFILECAPS_NOCOMPRESSION       = $00000020;
-
-type
-    TAVISAVECALLBACK                = function(i: int): BOOL; pascal;
-
-{-- AVICOMPRESSOPTIONS -------------------------------------------------------}
-
-// Make sure it matches the AutoDoc in avisave.c !!!
-
-type
-    PAVICOMPRESSOPTIONS             = ^TAVICOMPRESSOPTIONS;
-    TAVICOMPRESSOPTIONS             = packed record
-        fccType                     : DWORD;    // stream type, for consistency
-        fccHandler                  : DWORD;    // compressor
-        dwKeyFrameEvery             : DWORD;    // keyframe rate
-        dwQuality                   : DWORD;    // compress quality 0-10,000
-        dwBytesPerSecond            : DWORD;    // bytes per second
-        dwFlags                     : DWORD;    // flags... see below
-        lpFormat                    : PVOID;    // save format
-        cbFormat                    : DWORD;
-        lpParms                     : PVOID;    // compressor options
-        cbParms                     : DWORD;
-        dwInterleaveEvery           : DWORD;    // for non-video streams only
-    end;
-
-//
-// Defines for the dwFlags field of the AVICOMPRESSOPTIONS struct
-// Each of these flags determines if the appropriate field in the structure
-// (dwInterleaveEvery, dwBytesPerSecond, and dwKeyFrameEvery) is payed
-// attention to.  See the autodoc in avisave.c for details.
-//
-
-const
-    AVICOMPRESSF_INTERLEAVE         = $00000001;    // interleave
-    AVICOMPRESSF_DATARATE           = $00000002;    // use a data rate
-    AVICOMPRESSF_KEYFRAMES          = $00000004;    // use keyframes
-    AVICOMPRESSF_VALID              = $00000008;    // has valid data?
-
-(*	-	-	-	-	-	-	-	-	*/
-
-
-/****** AVI Stream Interface *******************************************)
-
-type
-    IAVIStream = interface(IUnknown)
-        function Create(lParam1, lParam2: LPARAM): HResult; stdcall;
-        function Info(var psi: TAVIStreamInfoW; lSize: LONG): HResult; stdcall;
-        function FindSample(lPos: LONG; lFlags: LONG): LONG; stdcall;
-        function ReadFormat(lPos: LONG; lpFormat: PVOID; var lpcbFormat: LONG): HResult; stdcall;
-        function SetFormat(lPos: LONG; lpFormat: PVOID; cbFormat: LONG): HResult; stdcall;
-        function Read(lStart: LONG; lSamples: LONG; lpBuffer: PVOID; cbBuffer: LONG; var plBytes, plSamples: LONG): HResult; stdcall;
-        function Write(lStart: LONG; lSamples: LONG; lpBuffer: PVOID; cbBuffer: LONG; dwFlags: DWORD; var plSampWritten, plBytesWritten: LONG): HResult; stdcall;
-        function Delete(lStart: LONG; lSamples: LONG): HResult; stdcall;
-        function ReadData(fcc: DWORD; lp: PVOID; var lpcb: LONG): HResult; stdcall;
-        function WriteData(fcc: DWORD; lp: PVOID; cb: LONG): HResult; stdcall;
-        function SetInfo(var lpInfo: TAVIStreamInfoW; cbInfo: LONG): HResult; stdcall;
-    end;
-
-    IAVIStreaming = interface(IUnknown)
-        function _Begin(lStart, lEnd : LONG; lRate : LONG): HResult; stdcall;
-        function _End: HResult; stdcall;
-    end;
-
-    IAVIEditStream = interface(IUnknown)
-        function Cut(var plStart, plLength: LONG; var ppResult: IAVIStream): HResult; stdcall;
-        function Copy(var plStart, plLength: LONG; var ppResult: IAVIStream): HResult; stdcall;
-        function Paste(var plPos: LONG; var plLength: LONG; pstream: IAVIStream; lStart, lEnd: LONG): HResult; stdcall;
-        function Clone(var ppResult: IAVIStream): HResult; stdcall;
-        function SetInfo(var lpInfo: TAVIStreamInfoW; cbInfo: LONG): HResult; stdcall;
-    end;
-
-{-- AVIFile ------------------------------------------------------------------}
-
-    IAVIFile = interface(IUnknown)
-        function Info(var pfi: TAVIFileInfoW; iSize: LONG): HResult; stdcall;
-        function GetStream(var ppStream: IAVISTREAM; fccType: DWORD; lParam: LONG): HResult; stdcall;
-        function CreateStream(var ppStream: IAVISTREAM; var psi: TAVIStreamInfoW): HResult; stdcall;
-        function WriteData(ckid: DWORD; lpData: PVOID; cbData: LONG): HResult; stdcall;
-        function ReadData(ckid: DWORD; lpData: PVOID; lpcbData: PLONG): HResult; stdcall;
-        function EndRecord: HResult; stdcall;
-        function DeleteStream(fccType: DWORD; lParam: LONG): HResult; stdcall;
-    end;
-
-{-- GetFrame -----------------------------------------------------------------}
-
-     // The functions 'BeginExtraction' and 'EndExtraction' have actually
-     // the names 'Begin' and 'End', but we cannot use that identifiers for
-     // obvious reasons.
-
-     IGetFrame = interface(IUnknown)
-       function GetFrame(lPos: LONG): PBitmapInfoHeader; stdcall;
-       function BeginExtraction(lStart, lEnd, lRate: LONG): HResult; stdcall;
-       function EndExtraction: HResult; stdcall;
-       function SetFormat(var lpbi: TBitmapInfoHeader; lpBits: Pointer; x, y, dx, dy: Integer): HResult; stdcall;
-     end;
-
-{-- GUIDs --------------------------------------------------------------------}
-
-const
-    IID_IAVIFile      : TGUID = (D1: $00020020; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
-    IID_IAVIStream    : TGUID = (D1: $00020021; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
-    IID_IAVIStreaming : TGUID = (D1: $00020022; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
-    IID_IGetFrame     : TGUID = (D1: $00020023; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
-    IID_IAVIEditStream: TGUID = (D1: $00020024; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
-
-    CLSID_AVISimpleUnMarshal : TGUID = (D1: $00020009; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
-    CLSID_AVIFile            : TGUID = (D1: $00020000; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
-
-    AVIFILEHANDLER_CANREAD          = $0001;
-    AVIFILEHANDLER_CANWRITE         = $0002;
-    AVIFILEHANDLER_CANACCEPTNONRGB  = $0004;
-
-{-- Functions ----------------------------------------------------------------}
-
-procedure   AVIFileInit; stdcall;   // Call this first!
-procedure   AVIFileExit; stdcall;
-
-function    AVIFileAddRef(pfile: IAVIFile): ULONG; stdcall;
-function    AVIFileRelease(pfile: IAVIFile): ULONG; stdcall;
-
-function    AVIFileOpenA(var ppfile: IAVIFile; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
-function    AVIFileOpenW(var ppfile: IAVIFile; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
-
-{$IFDEF UNICODE}
-function    AVIFileOpen(var ppfile: IAVIFile; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
-{$ELSE}
-function    AVIFileOpen(var ppfile: IAVIFile; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
-{$ENDIF}
-
-function    AVIFileInfoW(pfile: IAVIFile; var pfi: TAVIFILEINFOW; lSize: LONG): HResult; stdcall;
-function    AVIFileInfoA(pfile: IAVIFile; var pfi: TAVIFILEINFOA; lSize: LONG): HResult; stdcall;
-
-function    AVIFileInfo(pfile: IAVIFile; var pfi: TAVIFILEINFO; lSize: LONG): HResult; stdcall;
-
-function    AVIFileGetStream(pfile: IAVIFile; var ppavi: IAVISTREAM; fccType: DWORD; lParam: LONG): HResult; stdcall;
-
-function    AVIFileCreateStreamW(pfile: IAVIFile; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOW): HResult; stdcall;
-function    AVIFileCreateStreamA(pfile: IAVIFile; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOA): HResult; stdcall;
-
-function    AVIFileCreateStream(pfile: IAVIFile; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFO): HResult; stdcall;
-
-function    AVIFileWriteData(pfile: IAVIFile; ckid: DWORD; lpData: PVOID; cbData: LONG): HResult; stdcall;
-function    AVIFileReadData(pfile: IAVIFile; ckid: DWORD; lpData: PVOID; var lpcbData: LONG): HResult; stdcall;
-function    AVIFileEndRecord(pfile: IAVIFile): HResult; stdcall;
-
-function    AVIStreamAddRef(pavi: IAVIStream): ULONG; stdcall;
-function    AVIStreamRelease(pavi: IAVIStream): ULONG; stdcall;
-
-function    AVIStreamInfoW (pavi: IAVIStream; var psi: TAVISTREAMINFOW; lSize: LONG): HResult; stdcall;
-function    AVIStreamInfoA (pavi: IAVIStream; var psi: TAVISTREAMINFOA; lSize: LONG): HResult; stdcall;
-
-function    AVIStreamInfo(pavi: IAVIStream; var psi: TAVISTREAMINFO; lSize: LONG): HResult; stdcall;
-
-function    AVIStreamFindSample(pavi: IAVIStream; lPos: LONG; lFlags: LONG): LONG; stdcall;
-function    AVIStreamReadFormat(pavi: IAVIStream; lPos: LONG; lpFormat: PVOID; lpcbFormat: PLONG): HResult; stdcall;
-function    AVIStreamSetFormat(pavi: IAVIStream; lPos: LONG; lpFormat: PVOID; cbFormat: LONG): HResult; stdcall;
-function    AVIStreamReadData(pavi: IAVIStream; fcc: DWORD; lp: PVOID; lpcb: PLONG): HResult; stdcall;
-function    AVIStreamWriteData(pavi: IAVIStream; fcc: DWORD; lp: PVOID; cb: LONG): HResult; stdcall;
-
-function    AVIStreamRead(
-    pavi            : IAVISTREAM;
-    lStart          : LONG;
-    lSamples        : LONG;
-    lpBuffer        : PVOID;
-    cbBuffer        : LONG;
-    plBytes         : PLONG;
-    plSamples       : PLONG
-    ): HResult; stdcall;
-
-const
-    AVISTREAMREAD_CONVENIENT    = -1;
-
-function    AVIStreamWrite(
-    pavi            : IAVISTREAM;
-    lStart          : LONG;
-    lSamples        : LONG;
-    lpBuffer        : PVOID;
-    cbBuffer        : LONG;
-    dwFlags         : DWORD;
-    plSampWritten   : PLONG;
-    plBytesWritten  : PLONG
-    ): HResult; stdcall;
-
-// Right now, these just use AVIStreamInfo() to get information, then
-// return some of it.  Can they be more efficient?
-
-function    AVIStreamStart(pavi: IAVIStream): LONG; stdcall;
-function    AVIStreamLength(pavi: IAVIStream): LONG; stdcall;
-function    AVIStreamTimeToSample(pavi: IAVIStream; lTime: LONG): LONG; stdcall;
-function    AVIStreamSampleToTime(pavi: IAVIStream; lSample: LONG): LONG; stdcall;
-
-function    AVIStreamBeginStreaming(pavi: IAVIStream; lStart, lEnd: LONG; lRate: LONG): HResult; stdcall;
-function    AVIStreamEndStreaming(pavi: IAVIStream): HResult; stdcall;
-
-{-- Helper functions for using IGetFrame -------------------------------------}
-
-function    AVIStreamGetFrameOpen(pavi: IAVIStream; lpbiWanted: PBitmapInfoHeader): IGetFrame; stdcall;
-function    AVIStreamGetFrame(pg: IGetFrame; lPos: LONG): PBitmapInfoHeader; stdcall;
-function    AVIStreamGetFrameClose(pg: IGetFrame): HResult; stdcall;
-
-// !!! We need some way to place an advise on a stream....
-// STDAPI AVIStreamHasChanged   (PAVISTREAM pavi);
-
-{-- Shortcut function --------------------------------------------------------}
-
-function    AVIStreamOpenFromFileA(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
-                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
-function    AVIStreamOpenFromFileW(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
-                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
-
-{$IFDEF UNICODE}
-   function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
-     lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
-{$ELSE}
-   function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
-     lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
-{$ENDIF}
-
-{-- Use to create disembodied streams ----------------------------------------}
-
-function    AVIStreamCreate(var ppavi: IAVISTREAM; lParam1, lParam2: LONG; pclsidHandler: PCLSID): HResult; stdcall;
-
-// PHANDLER    AVIAPI AVIGetHandler         (PAVISTREAM pavi, PAVISTREAMHANDLER psh);
-// PAVISTREAM  AVIAPI AVIGetStream          (PHANDLER p);
-
-{-- Flags for AVIStreamFindSample --------------------------------------------}
-
-const
-    FIND_DIR                        = $0000000F;    // direction
-    FIND_NEXT                       = $00000001;    // go forward
-    FIND_PREV                       = $00000004;    // go backward
-    FIND_FROM_START                 = $00000008;    // start at the logical beginning
-
-    FIND_TYPE                       = $000000F0;    // type mask
-    FIND_KEY                        = $00000010;    // find key frame.
-    FIND_ANY                        = $00000020;    // find any (non-empty) sample
-    FIND_FORMAT                     = $00000040;    // find format change
-
-    FIND_RET                        = $0000F000;    // return mask
-    FIND_POS                        = $00000000;    // return logical position
-    FIND_LENGTH                     = $00001000;    // return logical size
-    FIND_OFFSET                     = $00002000;    // return physical position
-    FIND_SIZE                       = $00003000;    // return physical size
-    FIND_INDEX                      = $00004000;    // return physical index position
-
-{-- Stuff to support backward compat. ----------------------------------------}
-
-function    AVIStreamFindKeyFrame(var pavi: IAVISTREAM; lPos: LONG; lFlags: LONG): DWORD; stdcall; // AVIStreamFindSample
-
-// Non-portable: this is alias for method name
-// FindKeyFrame FindSample
-
-function    AVIStreamClose(pavi: IAVISTREAM): ULONG; stdcall; // AVIStreamRelease
-function    AVIFileClose(pfile: IAVIFILE): ULONG; stdcall; // AVIFileRelease
-procedure   AVIStreamInit; stdcall; // AVIFileInit
-procedure   AVIStreamExit; stdcall; // AVIFileExit
-
-const
-    SEARCH_NEAREST                  = FIND_PREV;
-    SEARCH_BACKWARD                 = FIND_PREV;
-    SEARCH_FORWARD                  = FIND_NEXT;
-    SEARCH_KEY                      = FIND_KEY;
-    SEARCH_ANY                      = FIND_ANY;
-
-{-- Helper macros ------------------------------------------------------------}
-
-function    AVIStreamSampleToSample(pavi1, pavi2: IAVISTREAM; l: LONG): LONG;
-function    AVIStreamNextSample(pavi: IAVISTREAM; l: LONG): LONG;
-function    AVIStreamPrevSample(pavi: IAVISTREAM; l: LONG): LONG;
-function    AVIStreamNearestSample(pavi: IAVISTREAM; l: LONG): LONG;
-function    AVIStreamNextKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
-function    AVIStreamPrevKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
-function    AVIStreamNearestKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
-function    AVIStreamIsKeyFrame(pavi: IAVISTREAM; l: LONG): BOOL;
-function    AVIStreamPrevSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
-function    AVIStreamNextSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
-function    AVIStreamNearestSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
-function    AVIStreamNextKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
-function    AVIStreamPrevKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
-function    AVIStreamNearestKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
-function    AVIStreamStartTime(pavi: IAVISTREAM): LONG;
-function    AVIStreamLengthTime(pavi: IAVISTREAM): LONG;
-function    AVIStreamEnd(pavi: IAVISTREAM): LONG;
-function    AVIStreamEndTime(pavi: IAVISTREAM): LONG;
-function    AVIStreamSampleSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): LONG;
-function    AVIStreamFormatSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): HResult;
-function    AVIStreamDataSize(pavi: IAVISTREAM; fcc: DWORD; plSize: PLONG): HResult;
-
-{== AVISave routines and structures ==========================================}
-
-const
-    comptypeDIB                     = $20424944; // mmioFOURCC('D', 'I', 'B', ' ')
-
-function    AVIMakeCompressedStream(
-    var ppsCompressed   : IAVISTREAM;
-    ppsSource           : IAVISTREAM;
-    lpOptions           : PAVICOMPRESSOPTIONS;
-    pclsidHandler       : PCLSID
-    ): HResult; stdcall;
-
-// Non-portable: uses variable number of params
-// EXTERN_C HRESULT CDECL AVISaveA (LPCSTR               szFile,
-//      CLSID FAR *pclsidHandler,
-//      AVISAVECALLBACK     lpfnCallback,
-//      int                 nStreams,
-//      PAVISTREAM      pfile,
-//      LPAVICOMPRESSOPTIONS lpOptions,
-//      ...);
-
-function    AVISaveVA(
-    szFile          : LPCSTR;
-    pclsidHandler   : PCLSID;
-    lpfnCallback    : TAVISAVECALLBACK;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): HResult; stdcall;
-
-// Non-portable: uses variable number of params
-// EXTERN_C HRESULT CDECL AVISaveW (LPCWSTR               szFile,
-//      CLSID FAR *pclsidHandler,
-//      AVISAVECALLBACK     lpfnCallback,
-//      int                 nStreams,
-//      PAVISTREAM      pfile,
-//      LPAVICOMPRESSOPTIONS lpOptions,
-//      ...);
-
-function    AVISaveVW(
-    szFile          : LPCWSTR;
-    pclsidHandler   : PCLSID;
-    lpfnCallback    : TAVISAVECALLBACK;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): HResult; stdcall;
-
-// #define AVISave      AVISaveA
-
-function    AVISaveV(
-    szFile          : LPCSTR;
-    pclsidHandler   : PCLSID;
-    lpfnCallback    : TAVISAVECALLBACK;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): HResult; stdcall; // AVISaveVA
-
-function    AVISaveOptions(
-    hwnd            : HWND;
-    uiFlags         : UINT;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): BOOL; stdcall;
-
-function    AVISaveOptionsFree(nStreams: int; var plpOptions: PAVICOMPRESSOPTIONS): HResult; stdcall;
-
-{-- FLAGS FOR uiFlags --------------------------------------------------------}
-
-// Same as the flags for ICCompressorChoose (see compman.h)
-// These determine what the compression options dialog for video streams
-// will look like.
-
-function    AVIBuildFilterW(lpszFilter: LPWSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall;
-function    AVIBuildFilterA(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall;
-
-function    AVIBuildFilter(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; // AVIBuildFilterA
-
-function    AVIMakeFileFromStreams(var ppfile: IAVIFILE; nStreams: int; var papStreams: IAVISTREAM): HResult; stdcall;
-
-function    AVIMakeStreamFromClipboard(cfFormat: UINT; hGlobal: THANDLE; var ppstream: IAVISTREAM): HResult; stdcall;
-
-{-- Clipboard routines -------------------------------------------------------}
-
-function    AVIPutFileOnClipboard(pf: IAVIFILE): HResult; stdcall;
-function    AVIGetFromClipboard(var lppf: IAVIFILE): HResult; stdcall;
-function    AVIClearClipboard: HResult; stdcall;
-
-{-- Editing routines ---------------------------------------------------------}
-
-function    CreateEditableStream(var ppsEditable: IAVISTREAM; psSource: IAVISTREAM): HResult; stdcall;
-
-function    EditStreamCut(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall;
-
-function    EditStreamCopy(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall;
-
-function    EditStreamPaste(pavi: IAVISTREAM; var plPos, plLength: LONG; pstream: IAVISTREAM; lStart, lEnd: LONG): HResult; stdcall;
-
-function    EditStreamClone(pavi: IAVISTREAM; var ppResult: IAVISTREAM): HResult; stdcall;
-
-function    EditStreamSetNameA(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall;
-function    EditStreamSetNameW(pavi: IAVISTREAM; lpszName: LPCWSTR): HResult; stdcall;
-function    EditStreamSetInfoW(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOW; cbInfo: LONG): HResult; stdcall;
-function    EditStreamSetInfoA(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall;
-
-function    EditStreamSetInfo(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall; // EditStreamSetInfoA
-function    EditStreamSetName(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall; // EditStreamSetNameA
-
-{-- Error handling -----------------------------------------------------------}
-
-const
-    AVIERR_OK                       = 0;
-
-// !!! Questions to be answered:
-// How can you get a string form of these errors?
-// Which of these errors should be replaced by errors in SCODE.H?
-
-const
-    AVIERR_UNSUPPORTED              = $80044065; // MAKE_AVIERR(101)
-    AVIERR_BADFORMAT                = $80044066; // MAKE_AVIERR(102)
-    AVIERR_MEMORY                   = $80044067; // MAKE_AVIERR(103)
-    AVIERR_INTERNAL                 = $80044068; // MAKE_AVIERR(104)
-    AVIERR_BADFLAGS                 = $80044069; // MAKE_AVIERR(105)
-    AVIERR_BADPARAM                 = $8004406A; // MAKE_AVIERR(106)
-    AVIERR_BADSIZE                  = $8004406B; // MAKE_AVIERR(107)
-    AVIERR_BADHANDLE                = $8004406C; // MAKE_AVIERR(108)
-    AVIERR_FILEREAD                 = $8004406D; // MAKE_AVIERR(109)
-    AVIERR_FILEWRITE                = $8004406E; // MAKE_AVIERR(110)
-    AVIERR_FILEOPEN                 = $8004406F; // MAKE_AVIERR(111)
-    AVIERR_COMPRESSOR               = $80044070; // MAKE_AVIERR(112)
-    AVIERR_NOCOMPRESSOR             = $80044071; // MAKE_AVIERR(113)
-    AVIERR_READONLY                 = $80044072; // MAKE_AVIERR(114)
-    AVIERR_NODATA                   = $80044073; // MAKE_AVIERR(115)
-    AVIERR_BUFFERTOOSMALL           = $80044074; // MAKE_AVIERR(116)
-    AVIERR_CANTCOMPRESS             = $80044075; // MAKE_AVIERR(117)
-    AVIERR_USERABORT                = $800440C6; // MAKE_AVIERR(198)
-    AVIERR_ERROR                    = $800440C7; // MAKE_AVIERR(199)
-
-{== MCIWnd - Window class for MCI objects ====================================}
-
-//
-//  MCIWnd
-//
-//    MCIWnd window class header file.
-//
-//    the MCIWnd window class is a window class for controling MCI devices
-//    MCI devices include, wave files, midi files, AVI Video, cd audio,
-//    vcr, video disc, and others..
-//
-//    to learn more about MCI and mci command sets see the
-//    "Microsoft Multimedia Programmers's guide" in the Win31 SDK
-//
-//    the easiest use of the MCIWnd class is like so:
-//
-//          hwnd = MCIWndCreate(hwndParent, hInstance, 0, "chimes.wav");
-//          ...
-//          MCIWndPlay(hwnd);
-//          MCIWndStop(hwnd);
-//          MCIWndPause(hwnd);
-//          ....
-//          MCIWndDestroy(hwnd);
-//
-//    this will create a window with a play/pause, stop and a playbar
-//    and start the wave file playing.
-//
-//    mciwnd.h defines macros for all the most common MCI commands, but
-//    any string command can be used if needed.
-//
-//    Note: unlike the mciSendString() API, no alias or file name needs
-//    to be specifed, since the device to use is implied by the window handle.
-//
-//          MCIWndSendString(hwnd, "setaudio stream to 2");
-//
-//    (C) Copyright Microsoft Corp. 1991-1995.  All rights reserved.
-//
-// WIN32:
-//
-//    MCIWnd supports both ansi and unicode interfaces. For any message that
-//    takes or returns a text string, two versions of the message are defined,
-//    appended with A or W for Ansi or Wide Char. The message or api itself
-//    is defined to be one or other of these depending on whether you have
-//    UNICODE defined in your application.
-//    Thus for the api MCIWndCreate, there are in fact two apis,
-//    MCIWndCreateA and MCIWndCreateW. If you call MCIWndCreate, this will be
-//    re-routed to MCIWndCreateA unless UNICODE is defined when building your
-//    application. In any one application, you can mix calls to the
-//    Ansi and Unicode entrypoints.
-//
-//    If you use SendMessage instead of the macros below such as MCIWndOpen(),
-//    you will see that the messages have changed for WIN32, to support Ansi
-//    and Unicode entrypoints. In particular, MCI_OPEN has been replaced by
-//    MCWNDM_OPENA, or MCIWNDM_OPENW (MCIWNDM_OPEN is defined to be one or
-//    other of these).
-//
-//    Also, note that the WIN32 implementation of MCIWnd uses UNICODE
-//    so all apis and messages supporting ANSI strings do so by mapping them
-//    UNICODE strings and then calling the corresponding UNICODE entrypoint.
-//
-
-function    MCIWndSM(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): DWORD;
-
-const                               
-    MCIWND_WINDOW_CLASS             = 'MCIWndClass' ;
-
-function    MCIWndCreateA(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl;
-function    MCIWndCreateW(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCWSTR): HWND; cdecl;
-
-function    MCIWndCreate(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl; // MCIWndCreateA
-
-function    MCIWndRegisterClass: BOOL; cdecl;
-
-{-- Flags for the MCIWndOpen command -----------------------------------------}
-
-const
-    MCIWNDOPENF_NEW                 = $0001;    // open a new file
-
-{-- Window styles ------------------------------------------------------------}
-
-    MCIWNDF_NOAUTOSIZEWINDOW        = $0001;    // when movie size changes
-    MCIWNDF_NOPLAYBAR               = $0002;    // no toolbar
-    MCIWNDF_NOAUTOSIZEMOVIE         = $0004;    // when window size changes
-    MCIWNDF_NOMENU                  = $0008;    // no popup menu from RBUTTONDOWN
-    MCIWNDF_SHOWNAME                = $0010;    // show name in caption
-    MCIWNDF_SHOWPOS                 = $0020;    // show position in caption
-    MCIWNDF_SHOWMODE                = $0040;    // show mode in caption
-    MCIWNDF_SHOWALL                 = $0070;    // show all
-
-    MCIWNDF_NOTIFYMODE              = $0100;    // tell parent of mode change
-    MCIWNDF_NOTIFYPOS               = $0200;    // tell parent of pos change
-    MCIWNDF_NOTIFYSIZE              = $0400;    // tell parent of size change
-    MCIWNDF_NOTIFYERROR             = $1000;    // tell parent of an error
-    MCIWNDF_NOTIFYALL               = $1F00;    // tell all
-
-    MCIWNDF_NOTIFYANSI              = $0080;
-
-// The MEDIA notification includes a text string.
-// To receive notifications in ANSI instead of unicode set the
-// MCIWNDF_NOTIFYANSI style bit. The macro below includes this bit
-// by default unless you define UNICODE in your application.
-
-    MCIWNDF_NOTIFYMEDIAA            = $0880;    // tell parent of media change
-    MCIWNDF_NOTIFYMEDIAW            = $0800;    // tell parent of media change
-
-    MCIWNDF_NOTIFYMEDIA             = MCIWNDF_NOTIFYMEDIAA;
-
-    MCIWNDF_RECORD                  = $2000;    // Give a record button
-    MCIWNDF_NOERRORDLG              = $4000;    // Show Error Dlgs for MCI cmds?
-    MCIWNDF_NOOPEN                  = $8000;    // Don't allow user to open things
-
-{-- Can macros ---------------------------------------------------------------}
-
-function    MCIWndCanPlay(hwnd: HWND): BOOL;
-function    MCIWndCanRecord(hwnd: HWND): BOOL;
-function    MCIWndCanSave(hwnd: HWND): BOOL;
-function    MCIWndCanWindow(hwnd: HWND): BOOL;
-function    MCIWndCanEject(hwnd: HWND): BOOL;
-function    MCIWndCanConfig(hwnd: HWND): BOOL;
-function    MCIWndPaletteKick(hwnd: HWND): BOOL;
-
-function    MCIWndSave(hwnd: HWND; szFile: LPCSTR): DWORD;
-function    MCIWndSaveDialog(hwnd: HWND): DWORD;
-
-// If you dont give a device it will use the current device....
-
-function    MCIWndNew(hwnd: HWND; lp: PVOID): DWORD;
-function    MCIWndRecord(hwnd: HWND): DWORD;
-function    MCIWndOpen(hwnd: HWND; sz: LPCSTR; f: BOOL): DWORD;
-function    MCIWndOpenDialog(hwnd: HWND): DWORD;
-function    MCIWndClose(hwnd: HWND): DWORD;
-function    MCIWndPlay(hwnd: HWND): DWORD;
-function    MCIWndStop(hwnd: HWND): DWORD;
-function    MCIWndPause(hwnd: HWND): DWORD;
-function    MCIWndResume(hwnd: HWND): DWORD;
-function    MCIWndSeek(hwnd: HWND; lPos: DWORD): DWORD;
-function    MCIWndEject(hwnd: HWND): DWORD;
-
-function    MCIWndHome(hwnd: HWND): DWORD;
-function    MCIWndEnd(hwnd: HWND): DWORD;
-
-function    MCIWndGetSource(hwnd: HWND; prc: PRECT): DWORD;
-function    MCIWndPutSource(hwnd: HWND; prc: PRECT): DWORD;
-
-function    MCIWndGetDest(hwnd: HWND; prc: PRECT): DWORD;
-function    MCIWndPutDest(hwnd: HWND; prc: PRECT): DWORD;
-
-function    MCIWndPlayReverse(hwnd: HWND): DWORD;
-function    MCIWndPlayFrom(hwnd: HWND; lPos: DWORD): DWORD;
-function    MCIWndPlayTo(hwnd: HWND; lPos: DWORD): DWORD;
-function    MCIWndPlayFromTo(hwnd: HWND; lStart, lEnd: DWORD): DWORD;
-
-function    MCIWndGetDeviceID(hwnd: HWND): UINT;
-function    MCIWndGetAlias(hwnd: HWND): UINT;
-function    MCIWndGetMode(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-function    MCIWndGetPosition(hwnd: HWND): DWORD;
-function    MCIWndGetPositionString(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-function    MCIWndGetStart(hwnd: HWND): DWORD;
-function    MCIWndGetLength(hwnd: HWND): DWORD;
-function    MCIWndGetEnd(hwnd: HWND): DWORD;
-
-function    MCIWndStep(hwnd: HWND; n: DWORD): DWORD;
-
-procedure   MCIWndDestroy(hwnd: HWND);
-procedure   MCIWndSetZoom(hwnd: HWND; iZoom: UINT);
-function    MCIWndGetZoom(hwnd: HWND): UINT;
-function    MCIWndSetVolume(hwnd: HWND; iVol: UINT): DWORD;
-function    MCIWndGetVolume(hwnd: HWND): DWORD;
-function    MCIWndSetSpeed(hwnd: HWND; iSpeed: UINT): DWORD;
-function    MCIWndGetSpeed(hwnd: HWND): DWORD;
-function    MCIWndSetTimeFormat(hwnd: HWND; lp: LPCSTR): DWORD;
-function    MCIWndGetTimeFormat(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-procedure   MCIWndValidateMedia(hwnd: HWND);
-
-procedure   MCIWndSetRepeat(hwnd: HWND; f: BOOL);
-function    MCIWndGetRepeat(hwnd: HWND): BOOL;
-
-function    MCIWndUseFrames(hwnd: HWND): DWORD;
-function    MCIWndUseTime(hwnd: HWND): DWORD;
-
-procedure   MCIWndSetActiveTimer(hwnd: HWND; active: UINT);
-procedure   MCIWndSetInactiveTimer(hwnd: HWND; inactive: UINT);
-procedure   MCIWndSetTimers(hwnd: HWND; active, inactive: UINT);
-function    MCIWndGetActiveTimer(hwnd: HWND): UINT;
-function    MCIWndGetInactiveTimer(hwnd: HWND): UINT;
-
-function    MCIWndRealize(hwnd: HWND; fBkgnd: BOOL): DWORD;
-
-function    MCIWndSendString(hwnd: HWND; sz: LPCSTR): DWORD;
-function    MCIWndReturnString(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-function    MCIWndGetError(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-
-// #define MCIWndActivate(hwnd, f)     (void)MCIWndSM(hwnd, WM_ACTIVATE, (WPARAM)(BOOL)(f), 0)
-
-function    MCIWndGetPalette(hwnd: HWND): HPALETTE;
-function    MCIWndSetPalette(hwnd: HWND; hpal: HPALETTE): DWORD;
-
-function    MCIWndGetFileName(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-function    MCIWndGetDevice(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-
-function    MCIWndGetStyles(hwnd: HWND): UINT;
-function    MCIWndChangeStyles(hwnd: HWND; mask: UINT; value: DWORD): DWORD;
-
-type
-    PUnknown    = ^IUnknown;
-
-function    MCIWndOpenInterface(hwnd: HWND; pUnk: PUnknown): DWORD;
-
-function    MCIWndSetOwner(hwnd: HWND; hwndP: HWND): DWORD;
-
-{-- Messages an app will send to MCIWND --------------------------------------}
-
-// all the text-related messages are defined out of order above (they need
-// to be defined before the MCIWndOpen() macros
-
-const
-    MCIWNDM_GETDEVICEID             = WM_USER + 100;
-    MCIWNDM_GETSTART                = WM_USER + 103;
-    MCIWNDM_GETLENGTH               = WM_USER + 104;
-    MCIWNDM_GETEND                  = WM_USER + 105;
-    MCIWNDM_EJECT                   = WM_USER + 107;
-    MCIWNDM_SETZOOM                 = WM_USER + 108;
-    MCIWNDM_GETZOOM                 = WM_USER + 109;
-    MCIWNDM_SETVOLUME               = WM_USER + 110;
-    MCIWNDM_GETVOLUME               = WM_USER + 111;
-    MCIWNDM_SETSPEED                = WM_USER + 112;
-    MCIWNDM_GETSPEED                = WM_USER + 113;
-    MCIWNDM_SETREPEAT               = WM_USER + 114;
-    MCIWNDM_GETREPEAT               = WM_USER + 115;
-    MCIWNDM_REALIZE                 = WM_USER + 118;
-    MCIWNDM_VALIDATEMEDIA           = WM_USER + 121;
-    MCIWNDM_PLAYFROM                = WM_USER + 122;
-    MCIWNDM_PLAYTO                  = WM_USER + 123;
-    MCIWNDM_GETPALETTE              = WM_USER + 126;
-    MCIWNDM_SETPALETTE              = WM_USER + 127;
-    MCIWNDM_SETTIMERS               = WM_USER + 129;
-    MCIWNDM_SETACTIVETIMER          = WM_USER + 130;
-    MCIWNDM_SETINACTIVETIMER        = WM_USER + 131;
-    MCIWNDM_GETACTIVETIMER          = WM_USER + 132;
-    MCIWNDM_GETINACTIVETIMER        = WM_USER + 133;
-    MCIWNDM_CHANGESTYLES            = WM_USER + 135;
-    MCIWNDM_GETSTYLES               = WM_USER + 136;
-    MCIWNDM_GETALIAS                = WM_USER + 137;
-    MCIWNDM_PLAYREVERSE             = WM_USER + 139;
-    MCIWNDM_GET_SOURCE              = WM_USER + 140;
-    MCIWNDM_PUT_SOURCE              = WM_USER + 141;
-    MCIWNDM_GET_DEST                = WM_USER + 142;
-    MCIWNDM_PUT_DEST                = WM_USER + 143;
-    MCIWNDM_CAN_PLAY                = WM_USER + 144;
-    MCIWNDM_CAN_WINDOW              = WM_USER + 145;
-    MCIWNDM_CAN_RECORD              = WM_USER + 146;
-    MCIWNDM_CAN_SAVE                = WM_USER + 147;
-    MCIWNDM_CAN_EJECT               = WM_USER + 148;
-    MCIWNDM_CAN_CONFIG              = WM_USER + 149;
-    MCIWNDM_PALETTEKICK             = WM_USER + 150;
-    MCIWNDM_OPENINTERFACE           = WM_USER + 151;
-    MCIWNDM_SETOWNER                = WM_USER + 152;
-
-{-- Define both A and W messages ---------------------------------------------}
-
-    MCIWNDM_SENDSTRINGA             = WM_USER + 101;
-    MCIWNDM_GETPOSITIONA            = WM_USER + 102;
-    MCIWNDM_GETMODEA                = WM_USER + 106;
-    MCIWNDM_SETTIMEFORMATA          = WM_USER + 119;
-    MCIWNDM_GETTIMEFORMATA          = WM_USER + 120;
-    MCIWNDM_GETFILENAMEA            = WM_USER + 124;
-    MCIWNDM_GETDEVICEA              = WM_USER + 125;
-    MCIWNDM_GETERRORA               = WM_USER + 128;
-    MCIWNDM_NEWA                    = WM_USER + 134;
-    MCIWNDM_RETURNSTRINGA           = WM_USER + 138;
-    MCIWNDM_OPENA                   = WM_USER + 153;
-
-    MCIWNDM_SENDSTRINGW             = WM_USER + 201;
-    MCIWNDM_GETPOSITIONW            = WM_USER + 202;
-    MCIWNDM_GETMODEW                = WM_USER + 206;
-    MCIWNDM_SETTIMEFORMATW          = WM_USER + 219;
-    MCIWNDM_GETTIMEFORMATW          = WM_USER + 220;
-    MCIWNDM_GETFILENAMEW            = WM_USER + 224;
-    MCIWNDM_GETDEVICEW              = WM_USER + 225;
-    MCIWNDM_GETERRORW               = WM_USER + 228;
-    MCIWNDM_NEWW                    = WM_USER + 234;
-    MCIWNDM_RETURNSTRINGW           = WM_USER + 238;
-    MCIWNDM_OPENW                   = WM_USER + 252;
-
-{-- Map defaults to A --------------------------------------------------------}
-
-    MCIWNDM_SENDSTRING              = MCIWNDM_SENDSTRINGA;
-    MCIWNDM_GETPOSITION             = MCIWNDM_GETPOSITIONA;
-    MCIWNDM_GETMODE                 = MCIWNDM_GETMODEA;
-    MCIWNDM_SETTIMEFORMAT           = MCIWNDM_SETTIMEFORMATA;
-    MCIWNDM_GETTIMEFORMAT           = MCIWNDM_GETTIMEFORMATA;
-    MCIWNDM_GETFILENAME             = MCIWNDM_GETFILENAMEA;
-    MCIWNDM_GETDEVICE               = MCIWNDM_GETDEVICEA;
-    MCIWNDM_GETERROR                = MCIWNDM_GETERRORA;
-    MCIWNDM_NEW                     = MCIWNDM_NEWA;
-    MCIWNDM_RETURNSTRING            = MCIWNDM_RETURNSTRINGA;
-    MCIWNDM_OPEN                    = MCIWNDM_OPENA;
-
-// note that the source text for MCIWND will thus contain
-// support for eg MCIWNDM_SENDSTRING (both the 16-bit entrypoint and
-// in win32 mapped to MCIWNDM_SENDSTRINGW), and MCIWNDM_SENDSTRINGA (the
-// win32 ansi thunk).
-
-{-- Messages MCIWND will send to an app --------------------------------------}
-
-const
-    MCIWNDM_NOTIFYMODE              = WM_USER + 200;    // wp = hwnd, lp = mode
-    MCIWNDM_NOTIFYPOS               = WM_USER + 201;    // wp = hwnd, lp = pos
-    MCIWNDM_NOTIFYSIZE              = WM_USER + 202;    // wp = hwnd
-    MCIWNDM_NOTIFYMEDIA             = WM_USER + 203;    // wp = hwnd, lp = fn
-    MCIWNDM_NOTIFYERROR             = WM_USER + 205;    // wp = hwnd, lp = error
-
-{-- Special seek values for START and END ------------------------------------}
-
-    MCIWND_START                    = dword(-1) ;
-    MCIWND_END                      = dword(-2) ;
-
-{== VIDEO - Video capture driver interface ===================================}
-
-type
-    HVIDEO                          = THandle;
-    PHVIDEO                         = ^HVIDEO;
-
-{-- Error return values ------------------------------------------------------}
-
-const
-    DV_ERR_OK                       = 0;                    // No error
-    DV_ERR_BASE                     = 1;                    // Error Base 
-    DV_ERR_NONSPECIFIC              = DV_ERR_BASE;
-    DV_ERR_BADFORMAT                = DV_ERR_BASE + 1;      // unsupported video format 
-    DV_ERR_STILLPLAYING             = DV_ERR_BASE + 2;      // still something playing 
-    DV_ERR_UNPREPARED               = DV_ERR_BASE + 3;      // header not prepared 
-    DV_ERR_SYNC                     = DV_ERR_BASE + 4;      // device is synchronous 
-    DV_ERR_TOOMANYCHANNELS          = DV_ERR_BASE + 5;      // number of channels exceeded 
-    DV_ERR_NOTDETECTED              = DV_ERR_BASE + 6;      // HW not detected 
-    DV_ERR_BADINSTALL               = DV_ERR_BASE + 7;      // Can not get Profile 
-    DV_ERR_CREATEPALETTE            = DV_ERR_BASE + 8;
-    DV_ERR_SIZEFIELD                = DV_ERR_BASE + 9;
-    DV_ERR_PARAM1                   = DV_ERR_BASE + 10;
-    DV_ERR_PARAM2                   = DV_ERR_BASE + 11;
-    DV_ERR_CONFIG1                  = DV_ERR_BASE + 12;
-    DV_ERR_CONFIG2                  = DV_ERR_BASE + 13;
-    DV_ERR_FLAGS                    = DV_ERR_BASE + 14;
-    DV_ERR_13                       = DV_ERR_BASE + 15;
-
-    DV_ERR_NOTSUPPORTED             = DV_ERR_BASE + 16;     // function not suported 
-    DV_ERR_NOMEM                    = DV_ERR_BASE + 17;     // out of memory 
-    DV_ERR_ALLOCATED                = DV_ERR_BASE + 18;     // device is allocated 
-    DV_ERR_BADDEVICEID              = DV_ERR_BASE + 19;
-    DV_ERR_INVALHANDLE              = DV_ERR_BASE + 20;
-    DV_ERR_BADERRNUM                = DV_ERR_BASE + 21;
-    DV_ERR_NO_BUFFERS               = DV_ERR_BASE + 22;     // out of buffers 
-
-    DV_ERR_MEM_CONFLICT             = DV_ERR_BASE + 23;     // Mem conflict detected 
-    DV_ERR_IO_CONFLICT              = DV_ERR_BASE + 24;     // I/O conflict detected 
-    DV_ERR_DMA_CONFLICT             = DV_ERR_BASE + 25;     // DMA conflict detected
-    DV_ERR_INT_CONFLICT             = DV_ERR_BASE + 26;     // Interrupt conflict detected
-    DV_ERR_PROTECT_ONLY             = DV_ERR_BASE + 27;     // Can not run in standard mode
-    DV_ERR_LASTERROR                = DV_ERR_BASE + 27;
-
-    DV_ERR_USER_MSG                 = DV_ERR_BASE + 1000;   // Hardware specific errors
-
-{-- Callback messages --------------------------------------------------------}
-
-// Note that the values for all installable driver callback messages are
-// identical, (ie. MM_DRVM_DATA has the same value for capture drivers,
-// installable video codecs, and the audio compression manager).
-
-const
-    DV_VM_OPEN                      = MM_DRVM_OPEN;     // Obsolete messages
-    DV_VM_CLOSE                     = MM_DRVM_CLOSE;
-    DV_VM_DATA                      = MM_DRVM_DATA;
-    DV_VM_ERROR                     = MM_DRVM_ERROR;
-
-{== Structures ===============================================================}
-
-{-- Video data block header --------------------------------------------------}
-
-type
-    PVIDEOHDR               = ^TVIDEOHDR;
-    TVIDEOHDR               = record
-        lpData              : PBYTE;                // pointer to locked data buffer
-        dwBufferLength      : DWORD;                // Length of data buffer
-        dwBytesUsed         : DWORD;                // Bytes actually used
-        dwTimeCaptured      : DWORD;                // Milliseconds from start of stream
-        dwUser              : DWORD;                // for client's use
-        dwFlags             : DWORD;                // assorted flags (see defines)
-        dwReserved          : array[0..3] of DWORD; // reserved for driver
-    end;
-
-{-- dwFlags field of VIDEOHDR ------------------------------------------------}
-
-const
-    VHDR_DONE                       = $00000001;    // Done bit
-    VHDR_PREPARED                   = $00000002;    // Set if this header has been prepared
-    VHDR_INQUEUE                    = $00000004;    // Reserved for driver
-    VHDR_KEYFRAME                   = $00000008;    // Key Frame
-
-{-- Channel capabilities structure -------------------------------------------}
-
-type
-    PCHANNEL_CAPS           = ^TCHANNEL_CAPS;
-    TCHANNEL_CAPS           = record
-        dwFlags             : DWORD;    // Capability flags
-        dwSrcRectXMod       : DWORD;    // Granularity of src rect in x
-        dwSrcRectYMod       : DWORD;    // Granularity of src rect in y
-        dwSrcRectWidthMod   : DWORD;    // Granularity of src rect width
-        dwSrcRectHeightMod  : DWORD;    // Granularity of src rect height
-        dwDstRectXMod       : DWORD;    // Granularity of dst rect in x
-        dwDstRectYMod       : DWORD;    // Granularity of dst rect in y
-        dwDstRectWidthMod   : DWORD;    // Granularity of dst rect width
-        dwDstRectHeightMod  : DWORD;    // Granularity of dst rect height
-    end;
-
-{-- dwFlags of CHANNEL_CAPS --------------------------------------------------}
-
-const
-    VCAPS_OVERLAY                   = $00000001;    // overlay channel 
-    VCAPS_SRC_CAN_CLIP              = $00000002;    // src rect can clip
-    VCAPS_DST_CAN_CLIP              = $00000004;    // dst rect can clip
-    VCAPS_CAN_SCALE                 = $00000008;    // allows src != dst
-
-{== API flags ================================================================}
-
-{-- Types of channels to open with the videoOpen function --------------------}
-
-const
-    VIDEO_EXTERNALIN                = $0001;
-    VIDEO_EXTERNALOUT               = $0002;
-    VIDEO_IN                        = $0004;
-    VIDEO_OUT                       = $0008;
-
-{-- Is a driver dialog available for this channel ----------------------------}
-
-    VIDEO_DLG_QUERY                 = $0010;
-
-{-- videoConfigure (both GET and SET) ----------------------------------------}
-
-    VIDEO_CONFIGURE_QUERY           = $8000;
-
-{-- videoConfigure (SET only) ------------------------------------------------}
-
-    VIDEO_CONFIGURE_SET             = $1000;
-
-{-- videoConfigure (GET only) ------------------------------------------------}
-
-    VIDEO_CONFIGURE_GET             = $2000;
-    VIDEO_CONFIGURE_QUERYSIZE       = $0001;
-
-    VIDEO_CONFIGURE_CURRENT         = $0010;
-    VIDEO_CONFIGURE_NOMINAL         = $0020;
-    VIDEO_CONFIGURE_MIN             = $0040;
-    VIDEO_CONFIGURE_MAX             = $0080;
-
-{== Configure messages =======================================================}
-
-    DVM_USER                        = $4000;
-
-    DVM_CONFIGURE_START             = $1000;
-    DVM_CONFIGURE_END               = $1FFF;
-
-    DVM_PALETTE                     = DVM_CONFIGURE_START + 1;
-    DVM_FORMAT                      = DVM_CONFIGURE_START + 2;
-    DVM_PALETTERGB555               = DVM_CONFIGURE_START + 3;
-    DVM_SRC_RECT                    = DVM_CONFIGURE_START + 4;
-    DVM_DST_RECT                    = DVM_CONFIGURE_START + 5;
-
-{== AVICAP - Window class for AVI capture ====================================}
-
-function    AVICapSM(hwnd: HWND; m: UINT; w: WPARAM; l: LPARAM): DWORD;
-
-{-- Window messages WM_CAP... which can be sent to an AVICAP window ----------}
-
-// UNICODE
-//
-// The Win32 version of AVICAP on NT supports UNICODE applications:
-// for each API or message that takes a char or string parameter, there are
-// two versions, ApiNameA and ApiNameW. The default name ApiName is #defined
-// to one or other depending on whether UNICODE is defined. Apps can call
-// the A and W apis directly, and mix them.
-//
-// The 32-bit AVICAP on NT uses unicode exclusively internally.
-// ApiNameA() will be implemented as a call to ApiNameW() together with
-// translation of strings.
-
-// Defines start of the message range
-const
-    WM_CAP_START                    = WM_USER;
-    WM_CAP_UNICODE_START            = WM_USER + 100;
-
-    WM_CAP_GET_CAPSTREAMPTR         = WM_CAP_START + 1;
-
-    WM_CAP_SET_CALLBACK_ERRORW      = WM_CAP_UNICODE_START + 2;
-    WM_CAP_SET_CALLBACK_STATUSW     = WM_CAP_UNICODE_START + 3;
-    WM_CAP_SET_CALLBACK_ERRORA      = WM_CAP_START + 2;
-    WM_CAP_SET_CALLBACK_STATUSA     = WM_CAP_START + 3;
-    WM_CAP_SET_CALLBACK_ERROR       = WM_CAP_SET_CALLBACK_ERRORA;
-    WM_CAP_SET_CALLBACK_STATUS      = WM_CAP_SET_CALLBACK_STATUSA;
-
-    WM_CAP_SET_CALLBACK_YIELD       = WM_CAP_START + 4;
-    WM_CAP_SET_CALLBACK_FRAME       = WM_CAP_START + 5;
-    WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START + 6;
-    WM_CAP_SET_CALLBACK_WAVESTREAM  = WM_CAP_START + 7;
-    WM_CAP_GET_USER_DATA            = WM_CAP_START + 8;
-    WM_CAP_SET_USER_DATA            = WM_CAP_START + 9;
-
-    WM_CAP_DRIVER_CONNECT           = WM_CAP_START + 10;
-    WM_CAP_DRIVER_DISCONNECT        = WM_CAP_START + 11;
-
-    WM_CAP_DRIVER_GET_NAMEA         = WM_CAP_START + 12;
-    WM_CAP_DRIVER_GET_VERSIONA      = WM_CAP_START + 13;
-    WM_CAP_DRIVER_GET_NAMEW         = WM_CAP_UNICODE_START + 12;
-    WM_CAP_DRIVER_GET_VERSIONW      = WM_CAP_UNICODE_START + 13;
-    WM_CAP_DRIVER_GET_NAME          = WM_CAP_DRIVER_GET_NAMEA;
-    WM_CAP_DRIVER_GET_VERSION       = WM_CAP_DRIVER_GET_VERSIONA;
-
-    WM_CAP_DRIVER_GET_CAPS          = WM_CAP_START + 14;
-
-    WM_CAP_FILE_SET_CAPTURE_FILEA   = WM_CAP_START + 20;
-    WM_CAP_FILE_GET_CAPTURE_FILEA   = WM_CAP_START + 21;
-    WM_CAP_FILE_SAVEASA             = WM_CAP_START + 23;
-    WM_CAP_FILE_SAVEDIBA            = WM_CAP_START + 25;
-    WM_CAP_FILE_SET_CAPTURE_FILEW   = WM_CAP_UNICODE_START + 20;
-    WM_CAP_FILE_GET_CAPTURE_FILEW   = WM_CAP_UNICODE_START + 21;
-    WM_CAP_FILE_SAVEASW             = WM_CAP_UNICODE_START + 23;
-    WM_CAP_FILE_SAVEDIBW            = WM_CAP_UNICODE_START + 25;
-    WM_CAP_FILE_SET_CAPTURE_FILE    = WM_CAP_FILE_SET_CAPTURE_FILEA;
-    WM_CAP_FILE_GET_CAPTURE_FILE    = WM_CAP_FILE_GET_CAPTURE_FILEA;
-    WM_CAP_FILE_SAVEAS              = WM_CAP_FILE_SAVEASA;
-    WM_CAP_FILE_SAVEDIB             = WM_CAP_FILE_SAVEDIBA;
-
-    // out of order to save on ifdefs
-
-    WM_CAP_FILE_ALLOCATE            = WM_CAP_START + 22;
-    WM_CAP_FILE_SET_INFOCHUNK       = WM_CAP_START + 24;
-
-    WM_CAP_EDIT_COPY                = WM_CAP_START + 30;
-
-    WM_CAP_SET_AUDIOFORMAT          = WM_CAP_START + 35;
-    WM_CAP_GET_AUDIOFORMAT          = WM_CAP_START + 36;
-
-    WM_CAP_DLG_VIDEOFORMAT          = WM_CAP_START + 41;
-    WM_CAP_DLG_VIDEOSOURCE          = WM_CAP_START + 42;
-    WM_CAP_DLG_VIDEODISPLAY         = WM_CAP_START + 43;
-    WM_CAP_GET_VIDEOFORMAT          = WM_CAP_START + 44;
-    WM_CAP_SET_VIDEOFORMAT          = WM_CAP_START + 45;
-    WM_CAP_DLG_VIDEOCOMPRESSION     = WM_CAP_START + 46;
-
-    WM_CAP_SET_PREVIEW              = WM_CAP_START + 50;
-    WM_CAP_SET_OVERLAY              = WM_CAP_START + 51;
-    WM_CAP_SET_PREVIEWRATE          = WM_CAP_START + 52;
-    WM_CAP_SET_SCALE                = WM_CAP_START + 53;
-    WM_CAP_GET_STATUS               = WM_CAP_START + 54;
-    WM_CAP_SET_SCROLL               = WM_CAP_START + 55;
-
-    WM_CAP_GRAB_FRAME               = WM_CAP_START + 60;
-    WM_CAP_GRAB_FRAME_NOSTOP        = WM_CAP_START + 61;
-
-    WM_CAP_SEQUENCE                 = WM_CAP_START + 62;
-    WM_CAP_SEQUENCE_NOFILE          = WM_CAP_START + 63;
-    WM_CAP_SET_SEQUENCE_SETUP       = WM_CAP_START + 64;
-    WM_CAP_GET_SEQUENCE_SETUP       = WM_CAP_START + 65;
-
-    WM_CAP_SET_MCI_DEVICEA          = WM_CAP_START + 66;
-    WM_CAP_GET_MCI_DEVICEA          = WM_CAP_START + 67;
-    WM_CAP_SET_MCI_DEVICEW          = WM_CAP_UNICODE_START + 66;
-    WM_CAP_GET_MCI_DEVICEW          = WM_CAP_UNICODE_START + 67;
-    WM_CAP_SET_MCI_DEVICE           = WM_CAP_SET_MCI_DEVICEA;
-    WM_CAP_GET_MCI_DEVICE           = WM_CAP_GET_MCI_DEVICEA;
-
-    WM_CAP_STOP                     = WM_CAP_START + 68;
-    WM_CAP_ABORT                    = WM_CAP_START + 69;
-
-    WM_CAP_SINGLE_FRAME_OPEN        = WM_CAP_START + 70;
-    WM_CAP_SINGLE_FRAME_CLOSE       = WM_CAP_START + 71;
-    WM_CAP_SINGLE_FRAME             = WM_CAP_START + 72;
-
-    WM_CAP_PAL_OPENA                = WM_CAP_START + 80;
-    WM_CAP_PAL_SAVEA                = WM_CAP_START + 81;
-    WM_CAP_PAL_OPENW                = WM_CAP_UNICODE_START + 80;
-    WM_CAP_PAL_SAVEW                = WM_CAP_UNICODE_START + 81;
-    WM_CAP_PAL_OPEN                 = WM_CAP_PAL_OPENA;
-    WM_CAP_PAL_SAVE                 = WM_CAP_PAL_SAVEA;
-
-    WM_CAP_PAL_PASTE                = WM_CAP_START + 82;
-    WM_CAP_PAL_AUTOCREATE           = WM_CAP_START + 83;
-    WM_CAP_PAL_MANUALCREATE         = WM_CAP_START + 84;
-
-    // Following added post VFW 1.1
-
-    WM_CAP_SET_CALLBACK_CAPCONTROL  = WM_CAP_START + 85;
-
-    // Defines end of the message range
-
-    WM_CAP_UNICODE_END              = WM_CAP_PAL_SAVEW;
-    WM_CAP_END                      = WM_CAP_UNICODE_END;
-
-{-- Callback definitions -----------------------------------------------------}
-
-type
-    TCAPYIELDCALLBACK               = function(hWnd: HWND): DWORD; stdcall;
-
-    TCAPSTATUSCALLBACKW             = function(hWnd: HWND; nID: int; lpsz: LPCWSTR): DWORD; stdcall;
-    TCAPERRORCALLBACKW              = function(hWnd: HWND; nID: int; lpsz: LPCWSTR): DWORD; stdcall;
-    TCAPSTATUSCALLBACKA             = function(hWnd: HWND; nID: int; lpsz: LPCSTR): DWORD; stdcall;
-    TCAPERRORCALLBACKA              = function(hWnd: HWND; nID: int; lpsz: LPCSTR): DWORD; stdcall;
-
-    TCAPSTATUSCALLBACK              = TCAPSTATUSCALLBACKA;
-    TCAPERRORCALLBACK               = TCAPERRORCALLBACKA;
-
-    TCAPVIDEOCALLBACK               = function(hWnd: HWND; lpVHdr: PVIDEOHDR): DWORD; stdcall;
-    TCAPWAVECALLBACK                = function(hWnd: HWND; lpWHdr: PWAVEHDR): DWORD; stdcall;
-    TCAPCONTROLCALLBACK             = function(hWnd: HWND; nState: int): DWORD; stdcall;
-
-{-- Structures ---------------------------------------------------------------}
-
-type
-    PCAPDRIVERCAPS                  = ^TCAPDRIVERCAPS;
-    TCAPDRIVERCAPS                  = record
-        wDeviceIndex                : UINT;     // Driver index in system.ini
-        fHasOverlay                 : BOOL;     // Can device overlay?
-        fHasDlgVideoSource          : BOOL;     // Has Video source dlg?
-        fHasDlgVideoFormat          : BOOL;     // Has Format dlg?
-        fHasDlgVideoDisplay         : BOOL;     // Has External out dlg?
-        fCaptureInitialized         : BOOL;     // Driver ready to capture?
-        fDriverSuppliesPalettes     : BOOL;     // Can driver make palettes?
-
-        // following always NULL on Win32.
-        hVideoIn                    : THANDLE;   // Driver In channel
-        hVideoOut                   : THANDLE;   // Driver Out channel
-        hVideoExtIn                 : THANDLE;   // Driver Ext In channel
-        hVideoExtOut                : THANDLE;   // Driver Ext Out channel
-    end;
-
-    PCAPSTATUS                      = ^TCAPSTATUS;
-    TCAPSTATUS                      = record
-        uiImageWidth                : UINT    ; // Width of the image
-        uiImageHeight               : UINT    ; // Height of the image
-        fLiveWindow                 : BOOL    ; // Now Previewing video?
-        fOverlayWindow              : BOOL    ; // Now Overlaying video?
-        fScale                      : BOOL    ; // Scale image to client?
-        ptScroll                    : TPOINT  ; // Scroll position
-        fUsingDefaultPalette        : BOOL    ; // Using default driver palette?
-        fAudioHardware              : BOOL    ; // Audio hardware present?
-        fCapFileExists              : BOOL    ; // Does capture file exist?
-        dwCurrentVideoFrame         : DWORD   ; // # of video frames cap'td
-        dwCurrentVideoFramesDropped : DWORD   ; // # of video frames dropped
-        dwCurrentWaveSamples        : DWORD   ; // # of wave samples cap'td
-        dwCurrentTimeElapsedMS      : DWORD   ; // Elapsed capture duration
-        hPalCurrent                 : HPALETTE; // Current palette in use
-        fCapturingNow               : BOOL    ; // Capture in progress?
-        dwReturn                    : DWORD   ; // Error value after any operation
-        wNumVideoAllocated          : UINT    ; // Actual number of video buffers
-        wNumAudioAllocated          : UINT    ; // Actual number of audio buffers
-    end;
-
-    // Default values in parenthesis
-
-    PCAPTUREPARMS                   = ^TCAPTUREPARMS;
-    TCAPTUREPARMS                   = record
-        dwRequestMicroSecPerFrame   : DWORD ;   // Requested capture rate
-        fMakeUserHitOKToCapture     : BOOL  ;   // Show "Hit OK to cap" dlg?
-        wPercentDropForError        : UINT  ;   // Give error msg if > (10%)
-        fYield                      : BOOL  ;   // Capture via background task?
-        dwIndexSize                 : DWORD ;   // Max index size in frames (32K)
-        wChunkGranularity           : UINT  ;   // Junk chunk granularity (2K)
-        fUsingDOSMemory             : BOOL  ;   // Use DOS buffers?
-        wNumVideoRequested          : UINT  ;   // # video buffers, If 0, autocalc
-        fCaptureAudio               : BOOL  ;   // Capture audio?
-        wNumAudioRequested          : UINT  ;   // # audio buffers, If 0, autocalc
-        vKeyAbort                   : UINT  ;   // Virtual key causing abort
-        fAbortLeftMouse             : BOOL  ;   // Abort on left mouse?
-        fAbortRightMouse            : BOOL  ;   // Abort on right mouse?
-        fLimitEnabled               : BOOL  ;   // Use wTimeLimit?
-        wTimeLimit                  : UINT  ;   // Seconds to capture
-        fMCIControl                 : BOOL  ;   // Use MCI video source?
-        fStepMCIDevice              : BOOL  ;   // Step MCI device?
-        dwMCIStartTime              : DWORD ;   // Time to start in MS
-        dwMCIStopTime               : DWORD ;   // Time to stop in MS
-        fStepCaptureAt2x            : BOOL  ;   // Perform spatial averaging 2x
-        wStepCaptureAverageFrames   : UINT  ;   // Temporal average n Frames
-        dwAudioBufferSize           : DWORD ;   // Size of audio bufs (0 = default)
-        fDisableWriteCache          : BOOL  ;   // Attempt to disable write cache
-        AVStreamMaster              : UINT  ;   // Which stream controls length?
-    end;
-
-{-- AVStreamMaster -----------------------------------------------------------}
-
-//  Since Audio and Video streams generally use non-synchronized capture
-//  clocks, this flag determines whether the audio stream is to be considered
-//  the master or controlling clock when writing the AVI file:
-//
-//  AVSTREAMMASTER_AUDIO  - Audio is master, video frame duration is forced
-//                          to match audio duration (VFW 1.0, 1.1 default)
-//  AVSTREAMMASTER_NONE   - No master, audio and video streams may be of
-//                          different lengths
-
-const
-    AVSTREAMMASTER_AUDIO            = 0;        // Audio master (VFW 1.0, 1.1)
-    AVSTREAMMASTER_NONE             = 1;        // No master
-
-type
-    PCAPINFOCHUNK                   = ^TCAPINFOCHUNK;
-    TCAPINFOCHUNK                   = record
-        fccInfoID                   : FOURCC;   // Chunk ID, "ICOP" for copyright
-        lpData                      : PVOID;    // pointer to data
-        cbData                      : DWORD;     // size of lpData
-    end;
-
-{-- CapControlCallback states ------------------------------------------------}
-
-const
-    CONTROLCALLBACK_PREROLL         = 1;        // Waiting to start capture 
-    CONTROLCALLBACK_CAPTURING       = 2;        // Now capturing
-
-{-- Message crackers for above -----------------------------------------------}
-
-// message wrapper macros are defined for the default messages only. Apps
-// that wish to mix Ansi and UNICODE message sending will have to
-// reference the _A and _W messages directly
-
-function    capSetCallbackOnError(hwnd: HWND; fpProc: TCAPERRORCALLBACK): BOOL;
-function    capSetCallbackOnStatus(hwnd: HWND; fpProc: TCAPSTATUSCALLBACK): BOOL;
-function    capSetCallbackOnYield(hwnd: HWND; fpProc: TCAPYIELDCALLBACK): BOOL;
-function    capSetCallbackOnFrame(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
-function    capSetCallbackOnVideoStream(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
-function    capSetCallbackOnWaveStream(hwnd: HWND; fpProc: TCAPWAVECALLBACK): BOOL;
-function    capSetCallbackOnCapControl(hwnd: HWND; fpProc: TCAPCONTROLCALLBACK): BOOL;
-
-function    capSetUserData(hwnd: HWND; lUser: DWORD): BOOL;
-function    capGetUserData(hwnd: HWND): DWORD;
-
-function    capDriverConnect(hwnd: HWND; i: INT): BOOL;
-function    capDriverDisconnect(hwnd: HWND): BOOL;
-function    capDriverGetName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
-function    capDriverGetVersion(hwnd: HWND; szVer: LPSTR; wSize: WORD): BOOL;
-function    capDriverGetCaps(hwnd: HWND; s: PCAPDRIVERCAPS; wSize: WORD): BOOL;
-
-function    capFileSetCaptureFile(hwnd: HWND; szName: LPCSTR): BOOL;
-function    capFileGetCaptureFile(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
-function    capFileAlloc(hwnd: HWND; dwSize: DWORD): BOOL;
-function    capFileSaveAs(hwnd: HWND; szName: LPCSTR): BOOL;
-function    capFileSetInfoChunk(hwnd: HWND; lpInfoChunk: PCAPINFOCHUNK): BOOL;
-function    capFileSaveDIB(hwnd: HWND; szName: LPCSTR): BOOL;
-
-function    capEditCopy(hwnd: HWND): BOOL;
-
-function    capSetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): BOOL;
-function    capGetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): DWORD;
-function    capGetAudioFormatSize(hwnd: HWND): DWORD;
-
-function    capDlgVideoFormat(hwnd: HWND): BOOL;
-function    capDlgVideoSource(hwnd: HWND): BOOL;
-function    capDlgVideoDisplay(hwnd: HWND): BOOL;
-function    capDlgVideoCompression(hwnd: HWND): BOOL;
-
-function    capGetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): DWORD;
-function    capGetVideoFormatSize(hwnd: HWND): DWORD;
-function    capSetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): BOOL;
-
-function    capPreview(hwnd: HWND; f: BOOL): BOOL;
-function    capPreviewRate(hwnd: HWND; wMS: WORD): BOOL;
-function    capOverlay(hwnd: HWND; f: BOOL): BOOL;
-function    capPreviewScale(hwnd: HWND; f: BOOL): BOOL;
-function    capGetStatus(hwnd: HWND; s: PCAPSTATUS; wSize: WORD): BOOL;
-function    capSetScrollPos(hwnd: HWND; lpP: PPOINT): BOOL;
-
-function    capGrabFrame(hwnd: HWND): BOOL;
-function    capGrabFrameNoStop(hwnd: HWND): BOOL;
-
-function    capCaptureSequence(hwnd: HWND): BOOL;
-function    capCaptureSequenceNoFile(hwnd: HWND): BOOL;
-function    capCaptureStop(hwnd: HWND): BOOL;
-function    capCaptureAbort(hwnd: HWND): BOOL;
-
-function    capCaptureSingleFrameOpen(hwnd: HWND): BOOL;
-function    capCaptureSingleFrameClose(hwnd: HWND): BOOL;
-function    capCaptureSingleFrame(hwnd: HWND): BOOL;
-
-function    capCaptureGetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
-function    capCaptureSetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
-
-function    capSetMCIDeviceName(hwnd: HWND; szName: LPCSTR): BOOL;
-function    capGetMCIDeviceName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
-
-function    capPaletteOpen(hwnd: HWND; szName: LPCSTR): BOOL;
-function    capPaletteSave(hwnd: HWND; szName: LPCSTR): BOOL;
-function    capPalettePaste(hwnd: HWND): BOOL;
-function    capPaletteAuto(hwnd: HWND; iFrames, iColors: INT): BOOL;
-function    capPaletteManual(hwnd: HWND; fGrab: BOOL; iColors: INT): BOOL;
-
-{-- The only exported functions from AVICAP.DLL ------------------------------}
-
-function    capCreateCaptureWindowA(
-    lpszWindowName      : LPCSTR;
-    dwStyle             : DWORD;
-    x, y                : int;
-    nWidth, nHeight     : int;
-    hwndParent          : HWND;
-    nID                 : int
-    ): HWND; stdcall;
-
-function    capGetDriverDescriptionA(
-    wDriverIndex        : UINT;
-    lpszName            : LPSTR;
-    cbName              : int;
-    lpszVer             : LPSTR;
-    cbVer               : int
-    ): BOOL; stdcall;
-
-function    capCreateCaptureWindowW(
-    lpszWindowName      : LPCWSTR;
-    dwStyle             : DWORD;
-    x, y                : int;
-    nWidth, nHeight     : int;
-    hwndParent          : HWND;
-    nID                 : int
-    ): HWND; stdcall;
-
-function    capGetDriverDescriptionW(
-    wDriverIndex        : UINT;
-    lpszName            : LPWSTR;
-    cbName              : int;
-    lpszVer             : LPWSTR;
-    cbVer               : int
-    ): BOOL; stdcall;
-
-function    capCreateCaptureWindow(
-    lpszWindowName      : LPCSTR;
-    dwStyle             : DWORD;
-    x, y                : int;
-    nWidth, nHeight     : int;
-    hwndParent          : HWND;
-    nID                 : int
-    ): HWND; stdcall; // capCreateCaptureWindowA
-
-function    capGetDriverDescription(
-    wDriverIndex        : UINT;
-    lpszName            : LPSTR;
-    cbName              : int;
-    lpszVer             : LPSTR;
-    cbVer               : int
-    ): BOOL; stdcall; // capGetDriverDescriptionA
-
-{-- New information chunk IDs ------------------------------------------------}
-
-const
-    infotypeDIGITIZATION_TIME       = $54494449; // mmioFOURCC ('I','D','I','T')
-    infotypeSMPTE_TIME              = $504D5349; // mmioFOURCC ('I','S','M','P')
-
-{-- String IDs from status and error callbacks -------------------------------}
-
-    IDS_CAP_BEGIN                   = 300;  // "Capture Start" 
-    IDS_CAP_END                     = 301;  // "Capture End" 
-
-    IDS_CAP_INFO                    = 401;  // "%s" 
-    IDS_CAP_OUTOFMEM                = 402;  // "Out of memory" 
-    IDS_CAP_FILEEXISTS              = 403;  // "File '%s' exists -- overwrite it?" 
-    IDS_CAP_ERRORPALOPEN            = 404;  // "Error opening palette '%s'" 
-    IDS_CAP_ERRORPALSAVE            = 405;  // "Error saving palette '%s'" 
-    IDS_CAP_ERRORDIBSAVE            = 406;  // "Error saving frame '%s'" 
-    IDS_CAP_DEFAVIEXT               = 407;  // "avi" 
-    IDS_CAP_DEFPALEXT               = 408;  // "pal" 
-    IDS_CAP_CANTOPEN                = 409;  // "Cannot open '%s'"
-    IDS_CAP_SEQ_MSGSTART            = 410;  // "Select OK to start capture\nof video sequence\nto %s."
-    IDS_CAP_SEQ_MSGSTOP             = 411;  // "Hit ESCAPE or click to end capture" 
-
-    IDS_CAP_VIDEDITERR              = 412;  // "An error occurred while trying to run VidEdit." 
-    IDS_CAP_READONLYFILE            = 413;  // "The file '%s' is a read-only file." 
-    IDS_CAP_WRITEERROR              = 414;  // "Unable to write to file '%s'.\nDisk may be full." 
-    IDS_CAP_NODISKSPACE             = 415;  // "There is no space to create a capture file on the specified device." 
-    IDS_CAP_SETFILESIZE             = 416;  // "Set File Size" 
-    IDS_CAP_SAVEASPERCENT           = 417;  // "SaveAs: %2ld%%  Hit Escape to abort." 
-
-    IDS_CAP_DRIVER_ERROR            = 418;  // Driver specific error message 
-
-    IDS_CAP_WAVE_OPEN_ERROR         = 419;  // "Error: Cannot open the wave input device.\nCheck sample size, frequency, and channels." 
-    IDS_CAP_WAVE_ALLOC_ERROR        = 420;  // "Error: Out of memory for wave buffers." 
-    IDS_CAP_WAVE_PREPARE_ERROR      = 421;  // "Error: Cannot prepare wave buffers." 
-    IDS_CAP_WAVE_ADD_ERROR          = 422;  // "Error: Cannot add wave buffers." 
-    IDS_CAP_WAVE_SIZE_ERROR         = 423;  // "Error: Bad wave size." 
-
-    IDS_CAP_VIDEO_OPEN_ERROR        = 424;  // "Error: Cannot open the video input device." 
-    IDS_CAP_VIDEO_ALLOC_ERROR       = 425;  // "Error: Out of memory for video buffers."
-    IDS_CAP_VIDEO_PREPARE_ERROR     = 426;  // "Error: Cannot prepare video buffers." 
-    IDS_CAP_VIDEO_ADD_ERROR         = 427;  // "Error: Cannot add video buffers." 
-    IDS_CAP_VIDEO_SIZE_ERROR        = 428;  // "Error: Bad video size." 
-
-    IDS_CAP_FILE_OPEN_ERROR         = 429;  // "Error: Cannot open capture file." 
-    IDS_CAP_FILE_WRITE_ERROR        = 430;  // "Error: Cannot write to capture file.  Disk may be full." 
-    IDS_CAP_RECORDING_ERROR         = 431;  // "Error: Cannot write to capture file.  Data rate too high or disk full." 
-    IDS_CAP_RECORDING_ERROR2        = 432;  // "Error while recording" 
-    IDS_CAP_AVI_INIT_ERROR          = 433;  // "Error: Unable to initialize for capture."
-    IDS_CAP_NO_FRAME_CAP_ERROR      = 434;  // "Warning: No frames captured.\nConfirm that vertical sync interrupts\nare configured and enabled." 
-    IDS_CAP_NO_PALETTE_WARN         = 435;  // "Warning: Using default palette." 
-    IDS_CAP_MCI_CONTROL_ERROR       = 436;  // "Error: Unable to access MCI device." 
-    IDS_CAP_MCI_CANT_STEP_ERROR     = 437;  // "Error: Unable to step MCI device." 
-    IDS_CAP_NO_AUDIO_CAP_ERROR      = 438;  // "Error: No audio data captured.\nCheck audio card settings." 
-    IDS_CAP_AVI_DRAWDIB_ERROR       = 439;  // "Error: Unable to draw this data format."
-    IDS_CAP_COMPRESSOR_ERROR        = 440;  // "Error: Unable to initialize compressor."
-    IDS_CAP_AUDIO_DROP_ERROR        = 441;  // "Error: Audio data was lost during capture, reduce capture rate."
-
-{-- Status string IDs --------------------------------------------------------}
-
-    IDS_CAP_STAT_LIVE_MODE          = 500;  // "Live window" 
-    IDS_CAP_STAT_OVERLAY_MODE       = 501;  // "Overlay window" 
-    IDS_CAP_STAT_CAP_INIT           = 502;  // "Setting up for capture - Please wait" 
-    IDS_CAP_STAT_CAP_FINI           = 503;  // "Finished capture, now writing frame %ld" 
-    IDS_CAP_STAT_PALETTE_BUILD      = 504;  // "Building palette map" 
-    IDS_CAP_STAT_OPTPAL_BUILD       = 505;  // "Computing optimal palette" 
-    IDS_CAP_STAT_I_FRAMES           = 506;  // "%d frames" 
-    IDS_CAP_STAT_L_FRAMES           = 507;  // "%ld frames" 
-    IDS_CAP_STAT_CAP_L_FRAMES       = 508;  // "Captured %ld frames" 
-    IDS_CAP_STAT_CAP_AUDIO          = 509;  // "Capturing audio" 
-    IDS_CAP_STAT_VIDEOCURRENT       = 510;  // "Captured %ld frames (%ld dropped) %d.%03d sec." 
-    IDS_CAP_STAT_VIDEOAUDIO         = 511;  // "Captured %d.%03d sec.  %ld frames (%ld dropped) (%d.%03d fps).  %ld audio bytes (%d,%03d sps)" 
-    IDS_CAP_STAT_VIDEOONLY          = 512;  // "Captured %d.%03d sec.  %ld frames (%ld dropped) (%d.%03d fps)" 
-    IDS_CAP_STAT_FRAMESDROPPED      = 513;  // "Dropped %ld of %ld frames (%d.%02d%%) during capture."
-
-{== FilePreview dialog =======================================================}
-
-function    GetOpenFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall;
-function    GetSaveFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall;
-
-function    GetOpenFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall;
-function    GetSaveFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall;
-
-function    GetOpenFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; // GetOpenFileNamePreviewA
-function    GetSaveFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; // GetSaveFileNamePreviewA
-
-implementation
-
-function MKFOURCC( ch0, ch1, ch2, ch3: AnsiChar ): FOURCC;
-begin
-  Result := (DWord(Ord(ch0))) or
-            (DWord(Ord(ch1)) shl 8) or
-            (DWord(Ord(ch2)) shl 16) or
-            (DWord(Ord(ch3)) shl 24);
-end;
-
-function mmioFOURCC( ch0, ch1, ch2, ch3: AnsiChar ): FOURCC;
-begin
-  Result := MKFOURCC(ch0,ch1,ch2,ch3);
-end;
-
-function aviTWOCC(ch0, ch1: AnsiChar): TWOCC;
-begin
-  Result := (Word(Ord(ch0))) or (Word(Ord(ch1)) shl 8);
-end;
-
-{-- Query macros -------------------------------------------------------------}
-
-function ICQueryAbout(hic: HIC): BOOL;
-begin
-  Result := ICSendMessage(hic, ICM_ABOUT, dword(-1), ICMF_ABOUT_QUERY) = ICERR_OK;
-end;
-
-function ICAbout(hic: HIC; hwnd: HWND): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_ABOUT, hwnd, 0);
-end;
-
-function ICQueryConfigure(hic: HIC): BOOL;
-begin
-  Result := ICSendMessage(hic, ICM_CONFIGURE, dword(-1), ICMF_CONFIGURE_QUERY) = ICERR_OK;
-end;
-
-function ICConfigure(hic: HIC; hwnd: HWND): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_CONFIGURE, hwnd, 0);
-end;
-
-{-- Get/Set state macros -----------------------------------------------------}
-
-function ICGetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_GETSTATE, DWORD(pv), cb);
-end;
-
-function ICSetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_SETSTATE, DWORD(pv), cb);
-end;
-
-function ICGetStateSize(hic: HIC): DWORD;
-begin
-  Result := ICGetState(hic, nil, 0);
-end;
-
-{-- Get value macros ---------------------------------------------------------}
-
-function ICGetDefaultQuality(hic: HIC): DWORD;
-begin
-  ICSendMessage(hic, ICM_GETDEFAULTQUALITY, DWORD(@Result), sizeof(Result));
-end;
-
-function ICGetDefaultKeyFrameRate(hic: HIC): DWORD;
-begin
-  ICSendMessage(hic, ICM_GETDEFAULTKEYFRAMERATE, DWORD(@Result), sizeof(Result));
-end;
-
-{-- Draw window macro --------------------------------------------------------}
-
-function ICDrawWindow(hic: HIC; prc: PRECT): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_DRAW_WINDOW, DWORD(prc), sizeof(prc^));
-end;
-
-{-- ICCompressBegin() - start compression from a source fmt to a dest fmt ----}
-
-function ICCompressBegin(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_COMPRESS_BEGIN, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-{-- ICCompressQuery() - determines if compression from src to dst is supp ----}
-
-function ICCompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_COMPRESS_QUERY, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-{-- ICCompressGetFormat() - get the output format (fmt of compressed) --------}
-
-// if lpbiOutput is nil return the size in bytes needed for format.
-
-function ICCompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-  Result := ICSendMessage(hic, ICM_COMPRESS_GET_FORMAT, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-function ICCompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
-begin
-  Result := ICCompressGetFormat(hic, lpbi, nil);
-end;
-
-{-- ICCompressSize() - return the maximal size of a compressed frame ---------}
-
-function    ICCompressGetSize(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_COMPRESS_GET_SIZE, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-function    ICCompressEnd(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_COMPRESS_END, 0, 0);
-end;
-
-{-- ICDecompressBegin() - start compression from src fmt to a dest fmt -------}
-
-function    ICDecompressBegin(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DECOMPRESS_BEGIN, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-{-- ICDecompressQuery() - determines if compression is supported -------------}
-
-function    ICDecompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DECOMPRESS_QUERY, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-{-- ICDecompressGetFormat - get the output fmt (fmt of uncompressed data) ----}
-
-// if lpbiOutput is NULL return the size in bytes needed for format.
-
-function    ICDecompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DECOMPRESS_GET_FORMAT, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-function    ICDecompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICDecompressGetFormat(hic, lpbi, nil);
-end;
-
-{-- ICDecompressGetPalette() - get the output palette ------------------------}
-
-function    ICDecompressGetPalette(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DECOMPRESS_GET_PALETTE, DWORD(lpbiInput), DWORD(lpbiOutput));
-end;
-
-function    ICDecompressSetPalette(hic: HIC; lpbiPalette: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DECOMPRESS_SET_PALETTE, DWORD(lpbiPalette), 0);
-end;
-
-function    ICDecompressEnd(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DECOMPRESS_END, 0, 0);
-end;
-
-{-- ICDecompressEx() - decompress a single frame -----------------------------}
-
-function    ICDecompressEx(
-    hic     : HIC;
-    dwFlags : DWORD;
-    lpbiSrc : PBITMAPINFOHEADER;
-    lpSrc   : PVOID;
-    xSrc    : int;
-    ySrc    : int;
-    dxSrc   : int;
-    dySrc   : int;
-    lpbiDst : PBITMAPINFOHEADER;
-    lpDst   : PVOID;
-    xDst    : int;
-    yDst    : int;
-    dxDst   : int;
-    dyDst   : int
-    ): DWORD; stdcall;
-var
-    ic : TICDECOMPRESSEX;
-begin
-    ic.dwFlags  := dwFlags;
-    ic.lpbiSrc  := lpbiSrc;
-    ic.lpSrc    := lpSrc;
-    ic.xSrc     := xSrc;
-    ic.ySrc     := ySrc;
-    ic.dxSrc    := dxSrc;
-    ic.dySrc    := dySrc;
-    ic.lpbiDst  := lpbiDst;
-    ic.lpDst    := lpDst;
-    ic.xDst     := xDst;
-    ic.yDst     := yDst;
-    ic.dxDst    := dxDst;
-    ic.dyDst    := dyDst;
-
-    // note that ICM swaps round the length and pointer
-    // length in lparam2, pointer in lparam1
-    Result := ICSendMessage(hic, ICM_DECOMPRESSEX, DWORD(@ic), sizeof(ic));
-end;
-
-{-- ICDecompressExBegin() - start compression from a src fmt to a dest fmt ---}
-
-function    ICDecompressExBegin(
-    hic     : HIC;
-    dwFlags : DWORD;
-    lpbiSrc : PBITMAPINFOHEADER;
-    lpSrc   : PVOID;
-    xSrc    : int;
-    ySrc    : int;
-    dxSrc   : int;
-    dySrc   : int;
-    lpbiDst : PBITMAPINFOHEADER;
-    lpDst   : PVOID;
-    xDst    : int;
-    yDst    : int;
-    dxDst   : int;
-    dyDst   : int
-    ): DWORD; stdcall;
-var
-    ic : TICDECOMPRESSEX ;
-begin
-    ic.dwFlags  := dwFlags;
-    ic.lpbiSrc  := lpbiSrc;
-    ic.lpSrc    := lpSrc;
-    ic.xSrc     := xSrc;
-    ic.ySrc     := ySrc;
-    ic.dxSrc    := dxSrc;
-    ic.dySrc    := dySrc;
-    ic.lpbiDst  := lpbiDst;
-    ic.lpDst    := lpDst;
-    ic.xDst     := xDst;
-    ic.yDst     := yDst;
-    ic.dxDst    := dxDst;
-    ic.dyDst    := dyDst;
-
-    // note that ICM swaps round the length and pointer
-    // length in lparam2, pointer in lparam1
-    Result      := ICSendMessage(hic, ICM_DECOMPRESSEX_BEGIN, DWORD(@ic), sizeof(ic));
-end;
-
-{-- ICDecompressExQuery() ----------------------------------------------------}
-
-function    ICDecompressExQuery(
-    hic     : HIC;
-    dwFlags : DWORD;
-    lpbiSrc : PBITMAPINFOHEADER;
-    lpSrc   : PVOID;
-    xSrc    : int;
-    ySrc    : int;
-    dxSrc   : int;
-    dySrc   : int;
-    lpbiDst : PBITMAPINFOHEADER;
-    lpDst   : PVOID;
-    xDst    : int;
-    yDst    : int;
-    dxDst   : int;
-    dyDst   : int
-    ): DWORD; stdcall;
-var
-    ic : TICDECOMPRESSEX;
-begin
-    ic.dwFlags  := dwFlags;
-    ic.lpbiSrc  := lpbiSrc;
-    ic.lpSrc    := lpSrc;
-    ic.xSrc     := xSrc;
-    ic.ySrc     := ySrc;
-    ic.dxSrc    := dxSrc;
-    ic.dySrc    := dySrc;
-    ic.lpbiDst  := lpbiDst;
-    ic.lpDst    := lpDst;
-    ic.xDst     := xDst;
-    ic.yDst     := yDst;
-    ic.dxDst    := dxDst;
-    ic.dyDst    := dyDst;
-
-    // note that ICM swaps round the length and pointer
-    // length in lparam2, pointer in lparam1
-    Result      := ICSendMessage(hic, ICM_DECOMPRESSEX_QUERY, DWORD(@ic), sizeof(ic));
-end;
-
-function    ICDecompressExEnd(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DECOMPRESSEX_END, 0, 0)
-end;
-
-function    ICDrawSuggestFormat(
-    hic         : HIC;
-    lpbiIn      : PBITMAPINFOHEADER;
-    lpbiOut     : PBITMAPINFOHEADER;
-    dxSrc       : int;
-    dySrc       : int;
-    dxDst       : int;
-    dyDst       : int;
-    hicDecomp   : HIC
-    ): DWORD; stdcall;
-var
-    ic : TICDRAWSUGGEST;
-begin
-    ic.lpbiIn           := lpbiIn;
-    ic.lpbiSuggest      := lpbiOut;
-    ic.dxSrc            := dxSrc;
-    ic.dySrc            := dySrc;
-    ic.dxDst            := dxDst;
-    ic.dyDst            := dyDst;
-    ic.hicDecompressor  := hicDecomp;
-
-    // note that ICM swaps round the length and pointer
-    // length in lparam2, pointer in lparam1
-    Result := ICSendMessage(hic, ICM_DRAW_SUGGESTFORMAT, DWORD(@ic), sizeof(ic));
-end;
-
-{-- ICDrawQuery() - determines if the compressor is willing to render fmt ----}
-
-function    ICDrawQuery(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_QUERY, DWORD(lpbiInput), 0);
-end;
-
-function    ICDrawChangePalette(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_CHANGEPALETTE, DWORD(lpbiInput), 0);
-end;
-
-function    ICGetBuffersWanted(hic: HIC; lpdwBuffers: PDWORD): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_GETBUFFERSWANTED, DWORD(lpdwBuffers), 0);
-end;
-
-function    ICDrawEnd(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_END, 0, 0);
-end;
-
-function    ICDrawStart(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_START, 0, 0);
-end;
-
-function    ICDrawStartPlay(hic: HIC; lFrom, lTo: DWORD): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_START_PLAY, lFrom, lTo);
-end;
-
-function    ICDrawStop(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_STOP, 0, 0);
-end;
-
-function    ICDrawStopPlay(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_STOP_PLAY, 0, 0);
-end;
-
-function    ICDrawGetTime(hic: HIC; lplTime: PDWORD): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_GETTIME, DWORD(lplTime), 0);
-end;
-
-function    ICDrawSetTime(hic: HIC; lTime: DWORD): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_SETTIME, lTime, 0);
-end;
-
-function    ICDrawRealize(hic: HIC; hdc: HDC; fBackground: BOOL): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_REALIZE, DWORD(hdc), DWORD(fBackground));
-end;
-
-function    ICDrawFlush(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_FLUSH, 0, 0);
-end;
-
-function    ICDrawRenderBuffer(hic: HIC): DWORD;
-begin
-    Result := ICSendMessage(hic, ICM_DRAW_RENDERBUFFER, 0, 0);
-end;
-
-{-- ICSetStatusProc() - Set the status callback function ---------------------}
-
-// ICMessage is not supported on NT
-
-function    ICSetStatusProc(
-    hic         : HIC;
-    dwFlags     : DWORD;
-    lParam      : DWORD;
-    fpfnStatus  : TICStatusProc
-    ): DWORD; stdcall;
-var
-    ic : TICSETSTATUSPROC;
-begin
-    ic.dwFlags  := dwFlags;
-    ic.lParam   := lParam;
-    ic.Status   := fpfnStatus;
-
-    // note that ICM swaps round the length and pointer
-    // length in lparam2, pointer in lparam1
-    Result      := ICSendMessage(hic, ICM_SET_STATUS_PROC, DWORD(@ic), sizeof(ic));
-end;
-
-{== Helper routines for DrawDib and MCIAVI... ================================}
-
-function    ICDecompressOpen(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER): HIC;
-begin
-    Result := ICLocate(fccType, fccHandler, lpbiIn, lpbiOut, ICMODE_DECOMPRESS);
-end;
-
-function    ICDrawOpen(fccType, fccHandler: DWORD; lpbiIn: PBITMAPINFOHEADER): HIC;
-begin
-    Result := ICLocate(fccType, fccHandler, lpbiIn, nil, ICMODE_DRAW);
-end;
-
-{-- DrawDibUpdate() - redraw last image (may only be valid with DDF_BUFFER) --}
-
-function    DrawDibUpdate(hdd: HDRAWDIB; hdc: HDC; x, y: int): BOOL;
-begin
-    Result  := DrawDibDraw(hdd, hdc, x, y, 0, 0, nil, nil, 0, 0, 0, 0, DDF_UPDATE);
-end;
-
-{== Useful macros ============================================================}
-
-{-- Macro to get stream number out of a FOURCC ckid --------------------------}
-
-function    FromHex(n: BYTE): BYTE;
-begin
-    if n >= Ord('A') then
-        Result := Ord(n) + 10 - Ord('A')
-    else
-        Result := Ord(n) - Ord('0');
-end;
-
-function    StreamFromFOURCC(fcc: DWORD): BYTE;
-begin
-    Result :=  (FromHex(Lo(LoWord(fcc))) shl 4) + FromHex(Hi(LoWord(fcc)));
-end;
-
-{-- Macro to get TWOCC chunk type out of a FOURCC ckid -----------------------}
-
-function    TWOCCFromFOURCC(fcc: DWORD): WORD;
-begin
-    Result := HiWord(fcc);
-end;
-
-{-- Macro to make a ckid for a chunk out of a TWOCC and a stream num (0-255) -}
-
-function    ToHex(n: BYTE): BYTE;
-begin
-    if n > 9 then
-        Result := n - 10 + Ord('A')
-    else
-        Result := n + Ord('0');
-end;
-
-function    MAKEAVICKID(tcc: WORD; stream: BYTE): DWORD;
-begin
-    Result := MakeLONG((ToHex(stream and $0F) shl 8) or ToHex((stream and $F0) shr 4),tcc);
-end;
-
-{-- Helper macros ------------------------------------------------------------}
-
-function    AVIStreamSampleToSample(pavi1, pavi2: IAVISTREAM; l: LONG): LONG;
-begin
-    Result  := AVIStreamTimeToSample(pavi1,AVIStreamSampleToTime(pavi2, l));
-end;
-
-function    AVIStreamNextSample(pavi: IAVISTREAM; l: LONG): LONG;
-begin
-    Result  := AVIStreamFindSample(pavi,l+1,FIND_NEXT or FIND_ANY);
-end;
-
-function    AVIStreamPrevSample(pavi: IAVISTREAM; l: LONG): LONG;
-begin
-    Result  := AVIStreamFindSample(pavi,l-1,FIND_PREV or FIND_ANY);
-end;
-
-function    AVIStreamNearestSample(pavi: IAVISTREAM; l: LONG): LONG;
-begin
-    Result  := AVIStreamFindSample(pavi,l,FIND_PREV or FIND_ANY);
-end;
-
-function    AVIStreamNextKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
-begin
-    Result  := AVIStreamFindSample(pavi,l+1,FIND_NEXT or FIND_KEY);
-end;
-
-function    AVIStreamPrevKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
-begin
-    Result  := AVIStreamFindSample(pavi,l-1,FIND_PREV or FIND_KEY);
-end;
-
-function    AVIStreamNearestKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
-begin
-    Result  := AVIStreamFindSample(pavi,l,FIND_PREV or FIND_KEY)
-end;
-
-function    AVIStreamIsKeyFrame(pavi: IAVISTREAM; l: LONG): BOOL;
-begin
-    Result  := AVIStreamNearestKeyFrame(pavi,l) = l;
-end;
-
-function    AVIStreamPrevSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamPrevSample(pavi,AVIStreamTimeToSample(pavi,t)));
-end;
-
-function    AVIStreamNextSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamNextSample(pavi,AVIStreamTimeToSample(pavi,t)));
-end;
-
-function    AVIStreamNearestSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamNearestSample(pavi,AVIStreamTimeToSample(pavi,t)));
-end;
-
-function    AVIStreamNextKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamNextKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)));
-end;
-
-function    AVIStreamPrevKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamPrevKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)));
-end;
-
-function    AVIStreamNearestKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamNearestKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)));
-end;
-
-function    AVIStreamStartTime(pavi: IAVISTREAM): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamStart(pavi));
-end;
-
-function    AVIStreamLengthTime(pavi: IAVISTREAM): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamLength(pavi));
-end;
-
-function    AVIStreamEnd(pavi: IAVISTREAM): LONG;
-begin
-    Result  := AVIStreamStart(pavi) + AVIStreamLength(pavi);
-end;
-
-function    AVIStreamEndTime(pavi: IAVISTREAM): LONG;
-begin
-    Result  := AVIStreamSampleToTime(pavi, AVIStreamEnd(pavi));
-end;
-
-function    AVIStreamSampleSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): LONG;
-begin
-    Result  := AVIStreamRead(pavi,lPos,1,nil,0,plSize,nil);
-end;
-
-function    AVIStreamFormatSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): HResult;
-begin
-    Result  := AVIStreamReadFormat(pavi,lPos,nil,plSize);
-end;
-
-function    AVIStreamDataSize(pavi: IAVISTREAM; fcc: DWORD; plSize: PLONG): HResult;
-begin
-    Result  := AVIStreamReadData(pavi,fcc,nil,plSize)
-end;
-
-{== MCIWnd ===================================================================}
-
-function    MCIWndSM(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): DWORD;
-begin
-    Result := SendMessage(hWnd, Msg, wParam, lParam);
-end;
-
-{-- Can macros ---------------------------------------------------------------}
-
-function    MCIWndCanPlay(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_PLAY,0,0) <> 0;
-end;
-
-function    MCIWndCanRecord(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_RECORD,0,0) <> 0;
-end;
-
-function    MCIWndCanSave(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_SAVE,0,0) <> 0;
-end;
-
-function    MCIWndCanWindow(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_WINDOW,0,0) <> 0;
-end;
-
-function    MCIWndCanEject(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_EJECT,0,0) <> 0;
-end;
-
-function    MCIWndCanConfig(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_CONFIG,0,0) <> 0;
-end;
-
-function    MCIWndPaletteKick(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd,MCIWNDM_PALETTEKICK,0,0) <> 0;
-end;
-
-function    MCIWndSave(hwnd: HWND; szFile: LPCSTR): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_SAVE, 0, LPARAM(szFile));
-end;
-
-function    MCIWndSaveDialog(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSave(hwnd, LPCSTR(-1));
-end;
-
-// If you dont give a device it will use the current device....
-
-function    MCIWndNew(hwnd: HWND; lp: PVOID): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_NEW, 0, LPARAM(lp));
-end;
-
-function    MCIWndRecord(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_RECORD, 0, 0);
-end;
-
-function    MCIWndOpen(hwnd: HWND; sz: LPCSTR; f: BOOL): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_OPEN, WPARAM(f), LPARAM(sz));
-end;
-
-function    MCIWndOpenDialog(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndOpen(hwnd, LPCSTR(-1), False);
-end;
-
-function    MCIWndClose(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_CLOSE, 0, 0);
-end;
-
-function    MCIWndPlay(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_PLAY, 0, 0);
-end;
-
-function    MCIWndStop(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_STOP, 0, 0);
-end;
-
-function    MCIWndPause(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_PAUSE, 0, 0);
-end;
-
-function    MCIWndResume(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_RESUME, 0, 0);
-end;
-
-function    MCIWndSeek(hwnd: HWND; lPos: DWORD): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_SEEK, 0, lPos);
-end;
-
-function    MCIWndEject(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_EJECT, 0, 0);
-end;
-
-function    MCIWndHome(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSeek(hwnd, MCIWND_START);
-end;
-
-function    MCIWndEnd(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSeek(hwnd, MCIWND_END);
-end;
-
-function    MCIWndGetSource(hwnd: HWND; prc: PRECT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GET_SOURCE, 0, LPARAM(prc));
-end;
-
-function    MCIWndPutSource(hwnd: HWND; prc: PRECT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_PUT_SOURCE, 0, LPARAM(prc));
-end;
-
-function    MCIWndGetDest(hwnd: HWND; prc: PRECT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GET_DEST, 0, LPARAM(prc));
-end;
-
-function    MCIWndPutDest(hwnd: HWND; prc: PRECT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_PUT_DEST, 0, LPARAM(prc));
-end;
-
-function    MCIWndPlayReverse(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_PLAYREVERSE, 0, 0);
-end;
-
-function    MCIWndPlayFrom(hwnd: HWND; lPos: DWORD): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_PLAYFROM, 0, lPos);
-end;
-
-function    MCIWndPlayTo(hwnd: HWND; lPos: DWORD): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_PLAYTO, 0, lPos);
-end;
-
-function    MCIWndPlayFromTo(hwnd: HWND; lStart, lEnd: DWORD): DWORD;
-begin
-    MCIWndSeek(hwnd, lStart);
-    Result  := MCIWndPlayTo(hwnd, lEnd);
-end;
-
-function    MCIWndGetDeviceID(hwnd: HWND): UINT;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETDEVICEID, 0, 0);
-end;
-
-function    MCIWndGetAlias(hwnd: HWND): UINT;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETALIAS, 0, 0);
-end;
-
-function    MCIWndGetMode(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETMODE, len, LPARAM(lp));
-end;
-
-function    MCIWndGetPosition(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETPOSITION, 0, 0);
-end;
-
-function    MCIWndGetPositionString(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETPOSITION, len, LPARAM(lp));
-end;
-
-function    MCIWndGetStart(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETSTART, 0, 0);
-end;
-
-function    MCIWndGetLength(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETLENGTH, 0, 0);
-end;
-
-function    MCIWndGetEnd(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETEND, 0, 0);
-end;
-
-function    MCIWndStep(hwnd: HWND; n: DWORD): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCI_STEP, 0, n);
-end;
-
-procedure   MCIWndDestroy(hwnd: HWND);
-begin
-    MCIWndSM(hwnd, WM_CLOSE, 0, 0);
-end;
-
-procedure   MCIWndSetZoom(hwnd: HWND; iZoom: UINT);
-begin
-    MCIWndSM(hwnd, MCIWNDM_SETZOOM, 0, iZoom);
-end;
-
-function    MCIWndGetZoom(hwnd: HWND): UINT;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETZOOM, 0, 0);
-end;
-
-function    MCIWndSetVolume(hwnd: HWND; iVol: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_SETVOLUME, 0, iVol);
-end;
-
-function    MCIWndGetVolume(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETVOLUME, 0, 0);
-end;
-
-function    MCIWndSetSpeed(hwnd: HWND; iSpeed: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_SETSPEED, 0, iSpeed);
-end;
-
-function    MCIWndGetSpeed(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETSPEED, 0, 0);
-end;
-
-function    MCIWndSetTimeFormat(hwnd: HWND; lp: LPCSTR): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_SETTIMEFORMAT, 0, LPARAM(lp));
-end;
-
-function    MCIWndGetTimeFormat(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETTIMEFORMAT, len, LPARAM(lp));
-end;
-
-procedure   MCIWndValidateMedia(hwnd: HWND);
-begin
-    MCIWndSM(hwnd, MCIWNDM_VALIDATEMEDIA, 0, 0);
-end;
-
-procedure   MCIWndSetRepeat(hwnd: HWND; f: BOOL);
-begin
-    MCIWndSM(hwnd, MCIWNDM_SETREPEAT, 0, LPARAM(f));
-end;
-
-function    MCIWndGetRepeat(hwnd: HWND): BOOL;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETREPEAT, 0, 0) <> 0;
-end;
-
-function    MCIWndUseFrames(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSetTimeFormat(hwnd, 'frames');
-end;
-
-function    MCIWndUseTime(hwnd: HWND): DWORD;
-begin
-    Result  := MCIWndSetTimeFormat(hwnd, 'ms');
-end;
-
-procedure   MCIWndSetActiveTimer(hwnd: HWND; active: UINT);
-begin
-    MCIWndSM(hwnd, MCIWNDM_SETACTIVETIMER, active, 0);
-end;
-
-procedure   MCIWndSetInactiveTimer(hwnd: HWND; inactive: UINT);
-begin
-    MCIWndSM(hwnd, MCIWNDM_SETINACTIVETIMER, inactive, 0);
-end;
-
-procedure   MCIWndSetTimers(hwnd: HWND; active, inactive: UINT);
-begin
-    MCIWndSM(hwnd, MCIWNDM_SETTIMERS, active, inactive);
-end;
-
-function    MCIWndGetActiveTimer(hwnd: HWND): UINT;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETACTIVETIMER, 0, 0);
-end;
-
-function    MCIWndGetInactiveTimer(hwnd: HWND): UINT;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETINACTIVETIMER, 0, 0);
-end;
-
-function    MCIWndRealize(hwnd: HWND; fBkgnd: BOOL): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_REALIZE, WPARAM(fBkgnd), 0);
-end;
-
-function    MCIWndSendString(hwnd: HWND; sz: LPCSTR): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_SENDSTRING, 0, LPARAM(sz));
-end;
-
-function    MCIWndReturnString(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_RETURNSTRING, len, LPARAM(lp));
-end;
-
-function    MCIWndGetError(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETERROR, len, LPARAM(lp));
-end;
-
-function    MCIWndGetPalette(hwnd: HWND): HPALETTE;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETPALETTE, 0, 0);
-end;
-
-function    MCIWndSetPalette(hwnd: HWND; hpal: HPALETTE): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_SETPALETTE, hpal, 0);
-end;
-
-function    MCIWndGetFileName(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETFILENAME, len, LPARAM(lp));
-end;
-
-function    MCIWndGetDevice(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETDEVICE, len, LPARAM(lp));
-end;
-
-function    MCIWndGetStyles(hwnd: HWND): UINT;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_GETSTYLES, 0, 0);
-end;
-
-function    MCIWndChangeStyles(hwnd: HWND; mask: UINT; value: DWORD): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_CHANGESTYLES, mask, value);
-end;
-
-function    MCIWndOpenInterface(hwnd: HWND; pUnk: PUNKNOWN): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_OPENINTERFACE, 0, LPARAM(pUnk));
-end;
-
-function    MCIWndSetOwner(hwnd: HWND; hwndP: HWND): DWORD;
-begin
-    Result  := MCIWndSM(hwnd, MCIWNDM_SETOWNER, hwndP, 0);
-end;
-
-{== AVICAP - Window class for AVI capture ====================================}
-
-function    AVICapSM(hwnd: HWND; m: UINT; w: WPARAM; l: LPARAM): DWORD;
-begin
-    if IsWindow(hwnd) then
-        Result := SendMessage(hwnd,m,w,l)
-    else
-        Result := 0;
-end;
-
-{-- Message crackers for above -----------------------------------------------}
-
-function    capSetCallbackOnError(hwnd: HWND; fpProc: TCAPERRORCALLBACK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_ERROR, 0, LPARAM(@fpProc)) <> 0;
-end;
-
-function    capSetCallbackOnStatus(hwnd: HWND; fpProc: TCAPSTATUSCALLBACK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_STATUS, 0, LPARAM(@fpProc)) <> 0;
-end;
-
-function    capSetCallbackOnYield(hwnd: HWND; fpProc: TCAPYIELDCALLBACK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_YIELD, 0, LPARAM(@fpProc)) <> 0;
-end;
-
-function    capSetCallbackOnFrame(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_FRAME, 0, LPARAM(@fpProc)) <> 0;
-end;
-
-function    capSetCallbackOnVideoStream(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, LPARAM(@fpProc)) <> 0;
-end;
-
-function    capSetCallbackOnWaveStream(hwnd: HWND; fpProc: TCAPWAVECALLBACK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_WAVESTREAM, 0, LPARAM(@fpProc)) <> 0;
-end;
-
-function    capSetCallbackOnCapControl(hwnd: HWND; fpProc: TCAPCONTROLCALLBACK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_CAPCONTROL, 0, LPARAM(@fpProc)) <> 0;
-end;
-
-function    capSetUserData(hwnd: HWND; lUser: DWORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_USER_DATA, 0, lUser) <> 0;
-end;
-
-function    capGetUserData(hwnd: HWND): DWORD;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_USER_DATA, 0, 0);
-end;
-
-function    capDriverConnect(hwnd: HWND; i: INT): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_CONNECT, i, 0) <> 0;
-end;
-
-function    capDriverDisconnect(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0) <> 0;
-end;
-
-function    capDriverGetName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_GET_NAME, wSize, LPARAM(szName)) <> 0;
-end;
-
-function    capDriverGetVersion(hwnd: HWND; szVer: LPSTR; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_GET_VERSION, wSize, LPARAM(szVer)) <> 0;
-end;
-
-function    capDriverGetCaps(hwnd: HWND; s: PCAPDRIVERCAPS; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_GET_CAPS, wSize, LPARAM(s)) <> 0;
-end;
-
-function    capFileSetCaptureFile(hwnd: HWND; szName: LPCSTR): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_FILE_SET_CAPTURE_FILE, 0, LPARAM(szName)) <> 0;
-end;
-
-function    capFileGetCaptureFile(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_FILE_GET_CAPTURE_FILE, wSize, LPARAM(szName)) <> 0;
-end;
-
-function    capFileAlloc(hwnd: HWND; dwSize: DWORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_FILE_ALLOCATE, 0, dwSize) <> 0;
-end;
-
-function    capFileSaveAs(hwnd: HWND; szName: LPCSTR): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_FILE_SAVEAS, 0, LPARAM(szName)) <> 0;
-end;
-
-function    capFileSetInfoChunk(hwnd: HWND; lpInfoChunk: PCAPINFOCHUNK): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_FILE_SET_INFOCHUNK, 0, LPARAM(lpInfoChunk)) <> 0;
-end;
-
-function    capFileSaveDIB(hwnd: HWND; szName: LPCSTR): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_FILE_SAVEDIB, 0, LPARAM(szName)) <> 0;
-end;
-
-function    capEditCopy(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_EDIT_COPY, 0, 0) <> 0;
-end;
-
-function    capSetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_AUDIOFORMAT, wSize, LPARAM(s)) <> 0;
-end;
-
-function    capGetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): DWORD;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_AUDIOFORMAT, wSize, LPARAM(s));
-end;
-
-function    capGetAudioFormatSize(hwnd: HWND): DWORD;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_AUDIOFORMAT, 0, 0);
-end;
-
-function    capDlgVideoFormat(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEOFORMAT, 0, 0) <> 0;
-end;
-
-function    capDlgVideoSource(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEOSOURCE, 0, 0) <> 0;
-end;
-
-function    capDlgVideoDisplay(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEODISPLAY, 0, 0) <> 0;
-end;
-
-function    capDlgVideoCompression(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEOCOMPRESSION, 0, 0) <> 0;
-end;
-
-function    capGetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): DWORD;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, wSize, LPARAM(s));
-end;
-
-function    capGetVideoFormatSize(hwnd: HWND): DWORD;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, 0, 0);
-end;
-
-function    capSetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_VIDEOFORMAT, wSize, LPARAM(s)) <> 0;
-end;
-
-function    capPreview(hwnd: HWND; f: BOOL): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_PREVIEW, WPARAM(f), 0) <> 0;
-end;
-
-function    capPreviewRate(hwnd: HWND; wMS: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_PREVIEWRATE, wMS, 0) <> 0;
-end;
-
-function    capOverlay(hwnd: HWND; f: BOOL): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_OVERLAY, WPARAM(f), 0) <> 0;
-end;
-
-function    capPreviewScale(hwnd: HWND; f: BOOL): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_SCALE, WPARAM(f), 0) <> 0;
-end;
-
-function    capGetStatus(hwnd: HWND; s: PCAPSTATUS; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_STATUS, wSize, LPARAM(s)) <> 0;
-end;
-
-function    capSetScrollPos(hwnd: HWND; lpP: PPOINT): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_SCROLL, 0, LPARAM(lpP)) <> 0;
-end;
-
-function    capGrabFrame(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GRAB_FRAME, 0, 0) <> 0;
-end;
-
-function    capGrabFrameNoStop(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0) <> 0;
-end;
-
-function    capCaptureSequence(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SEQUENCE, 0, 0) <> 0;
-end;
-
-function    capCaptureSequenceNoFile(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SEQUENCE_NOFILE, 0, 0) <> 0;
-end;
-
-function    capCaptureStop(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_STOP, 0, 0) <> 0;
-end;
-
-function    capCaptureAbort(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_ABORT, 0, 0) <> 0;
-end;
-
-function    capCaptureSingleFrameOpen(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SINGLE_FRAME_OPEN, 0, 0) <> 0;
-end;
-
-function    capCaptureSingleFrameClose(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SINGLE_FRAME_CLOSE, 0, 0) <> 0;
-end;
-
-function    capCaptureSingleFrame(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SINGLE_FRAME, 0, 0) <> 0;
-end;
-
-function    capCaptureGetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_SEQUENCE_SETUP, wSize, LPARAM(s)) <> 0;
-end;
-
-function    capCaptureSetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_SEQUENCE_SETUP, wSize, LPARAM(s)) <> 0;
-end;
-
-function    capSetMCIDeviceName(hwnd: HWND; szName: LPCSTR): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_SET_MCI_DEVICE, 0, LPARAM(szName)) <> 0;
-end;
-
-function    capGetMCIDeviceName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_GET_MCI_DEVICE, wSize, LPARAM(szName)) <> 0;
-end;
-
-function    capPaletteOpen(hwnd: HWND; szName: LPCSTR): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_PAL_OPEN, 0, LPARAM(szName)) <> 0;
-end;
-
-function    capPaletteSave(hwnd: HWND; szName: LPCSTR): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_PAL_SAVE, 0, LPARAM(szName)) <> 0;
-end;
-
-function    capPalettePaste(hwnd: HWND): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_PAL_PASTE, 0, 0) <> 0;
-end;
-
-function    capPaletteAuto(hwnd: HWND; iFrames, iColors: INT): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_PAL_AUTOCREATE, iFrames, iColors) <> 0;
-end;
-
-function    capPaletteManual(hwnd: HWND; fGrab: BOOL; iColors: INT): BOOL;
-begin
-    Result  := AVICapSM(hwnd, WM_CAP_PAL_MANUALCREATE, WPARAM(fGrab), iColors) <> 0;
-end;
-
-{== Externals ================================================================}
-
-const
-    VFWDLL      = 'MSVFW32.DLL';
-    AVIFILDLL   = 'AVIFIL32.DLL';
-    AVICAPDLL   = 'AVICAP32.DLL';
-
-{-- Returns version of VFW ---------------------------------------------------}
-
-function    VideoForWindowsVersion: DWord; pascal; external VFWDLL;
-
-{-- Call these to start stop using VfW from your app -------------------------}
-
-{ TODO: Where are these functions? }
-                            {
- function    InitVFW: LONG; stdcall;
- function    TermVFW: LONG; stdcall; }
-
-{-- ICM function declarations ------------------------------------------------}
-
-function    ICInfo(fccType, fccHandler: DWORD; lpicinfo: PICINFO) : BOOL ; stdcall ; external VFWDLL;
-function    ICInstall(fccType, fccHandler: DWORD; lParam: LPARAM; szDesc: LPSTR; wFlags: UINT) : BOOL ; stdcall ; external VFWDLL;
-function    ICRemove(fccType, fccHandler: DWORD; wFlags: UINT) : BOOL ; stdcall ; external VFWDLL;
-function    ICGetInfo(hic: HIC; picinfo: PICINFO; cb: DWORD) : DWORD ; stdcall ; external VFWDLL;
-
-function    ICOpen(fccType, fccHandler: DWORD; wMode: UINT) : HIC ; stdcall ; external VFWDLL;
-function    ICOpenFunction(fccType, fccHandler: DWORD; wMode: UINT; lpfnHandler: TFarProc) : HIC ; stdcall ; external VFWDLL;
-function    ICClose(hic: HIC) : DWORD ; stdcall ; external VFWDLL;
-
-function    ICSendMessage(hic: HIC; msg: UINT; dw1, dw2: DWORD) : DWORD ; stdcall ; external VFWDLL;
-
-{== Compression functions ====================================================}
-
-{-- ICCompress() - compress a single frame -----------------------------------}
-
-function    ICCompress(
-    hic             : HIC;
-    dwFlags         : DWORD;                // flags
-    lpbiOutput      : PBITMAPINFOHEADER;    // output format
-    lpData          : PVOID;                // output data
-    lpbiInput       : PBITMAPINFOHEADER;    // format of frame to compress
-    lpBits          : PVOID;                // frame data to compress
-    lpckid          : PDWORD;               // ckid for data in AVI file
-    lpdwFlags       : PDWORD;               // flags in the AVI index.
-    lFrameNum       : DWORD;                 // frame number of seq.
-    dwFrameSize     : DWORD;                // reqested size in bytes. (if non zero)
-    dwQuality       : DWORD;                // quality within one frame
-    lpbiPrev        : PBITMAPINFOHEADER;    // format of previous frame
-    lpPrev          : PVOID                 // previous frame
-    ) : DWORD; cdecl; external VFWDLL;
-
-{== Decompression functions ==================================================}
-
-{-- ICDecompress() - decompress a single frame -------------------------------}
-
-function    ICDecompress(
-    hic             : HIC;
-    dwFlags         : DWORD;                // flags (from AVI index...)
-    lpbiFormat      : PBITMAPINFOHEADER;    // BITMAPINFO of compressed data
-                                            // biSizeImage has the chunk size
-    lpData          : PVOID;                // data
-    lpbi            : PBITMAPINFOHEADER;    // DIB to decompress to
-    lpBits          : PVOID
-    ): DWORD; cdecl; external VFWDLL;
-
-{== Drawing functions ========================================================}
-
-{-- ICDrawBegin() - start decompressing data with fmt directly to screen -----}
-
-// return zero if the decompressor supports drawing.
-
-function    ICDrawBegin(
-    hic         : HIC;
-    dwFlags     : DWORD;                // flags
-    hpal        : HPALETTE;             // palette to draw with
-    hwnd        : HWND;                 // window to draw to
-    hdc         : HDC;                  // HDC to draw to
-    xDst        : int;                  // destination rectangle
-    yDst        : int;
-    dxDst       : int;
-    dyDst       : int;
-    lpbi        : PBITMAPINFOHEADER;    // format of frame to draw
-    xSrc        : int;                  // source rectangle
-    ySrc        : int;
-    dxSrc       : int;
-    dySrc       : int;
-    dwRate      : DWORD;                // frames/second = (dwRate/dwScale)
-    dwScale     : DWORD
-    ): DWORD; cdecl; external VFWDLL;
-
-{-- ICDraw() - decompress data directly to the screen ------------------------}
-
-function    ICDraw(
-    hic         : HIC;
-    dwFlags     : DWORD;                // flags
-    lpFormat    : PVOID;                // format of frame to decompress
-    lpData      : PVOID;                // frame data to decompress
-    cbData      : DWORD;                // size of data
-    lTime       : DWORD                  // time to draw this frame
-    ): DWORD; cdecl; external VFWDLL;
-
-{== Helper routines for DrawDib and MCIAVI... ================================}
-
-function    ICLocate(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER; wFlags: WORD): HIC; stdcall; external VFWDLL;
-function    ICGetDisplayFormat(hic: HIC; lpbiIn, lpbiOut: PBITMAPINFOHEADER; BitDepth: int; dx, dy: int): HIC; stdcall; external VFWDLL;
-
-{== Higher level functions ===================================================}
-
-function    ICImageCompress(
-    hic         : HIC;                  // compressor to use
-    uiFlags     : UINT;                 // flags (none yet)
-    lpbiIn      : PBITMAPINFO;          // format to compress from
-    lpBits      : PVOID;                // data to compress
-    lpbiOut     : PBITMAPINFO;          // compress to this (NULL ==> default)
-    lQuality    : LONG;                 // quality to use
-    plSize      : PDWORD                 // compress to this size (0=whatever)
-    ): THANDLE; stdcall; external VFWDLL;
-
-function    ICImageDecompress(
-    hic         : HIC;                  // compressor to use
-    uiFlags     : UINT;                 // flags (none yet)
-    lpbiIn      : PBITMAPINFO;          // format to decompress from
-    lpBits      : PVOID;                // data to decompress
-    lpbiOut     : PBITMAPINFO           // decompress to this (NULL ==> default)
-    ): THANDLE; stdcall; external VFWDLL;
-
-{-- ICCompressorChoose() - allows user to choose compressor, quality etc... --}
-
-function    ICCompressorChoose(
-    hwnd        : HWND;                     // parent window for dialog
-    uiFlags     : UINT;                     // flags
-    pvIn        : PVOID;                    // input format (optional)
-    lpData      : PVOID;                    // input data (optional)
-    pc          : PCOMPVARS;                // data about the compressor/dlg
-    lpszTitle   : LPSTR                     // dialog title (optional)
-    ): BOOL; stdcall; external VFWDLL;
-
-function    ICSeqCompressFrameStart(pc: PCOMPVARS; lpbiIn: PBITMAPINFO): BOOL; stdcall; external VFWDLL;
-procedure   ICSeqCompressFrameEnd(pc: PCOMPVARS); stdcall; external VFWDLL;
-
-function    ICSeqCompressFrame(
-    pc          : PCOMPVARS;                // set by ICCompressorChoose
-    uiFlags     : UINT;                     // flags
-    lpBits      : PVOID;                    // input DIB bits
-    pfKey       : PBOOL;                    // did it end up being a key frame?
-    plSize      : PDWORD                     // size to compress to/of returned image
-    ): PVOID; stdcall; external VFWDLL;
-
-procedure   ICCompressorFree(pc: PCOMPVARS); stdcall; external VFWDLL;
-
-{== DrawDib functions ========================================================}
-
-{-- DrawDibOpen() ------------------------------------------------------------}
-
-function    DrawDibOpen: HDRAWDIB; stdcall; external VFWDLL;
-
-{-- DrawDibClose() -----------------------------------------------------------}
-
-function    DrawDibClose(hdd: HDRAWDIB): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibGetBuffer() -------------------------------------------------------}
-
-function    DrawDibGetBuffer(hdd: HDRAWDIB; lpbi: PBITMAPINFOHEADER; dwSize: DWORD; dwFlags: DWORD): PVOID; stdcall; external VFWDLL;
-
-{-- DrawDibGetPalette() - get the palette used for drawing DIBs --------------}
-
-function    DrawDibGetPalette(hdd: HDRAWDIB): HPALETTE; stdcall; external VFWDLL;
-
-{-- DrawDibSetPalette() - set the palette used for drawing DIBs --------------}
-
-function    DrawDibSetPalette(hdd: HDRAWDIB; hpal: HPALETTE): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibChangePalette() ---------------------------------------------------}
-
-function    DrawDibChangePalette(hdd: HDRAWDIB; iStart, iLen: int; lppe: PPALETTEENTRY): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibRealize() - realize the palette in a HDD --------------------------}
-
-function    DrawDibRealize(hdd: HDRAWDIB; hdc: HDC; fBackground: BOOL): UINT; stdcall; external VFWDLL;
-
-{-- DrawDibStart() - start of streaming playback -----------------------------}
-
-function    DrawDibStart(hdd: HDRAWDIB; rate: DWORD): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibStop() - start of streaming playback ------------------------------}
-
-function    DrawDibStop(hdd: HDRAWDIB): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibBegin() - prepare to draw -----------------------------------------}
-
-function    DrawDibBegin(
-    hdd         : HDRAWDIB;
-    hdc         : HDC;
-    dxDst       : int;
-    dyDst       : int;
-    lpbi        : PBITMAPINFOHEADER;
-    dxSrc       : int;
-    dySrc       : int;
-    wFlags      : UINT
-    ): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibDraw() - actually draw a DIB to the screen ------------------------}
-
-function    DrawDibDraw(
-    hdd         : HDRAWDIB;
-    hdc         : HDC;
-    xDst        : int;
-    yDst        : int;
-    dxDst       : int;
-    dyDst       : int;
-    lpbi        : PBITMAPINFOHEADER;
-    lpBits      : PVOID;
-    xSrc        : int;
-    ySrc        : int;
-    dxSrc       : int;
-    dySrc       : int;
-    wFlags      : UINT
-    ): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibEnd() -------------------------------------------------------------}
-
-function    DrawDibEnd(hdd: HDRAWDIB): BOOL; stdcall; external VFWDLL;
-
-{-- DrawDibTime() - for debugging purposes only ------------------------------}
-
-function    DrawDibTime(hdd: HDRAWDIB; lpddtime: PDRAWDIBTIME): BOOL; stdcall; external VFWDLL;
-
-{-- Display profiling --------------------------------------------------------}
-
-function    DrawDibProfileDisplay(lpbi: PBITMAPINFOHEADER): DWORD; stdcall; external VFWDLL;
-
-{-- Functions ----------------------------------------------------------------}
-
-procedure   AVIFileInit; stdcall; external AVIFILDLL; // Call this first!
-procedure   AVIFileExit; stdcall; external AVIFILDLL;
-
-function    AVIFileAddRef(pfile: IAVIFILE): ULONG; stdcall; external AVIFILDLL;
-function    AVIFileRelease(pfile: IAVIFILE): ULONG; stdcall; external AVIFILDLL;
-
-function    AVIFileOpenA(var ppfile: IAVIFILE; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
-function    AVIFileOpenW(var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
-
-{$IFDEF UNICODE}
-function    AVIFileOpen(var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;  external AVIFILDLL name 'AVIFileOpenW';
-{$ELSE}
-function    AVIFileOpen(var ppfile: IAVIFILE; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;  external AVIFILDLL name 'AVIFileOpenA';
-{$ENDIF}
-
-function    AVIFileInfoW(pfile: IAVIFILE; var pfi: TAVIFILEINFOW; lSize: LONG): HResult; stdcall; external AVIFILDLL;
-function    AVIFileInfoA(pfile: IAVIFILE; var pfi: TAVIFILEINFOA; lSize: LONG): HResult; stdcall; external AVIFILDLL;
-
-{$IFDEF UNICODE}
-function    AVIFileInfo(pfile: IAVIFILE; var pfi: TAVIFILEINFO; lSize: LONG): HResult; stdcall;  external AVIFILDLL name 'AVIFileInfoW';
-{$ELSE}
-function    AVIFileInfo(pfile: IAVIFILE; var pfi: TAVIFILEINFO; lSize: LONG): HResult; stdcall;  external AVIFILDLL name 'AVIFileInfoA';
-{$ENDIF}
-
-function    AVIFileGetStream(pfile: IAVIFILE; var ppavi: IAVISTREAM; fccType: DWORD; lParam: LONG): HResult; stdcall; external AVIFILDLL;
-
-function    AVIFileCreateStreamW(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOW): HResult; stdcall; external AVIFILDLL;
-function    AVIFileCreateStreamA(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOA): HResult; stdcall; external AVIFILDLL;
-
-{$IFDEF UNICODE}
-function    AVIFileCreateStream(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFO): HResult; stdcall; external AVIFILDLL name 'AVIFileCreateStreamW';
-{$ELSE}
-function    AVIFileCreateStream(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFO): HResult; stdcall; external AVIFILDLL name 'AVIFileCreateStreamA';
-{$ENDIF}
-
-function    AVIFileWriteData(pfile: IAVIFILE; ckid: DWORD; lpData: PVOID; cbData: LONG): HResult; stdcall; external AVIFILDLL;
-function    AVIFileReadData(pfile: IAVIFILE; ckid: DWORD; lpData: PVOID; var lpcbData: LONG): HResult; stdcall; external AVIFILDLL;
-function    AVIFileEndRecord(pfile: IAVIFILE): HResult; stdcall; external AVIFILDLL;
-
-function    AVIStreamAddRef(pavi: IAVISTREAM): ULONG; stdcall; external AVIFILDLL;
-function    AVIStreamRelease(pavi: IAVISTREAM): ULONG; stdcall; external AVIFILDLL;
-
-function    AVIStreamInfoW (pavi: IAVISTREAM; var psi: TAVISTREAMINFOW; lSize: LONG): HResult; stdcall; external AVIFILDLL;
-function    AVIStreamInfoA (pavi: IAVISTREAM; var psi: TAVISTREAMINFOA; lSize: LONG): HResult; stdcall; external AVIFILDLL;
-
-{$IFDEF UNICODE}
-function    AVIStreamInfo(pavi: IAVISTREAM; var psi: TAVISTREAMINFO; lSize: LONG): HResult; stdcall; external AVIFILDLL name 'AVIStreamInfoW';
-{$ELSE}
-function    AVIStreamInfo(pavi: IAVISTREAM; var psi: TAVISTREAMINFO; lSize: LONG): HResult; stdcall; external AVIFILDLL name 'AVIStreamInfoA';
-{$ENDIF}
-
-
-function    AVIStreamFindSample(pavi: IAVISTREAM; lPos: LONG; lFlags: LONG): LONG; stdcall; external AVIFILDLL;
-function    AVIStreamReadFormat(pavi: IAVISTREAM; lPos: LONG; lpFormat: PVOID; lpcbFormat: PLONG): HResult; stdcall; external AVIFILDLL;
-function    AVIStreamSetFormat(pavi: IAVISTREAM; lPos: LONG; lpFormat: PVOID; cbFormat: LONG): HResult; stdcall; external AVIFILDLL;
-function    AVIStreamReadData(pavi: IAVISTREAM; fcc: DWORD; lp: PVOID; lpcb: PLONG): HResult; stdcall; external AVIFILDLL;
-function    AVIStreamWriteData(pavi: IAVISTREAM; fcc: DWORD; lp: PVOID; cb: LONG): HResult; stdcall; external AVIFILDLL;
-
-function    AVIStreamRead(
-    pavi            : IAVISTREAM;
-    lStart          : LONG;
-    lSamples        : LONG;
-    lpBuffer        : PVOID;
-    cbBuffer        : LONG;
-    plBytes         : PLONG;
-    plSamples       : PLONG
-    ): HResult; stdcall; external AVIFILDLL;
-
-function    AVIStreamWrite(
-    pavi            : IAVISTREAM;
-    lStart          : LONG;
-    lSamples        : LONG;
-    lpBuffer        : PVOID;
-    cbBuffer        : LONG;
-    dwFlags         : DWORD;
-    plSampWritten   : PLONG;
-    plBytesWritten  : PLONG
-    ): HResult; stdcall; external AVIFILDLL;
-
-// Right now, these just use AVIStreamInfo() to get information, then
-// return some of it.  Can they be more efficient?
-
-function    AVIStreamStart(pavi: IAVISTREAM): LONG; stdcall; external AVIFILDLL;
-function    AVIStreamLength(pavi: IAVISTREAM): LONG; stdcall; external AVIFILDLL;
-function    AVIStreamTimeToSample(pavi: IAVISTREAM; lTime: LONG): LONG; stdcall; external AVIFILDLL;
-function    AVIStreamSampleToTime(pavi: IAVISTREAM; lSample: LONG): LONG; stdcall; external AVIFILDLL;
-
-function    AVIStreamBeginStreaming(pavi: IAVISTREAM; lStart, lEnd: LONG; lRate: LONG): HResult; stdcall; external AVIFILDLL;
-function    AVIStreamEndStreaming(pavi: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
-
-{-- Helper functions for using IGetFrame -------------------------------------}
-
-function    AVIStreamGetFrameOpen_(pavi: IAVISTREAM; lpbiWanted: PBitmapInfoHeader): pointer; stdcall; external AVIFILDLL name 'AVIStreamGetFrameOpen';
-function    AVIStreamGetFrame(pg: IGETFRAME; lPos: LONG): PBitmapInfoHeader; stdcall; external AVIFILDLL;
-function    AVIStreamGetFrameClose(pg: IGETFRAME): HResult; stdcall; external AVIFILDLL;
-
-function    AVIStreamGetFrameOpen(pavi: IAVIStream; lpbiWanted: PBitmapInfoHeader): IGetFrame; stdcall;
-begin
-  pointer(Result) := AVIStreamGetFrameOpen_(pavi, lpbiWanted);
-end;
-
-// !!! We need some way to place an advise on a stream....
-// STDAPI AVIStreamHasChanged   (PAVISTREAM pavi);
-
-{-- Shortcut function --------------------------------------------------------}
-
-function    AVIStreamOpenFromFileA(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
-                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
-function    AVIStreamOpenFromFileW(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
-                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
-
-{$IFDEF UNICODE}
-function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
-  lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL name 'AVIStreamOpenFromFileW';
-{$ELSE}
-function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
-  lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL name 'AVIStreamOpenFromFileA';
-{$ENDIF}
-
-{-- Use to create disembodied streams ----------------------------------------}
-
-function    AVIStreamCreate(var ppavi: IAVISTREAM; lParam1, lParam2: LONG;
-                            pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
-
-// PHANDLER    AVIAPI AVIGetHandler         (PAVISTREAM pavi, PAVISTREAMHANDLER psh);
-// PAVISTREAM  AVIAPI AVIGetStream          (PHANDLER p);
-
-{-- Stuff to support backward compat. ----------------------------------------}
-
-function    AVIStreamFindKeyFrame(var pavi: IAVISTREAM; lPos: LONG; lFlags: LONG): DWORD; stdcall; external AVIFILDLL name 'AVIStreamFindSample';
-
-// Non-portable: this is alias for method name
-// FindKeyFrame FindSample
-
-function    AVIStreamClose(pavi: IAVISTREAM): ULONG; stdcall; external AVIFILDLL name 'AVIStreamRelease';
-function    AVIFileClose(pfile: IAVIFILE): ULONG; stdcall; external AVIFILDLL name 'AVIFileRelease';
-procedure   AVIStreamInit; stdcall; external AVIFILDLL name 'AVIFileInit';
-procedure   AVIStreamExit; stdcall; external AVIFILDLL name 'AVIFileExit';
-
-{== AVISave routines and structures ==========================================}
-
-function    AVIMakeCompressedStream(
-    var ppsCompressed   : IAVISTREAM;
-    ppsSource           : IAVISTREAM;
-    lpOptions           : PAVICOMPRESSOPTIONS;
-    pclsidHandler       : PCLSID
-    ): HResult; stdcall; external AVIFILDLL;
-
-// Non-portable: uses variable number of params
-// EXTERN_C HRESULT CDECL AVISaveA (LPCSTR               szFile,
-//      CLSID FAR *pclsidHandler,
-//      AVISAVECALLBACK     lpfnCallback,
-//      int                 nStreams,
-//      PAVISTREAM      pfile,
-//      LPAVICOMPRESSOPTIONS lpOptions,
-//      ...);
-
-function    AVISaveVA(
-    szFile          : LPCSTR;
-    pclsidHandler   : PCLSID;
-    lpfnCallback    : TAVISAVECALLBACK;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): HResult; stdcall; external AVIFILDLL;
-
-// Non-portable: uses variable number of params
-// EXTERN_C HRESULT CDECL AVISaveW (LPCWSTR               szFile,
-//      CLSID FAR *pclsidHandler,
-//      AVISAVECALLBACK     lpfnCallback,
-//      int                 nStreams,
-//      PAVISTREAM      pfile,
-//      LPAVICOMPRESSOPTIONS lpOptions,
-//      ...);
-
-function    AVISaveVW(
-    szFile          : LPCWSTR;
-    pclsidHandler   : PCLSID;
-    lpfnCallback    : TAVISAVECALLBACK;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): HResult; stdcall; external AVIFILDLL;
-
-// #define AVISave      AVISaveA
-
-function    AVISaveV(
-    szFile          : LPCSTR;
-    pclsidHandler   : PCLSID;
-    lpfnCallback    : TAVISAVECALLBACK;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): HResult; stdcall; external AVIFILDLL name 'AVISaveVA';
-
-function    AVISaveOptions(
-    hwnd            : HWND;
-    uiFlags         : UINT;
-    nStreams        : int;
-    var ppavi       : IAVISTREAM;
-    var plpOptions  : PAVICOMPRESSOPTIONS
-    ): BOOL; stdcall; external AVIFILDLL;
-
-function    AVISaveOptionsFree(nStreams: int; var plpOptions: PAVICOMPRESSOPTIONS): HResult; stdcall; external AVIFILDLL;
-
-{-----------------------------------------------------------------------------}
-
-function    AVIBuildFilterW(lpszFilter: LPWSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; external AVIFILDLL;
-function    AVIBuildFilterA(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; external AVIFILDLL;
-
-function    AVIBuildFilter(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; external AVIFILDLL name 'AVIBuildFilterA';
-
-function    AVIMakeFileFromStreams(var ppfile: IAVIFILE; nStreams: int; var papStreams: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
-
-function    AVIMakeStreamFromClipboard(cfFormat: UINT; hGlobal: THANDLE; var ppstream: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
-
-{-- Clipboard routines -------------------------------------------------------}
-
-function    AVIPutFileOnClipboard(pf: IAVIFILE): HResult; stdcall; external AVIFILDLL;
-function    AVIGetFromClipboard(var lppf: IAVIFILE): HResult; stdcall; external AVIFILDLL;
-function    AVIClearClipboard: HResult; stdcall; external AVIFILDLL;
-
-{-- Editing routines ---------------------------------------------------------}
-
-function    CreateEditableStream(var ppsEditable: IAVISTREAM; psSource: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
-
-function    EditStreamCut(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
-function    EditStreamCopy(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
-function    EditStreamPaste(pavi: IAVISTREAM; var plPos, plLength: LONG; pstream: IAVISTREAM; lStart, lEnd: LONG): HResult; stdcall; external AVIFILDLL;
-function    EditStreamClone(pavi: IAVISTREAM; var ppResult: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
-
-function    EditStreamSetNameA(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall; external AVIFILDLL;
-function    EditStreamSetNameW(pavi: IAVISTREAM; lpszName: LPCWSTR): HResult; stdcall; external AVIFILDLL;
-function    EditStreamSetInfoW(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOW; cbInfo: LONG): HResult; stdcall; external AVIFILDLL;
-function    EditStreamSetInfoA(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall; external AVIFILDLL;
-
-function    EditStreamSetInfo(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall; external AVIFILDLL name 'EditStreamSetInfoA';
-function    EditStreamSetName(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall; external AVIFILDLL name 'EditStreamSetNameA';
-
-{-- MCIWnd -------------------------------------------------------------------}
-
-function    MCIWndCreateA(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl; external VFWDLL;
-function    MCIWndCreateW(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCWSTR): HWND; cdecl; external VFWDLL;
-
-function    MCIWndCreate(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl;  external VFWDLL name 'MCIWndCreateA';
-
-function    MCIWndRegisterClass: BOOL; cdecl; external VFWDLL;
-
-{== AVICAP - Window class for AVI capture ====================================}
-
-{-- The only exported functions from AVICAP.DLL ------------------------------}
-
-function    capCreateCaptureWindowA(
-    lpszWindowName      : LPCSTR;
-    dwStyle             : DWORD;
-    x, y                : int;
-    nWidth, nHeight     : int;
-    hwndParent          : HWND;
-    nID                 : int
-    ): HWND; stdcall; external AVICAPDLL;
-
-function    capGetDriverDescriptionA(
-    wDriverIndex        : UINT;
-    lpszName            : LPSTR;
-    cbName              : int;
-    lpszVer             : LPSTR;
-    cbVer               : int
-    ): BOOL; stdcall; external AVICAPDLL;
-
-function    capCreateCaptureWindowW(
-    lpszWindowName      : LPCWSTR;
-    dwStyle             : DWORD;
-    x, y                : int;
-    nWidth, nHeight     : int;
-    hwndParent          : HWND;
-    nID                 : int
-    ): HWND; stdcall; external AVICAPDLL;
-
-function    capGetDriverDescriptionW(
-    wDriverIndex        : UINT;
-    lpszName            : LPWSTR;
-    cbName              : int;
-    lpszVer             : LPWSTR;
-    cbVer               : int
-    ): BOOL; stdcall; external AVICAPDLL;
-
-function    capCreateCaptureWindow(
-    lpszWindowName      : LPCSTR;
-    dwStyle             : DWORD;
-    x, y                : int;
-    nWidth, nHeight     : int;
-    hwndParent          : HWND;
-    nID                 : int
-    ): HWND; stdcall; external AVICAPDLL name 'capCreateCaptureWindowA';
-
-function    capGetDriverDescription(
-    wDriverIndex        : UINT;
-    lpszName            : LPSTR;
-    cbName              : int;
-    lpszVer             : LPSTR;
-    cbVer               : int
-    ): BOOL; stdcall; external AVICAPDLL name 'capGetDriverDescriptionA';
-
-{== FilePreview dialog =======================================================}
-
-function GetOpenFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL;
-function GetSaveFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL;
-
-function GetOpenFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall; external VFWDLL;
-function GetSaveFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall; external VFWDLL;
-
-function GetOpenFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL name 'GetOpenFileNamePreviewA';
-function GetSaveFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL name 'GetSaveFileNamePreviewA';
-
-end.
+//
+// This unit is part of the GLScene Engine, http://glscene.org
+//
+
+unit Formats.FileVFW;
+
+(*  Video for windows *)
+
+interface
+
+{.$UNDEF UNICODE}
+{$I GLScene.inc}
+
+(****************************************************************************
+ *
+ *      VfW.H - Video for windows include file for WIN32
+ *
+ *      Copyright (c) 1991-1999, Microsoft Corp.  All rights reserved.
+ *
+ *      This include files defines interfaces to the following
+ *      video components
+ *
+ *          COMPMAN         - Installable Compression Manager.
+ *          DRAWDIB         - Routines for drawing to the display.
+ *          VIDEO           - Video Capture Driver Interface
+ *
+ *          AVIFMT          - AVI File Format structure definitions.
+ *          MMREG           - FOURCC and other things
+ *
+ *          AVIFile         - Interface for reading AVI Files and AVI Streams
+ *          MCIWND          - MCI/AVI window class
+ *          AVICAP          - AVI Capture Window class
+ *
+ *          MSACM           - Audio compression manager.
+ *
+ *      The following symbols control inclusion of various parts of this file:
+ *
+ *          NOCOMPMAN       - dont include COMPMAN
+ *          NODRAWDIB       - dont include DRAWDIB
+ *          NOVIDEO         - dont include video capture interface
+ *
+ *          NOAVIFMT        - dont include AVI file format structs
+ *          NOMMREG         - dont include MMREG
+ *
+ *          NOAVIFILE       - dont include AVIFile interface
+ *          NOMCIWND        - dont include AVIWnd class.
+ *          NOAVICAP        - dont include AVICap class.
+ *
+ *          NOMSACM         - dont include ACM stuff.
+ *
+ ****************************************************************************)
+
+(******************************************************************************)
+(*                                                                            *)
+(*  VFW.PAS Conversion by Ronald Dittrich                                     *)
+(*                                                                            *)
+(*  E-Mail: [email protected]                                                 *)
+(*  http://www.swiftsoft.de                                                   *)
+(*                                                                            *)
+(******************************************************************************)
+
+(******************************************************************************)
+(*                                                                            *)
+(*  Modyfied: 25.April.2000                                                   *)
+(*                                                                            *)
+(*  E-Mail:                                                                   *)
+(*  Ivo Steinmann: [email protected]                                      *)
+(*                                                                            *)
+(*  Please send all messages regarding specific errors and lacks of this unit *)
+(*  to Ivo Steinmann                                                          *)
+(*                                                                            *)
+(******************************************************************************)
+
+(******************************************************************************)
+(*                                                                            *)
+(*  Modyfied: 2000-12-07                                                      *)
+(*                                                                            *)
+(*  E-Mail:                                                                   *)
+(*  Peter Haas: [email protected]                                        *)
+(*                                                                            *)
+(*  Only modified line 1380  ( TAVIPALCHANGE.peNew )                          *)
+(*                                                                            *)
+(******************************************************************************)
+
+uses
+    Winapi.Windows,
+    Winapi.MMSystem,
+    Winapi.Messages,
+    Winapi.CommDlg,
+    Winapi.ActiveX;
+
+(****************************************************************************
+ *
+ *  types
+ *
+ ***************************************************************************)
+
+type
+  PVOID = pointer;
+  LONG  = longint;
+  PLONG = ^LONG;
+  int   = integer;
+
+(****************************************************************************
+ *
+ *  VideoForWindowsVersion() - returns version of VfW
+ *
+ ***************************************************************************)
+
+function VideoForWindowsVersion: DWORD; pascal;
+
+(****************************************************************************
+ *
+ *  call these to start stop using VfW from your app.
+ *
+ ***************************************************************************)
+                                {
+function InitVFW: LONG; stdcall;
+function TermVFW: LONG; stdcall;  }
+
+(****************************************************************************/
+/*                                                                          */
+/*        Macros                                                            */
+/*                                                                          */
+/*  should we define this??                                                 */
+/*                                                                          */
+/****************************************************************************)
+
+function MKFOURCC(ch0, ch1, ch2, ch3: AnsiChar): FOURCC;
+
+(****************************************************************************
+ *
+ *  COMPMAN - Installable Compression Manager.
+ *
+ ****************************************************************************)
+
+const
+  ICVERSION                   = $0104 ;
+
+type
+  HIC                         = THandle;  // Handle to an Installable Compressor
+
+//
+// this code in biCompression means the DIB must be accesed via
+// 48 bit pointers! using *ONLY* the selector given.
+//
+const
+  BI_1632                     = $32333631;    // '1632'
+
+function mmioFOURCC(ch0, ch1, ch2, ch3: AnsiChar): FOURCC;
+
+type
+  TWOCC                       = word;
+
+function aviTWOCC(ch0, ch1: AnsiChar): TWOCC;
+
+const
+  ICTYPE_VIDEO                = $63646976;  {vidc}
+  ICTYPE_AUDIO                = $63647561;  {audc}
+
+const
+  ICERR_OK                    = 0 ;
+  ICERR_DONTDRAW              = 1 ;
+  ICERR_NEWPALETTE            = 2 ;
+  ICERR_GOTOKEYFRAME          = 3 ;
+  ICERR_STOPDRAWING           = 4 ;
+
+  ICERR_UNSUPPORTED           = -1 ;
+  ICERR_BADFORMAT             = -2 ;
+  ICERR_MEMORY                = -3 ;
+  ICERR_INTERNAL              = -4 ;
+  ICERR_BADFLAGS              = -5 ;
+  ICERR_BADPARAM              = -6 ;
+  ICERR_BADSIZE               = -7 ;
+  ICERR_BADHANDLE             = -8 ;
+  ICERR_CANTUPDATE            = -9 ;
+  ICERR_ABORT                 = -10 ;
+  ICERR_ERROR                 = -100 ;
+  ICERR_BADBITDEPTH           = -200 ;
+  ICERR_BADIMAGESIZE          = -201 ;
+
+  ICERR_CUSTOM                = -400 ;    // errors less than ICERR_CUSTOM...
+
+{-- Values for dwFlags of ICOpen() -------------------------------------------}
+
+  ICMODE_COMPRESS             = 1 ;
+  ICMODE_DECOMPRESS           = 2 ;
+  ICMODE_FASTDECOMPRESS       = 3 ;
+  ICMODE_QUERY                = 4 ;
+  ICMODE_FASTCOMPRESS         = 5 ;
+  ICMODE_DRAW                 = 8 ;
+
+{-- Flags for AVI file index -------------------------------------------------}
+
+  AVIIF_LIST                  = $00000001 ;
+  AVIIF_TWOCC                 = $00000002 ;
+  AVIIF_KEYFRAME              = $00000010 ;
+
+{-- quality flags ------------------------------------------------------------}
+
+  ICQUALITY_LOW               = 0 ;
+  ICQUALITY_HIGH              = 10000 ;
+  ICQUALITY_DEFAULT           = -1 ;
+
+(************************************************************************
+************************************************************************)
+
+  ICM_USER                    = (DRV_USER+$0000) ;
+
+  ICM_RESERVED_LOW            = (DRV_USER+$1000) ;
+  ICM_RESERVED_HIGH           = (DRV_USER+$2000) ;
+  ICM_RESERVED                = ICM_RESERVED_LOW ;
+
+(************************************************************************
+
+    messages.
+
+************************************************************************)
+
+  ICM_GETSTATE                = (ICM_RESERVED+0) ;    // Get compressor state
+  ICM_SETSTATE                = (ICM_RESERVED+1) ;    // Set compressor state
+  ICM_GETINFO                 = (ICM_RESERVED+2) ;    // Query info about the compressor
+
+  ICM_CONFIGURE               = (ICM_RESERVED+10);    // show the configure dialog
+  ICM_ABOUT                   = (ICM_RESERVED+11);    // show the about box
+
+  ICM_GETDEFAULTQUALITY       = (ICM_RESERVED+30);    // get the default value for quality
+  ICM_GETQUALITY              = (ICM_RESERVED+31);    // get the current value for quality
+  ICM_SETQUALITY              = (ICM_RESERVED+32);    // set the default value for quality
+
+  ICM_SET                     = (ICM_RESERVED+40);    // Tell the driver something
+  ICM_GET                     = (ICM_RESERVED+41);    // Ask the driver something
+
+{-- Constants for ICM_SET: ---------------------------------------------------}
+
+  ICM_FRAMERATE               = $526D7246;  {FrmR}
+  ICM_KEYFRAMERATE            = $5279654B;  {KeyR}
+
+(************************************************************************
+
+    ICM specific messages.
+
+************************************************************************)
+
+  ICM_COMPRESS_GET_FORMAT     = (ICM_USER+4)  ;   // get compress format or size
+  ICM_COMPRESS_GET_SIZE       = (ICM_USER+5)  ;   // get output size
+  ICM_COMPRESS_QUERY          = (ICM_USER+6)  ;   // query support for compress
+  ICM_COMPRESS_BEGIN          = (ICM_USER+7)  ;   // begin a series of compress calls.
+  ICM_COMPRESS                = (ICM_USER+8)  ;   // compress a frame
+  ICM_COMPRESS_END            = (ICM_USER+9)  ;   // end of a series of compress calls.
+
+  ICM_DECOMPRESS_GET_FORMAT   = (ICM_USER+10) ;   // get decompress format or size
+  ICM_DECOMPRESS_QUERY        = (ICM_USER+11) ;   // query support for dempress
+  ICM_DECOMPRESS_BEGIN        = (ICM_USER+12) ;   // start a series of decompress calls
+  ICM_DECOMPRESS              = (ICM_USER+13) ;   // decompress a frame
+  ICM_DECOMPRESS_END          = (ICM_USER+14) ;   // end a series of decompress calls
+  ICM_DECOMPRESS_SET_PALETTE  = (ICM_USER+29) ;   // fill in the DIB color table
+  ICM_DECOMPRESS_GET_PALETTE  = (ICM_USER+30) ;   // fill in the DIB color table
+
+  ICM_DRAW_QUERY              = (ICM_USER+31) ;   // query support for dempress
+  ICM_DRAW_BEGIN              = (ICM_USER+15) ;   // start a series of draw calls
+  ICM_DRAW_GET_PALETTE        = (ICM_USER+16) ;   // get the palette needed for drawing
+  ICM_DRAW_START              = (ICM_USER+18) ;   // start decompress clock
+  ICM_DRAW_STOP               = (ICM_USER+19) ;   // stop decompress clock
+  ICM_DRAW_END                = (ICM_USER+21) ;   // end a series of draw calls
+  ICM_DRAW_GETTIME            = (ICM_USER+32) ;   // get value of decompress clock
+  ICM_DRAW                    = (ICM_USER+33) ;   // generalized "render" message
+  ICM_DRAW_WINDOW             = (ICM_USER+34) ;   // drawing window has moved or hidden
+  ICM_DRAW_SETTIME            = (ICM_USER+35) ;   // set correct value for decompress clock
+  ICM_DRAW_REALIZE            = (ICM_USER+36) ;   // realize palette for drawing
+  ICM_DRAW_FLUSH              = (ICM_USER+37) ;   // clear out buffered frames
+  ICM_DRAW_RENDERBUFFER       = (ICM_USER+38) ;   // draw undrawn things in queue
+
+  ICM_DRAW_START_PLAY         = (ICM_USER+39) ;   // start of a play
+  ICM_DRAW_STOP_PLAY          = (ICM_USER+40) ;   // end of a play
+
+  ICM_DRAW_SUGGESTFORMAT      = (ICM_USER+50) ;   // Like ICGetDisplayFormat
+  ICM_DRAW_CHANGEPALETTE      = (ICM_USER+51) ;   // for animating palette
+
+  ICM_GETBUFFERSWANTED        = (ICM_USER+41) ;   // ask about prebuffering
+
+  ICM_GETDEFAULTKEYFRAMERATE  = (ICM_USER+42) ;   // get the default value for key frames
+
+  ICM_DECOMPRESSEX_BEGIN      = (ICM_USER+60) ;   // start a series of decompress calls
+  ICM_DECOMPRESSEX_QUERY      = (ICM_USER+61) ;   // start a series of decompress calls
+  ICM_DECOMPRESSEX            = (ICM_USER+62) ;   // decompress a frame
+  ICM_DECOMPRESSEX_END        = (ICM_USER+63) ;   // end a series of decompress calls
+
+  ICM_COMPRESS_FRAMES_INFO    = (ICM_USER+70) ;   // tell about compress to come
+  ICM_SET_STATUS_PROC         = (ICM_USER+72) ;   // set status callback
+
+(************************************************************************
+************************************************************************)
+
+type
+  PICOPEN = ^TICOPEN;
+  TICOPEN = packed record
+    dwSize                  : DWORD   ; // sizeof(ICOPEN)
+    fccType                 : DWORD   ; // 'vidc'
+    fccHandler              : DWORD   ; //
+    dwVersion               : DWORD   ; // version of compman opening you
+    dwFlags                 : DWORD   ; // LOWORD is type specific
+    dwError                 : DWORD   ; // error return.
+    pV1Reserved             : PVOID   ; // Reserved
+    pV2Reserved             : PVOID   ; // Reserved
+    dnDevNode               : DWORD   ; // Devnode for PnP devices
+  end;
+
+(************************************************************************
+************************************************************************)
+
+  PICINFO = ^TICINFO;
+  TICINFO = packed record
+    dwSize                  : DWORD;    // sizeof(ICINFO)
+    fccType                 : DWORD;    // compressor type     'vidc' 'audc'
+    fccHandler              : DWORD;    // compressor sub-type 'rle ' 'jpeg' 'pcm '
+    dwFlags                 : DWORD;    // flags LOWORD is type specific
+    dwVersion               : DWORD;    // version of the driver
+    dwVersionICM            : DWORD;    // version of the ICM used
+    //
+    // under Win32, the driver always returns UNICODE strings.
+    //
+    szName                  : array[0..15] of WChar  ; // short name
+    szDescription           : array[0..127] of WChar ; // DWORD name
+    szDriver                : array[0..127] of WChar ; // driver that contains compressor
+  end;
+
+{-- Flags for the <dwFlags> field of the <ICINFO> structure. ------------}
+
+const
+  VIDCF_QUALITY               = $0001 ;  // supports quality
+  VIDCF_CRUNCH                = $0002 ;  // supports crunching to a frame size
+  VIDCF_TEMPORAL              = $0004 ;  // supports inter-frame compress
+  VIDCF_COMPRESSFRAMES        = $0008 ;  // wants the compress all frames message
+  VIDCF_DRAW                  = $0010 ;  // supports drawing
+  VIDCF_FASTTEMPORALC         = $0020 ;  // does not need prev frame on compress
+  VIDCF_FASTTEMPORALD         = $0080 ;  // does not need prev frame on decompress
+  //VIDCF_QUALITYTIME         = $0040 ;  // supports temporal quality
+
+  //VIDCF_FASTTEMPORAL        = (VIDCF_FASTTEMPORALC or VIDCF_FASTTEMPORALD)
+
+(************************************************************************
+************************************************************************)
+
+  ICCOMPRESS_KEYFRAME         = $00000001;
+
+type
+  PICCOMPRESS = ^TICCOMPRESS;
+  TICCOMPRESS = packed record
+    dwFlags                 : DWORD;                // flags
+
+    lpbiOutput              : PBITMAPINFOHEADER ;   // output format
+    lpOutput                : PVOID ;               // output data
+
+    lpbiInput               : PBITMAPINFOHEADER ;   // format of frame to compress
+    lpInput                 : PVOID ;               // frame data to compress
+
+    lpckid                  : PDWORD ;              // ckid for data in AVI file
+    lpdwFlags               : PDWORD;               // flags in the AVI index.
+    lFrameNum               : LONG ;               // frame number of seq.
+    dwFrameSize             : DWORD ;               // reqested size in bytes. (if non zero)
+
+    dwQuality               : DWORD ;               // quality
+
+    // these are new fields
+
+    lpbiPrev                : PBITMAPINFOHEADER ;   // format of previous frame
+    lpPrev                  : PVOID ;               // previous frame
+  end;
+
+(************************************************************************
+************************************************************************)
+
+const
+  ICCOMPRESSFRAMES_PADDING    = $00000001 ;
+
+type
+  TICCompressProc    = function(lInputOutput: LPARAM; lFrame: DWORD; lpBits: PVOID; len: LONG): LONG; stdcall;
+
+  PICCOMPRESSFRAMES  = ^TICCOMPRESSFRAMES;
+  TICCOMPRESSFRAMES  = packed record
+    dwFlags                 : DWORD ;               // flags
+
+    lpbiOutput              : PBITMAPINFOHEADER ;   // output format
+    lOutput                 : LPARAM ;              // output identifier
+
+    lpbiInput               : PBITMAPINFOHEADER ;   // format of frame to compress
+    lInput                  : LPARAM ;              // input identifier
+
+    lStartFrame             : LONG ;                // start frame
+    lFrameCount             : LONG ;                // # of frames
+
+    lQuality                : LONG ;                // quality
+    lDataRate               : LONG ;                // data rate
+    lKeyRate                : LONG ;                // key frame rate
+
+    dwRate                  : DWORD ;               // frame rate, as always
+    dwScale                 : DWORD ;
+
+    dwOverheadPerFrame      : DWORD ;
+    dwReserved2             : DWORD ;
+
+    GetData                 : TICCompressProc;
+    PutData                 : TICCompressProc;
+  end;
+
+{-- Messages for Status callback ---------------------------------------------}
+
+const
+    ICSTATUS_START              = 0 ;
+    ICSTATUS_STATUS             = 1 ;   // l = % done
+    ICSTATUS_END                = 2 ;
+    ICSTATUS_ERROR              = 3 ;   // l = error string (LPSTR)
+    ICSTATUS_YIELD              = 4 ;
+
+type
+  // return nonzero means abort operation in progress
+  TICStatusProc    = function(lParam: LPARAM; message: UINT; l: LONG): LONG; stdcall;
+
+  PICSETSTATUSPROC = ^TICSETSTATUSPROC;
+  TICSETSTATUSPROC = packed record
+    dwFlags                 : DWORD ;
+    lParam                  : LPARAM ;
+    Status                  : TICStatusProc;
+  end;
+
+(************************************************************************
+************************************************************************)
+
+const
+    ICDECOMPRESS_HURRYUP        = $80000000 ;   // don't draw just buffer (hurry up!)
+    ICDECOMPRESS_UPDATE         = $40000000 ;   // don't draw just update screen
+    ICDECOMPRESS_PREROLL        = $20000000 ;   // this frame is before real start
+    ICDECOMPRESS_NULLFRAME      = $10000000 ;   // repeat last frame
+    ICDECOMPRESS_NOTKEYFRAME    = $08000000 ;   // this frame is not a key frame
+
+type
+  PICDECOMPRESS = ^TICDECOMPRESS;
+  TICDECOMPRESS = packed record
+    dwFlags                 : DWORD ;               // flags (from AVI index...)
+    lpbiInput               : PBITMAPINFOHEADER ;   // BITMAPINFO of compressed data
+                                                        // biSizeImage has the chunk size
+    lpInput                 : PVOID ;               // compressed data
+    lpbiOutput              : PBITMAPINFOHEADER ;   // DIB to decompress to
+    lpOutput                : PVOID ;
+    ckid                    : DWORD ;               // ckid from AVI file
+  end;
+
+  PICDECOMPRESSEX = ^TICDECOMPRESSEX;
+  TICDECOMPRESSEX = packed record
+
+    //
+    // same as ICM_DECOMPRESS
+    //
+
+    dwFlags                 : DWORD;
+    lpbiSrc                 : PBITMAPINFOHEADER;    // BITMAPINFO of compressed data
+    lpSrc                   : PVOID;                // compressed data
+    lpbiDst                 : PBITMAPINFOHEADER;    // DIB to decompress to
+    lpDst                   : PVOID;                // output data
+
+    //
+    // new for ICM_DECOMPRESSEX
+    //
+
+    xDst                    : int; // destination rectangle
+    yDst                    : int;
+    dxDst                   : int;
+    dyDst                   : int;
+
+    xSrc                    : int; // source rectangle
+    ySrc                    : int;
+    dxSrc                   : int;
+    dySrc                   : int;
+  end;
+
+(************************************************************************
+************************************************************************)
+
+const
+    ICDRAW_QUERY                = $00000001 ; // test for support
+    ICDRAW_FULLSCREEN           = $00000002 ; // draw to full screen
+    ICDRAW_HDC                  = $00000004 ; // draw to a HDC/HWND
+    ICDRAW_ANIMATE              = $00000008 ;   // expect palette animation
+    ICDRAW_CONTINUE             = $00000010 ;   // draw is a continuation of previous draw
+    ICDRAW_MEMORYDC             = $00000020 ;   // DC is offscreen, by the way
+    ICDRAW_UPDATING             = $00000040 ;   // We're updating, as opposed to playing
+    ICDRAW_RENDER               = $00000080 ; // used to render data not draw it
+    ICDRAW_BUFFER               = $00000100 ; // please buffer this data offscreen, we will need to update it
+
+type
+  PICDRAWBEGIN = ^TICDRAWBEGIN;
+  TICDRAWBEGIN = packed record
+    dwFlags                 : DWORD ;       // flags
+
+    hpal                    : HPALETTE ;    // palette to draw with
+    hwnd                    : HWND ;        // window to draw to
+    hdc                     : HDC ;         // HDC to draw to
+
+    xDst                    : int ;         // destination rectangle
+    yDst                    : int ;
+    dxDst                   : int ;
+    dyDst                   : int ;
+
+    lpbi                    : PBITMAPINFOHEADER ;
+                                                // format of frame to draw
+
+    xSrc                    : int ;         // source rectangle
+    ySrc                    : int ;
+    dxSrc                   : int ;
+    dySrc                   : int ;
+
+    dwRate                  : DWORD ;       // frames/second = (dwRate/dwScale)
+    dwScale                 : DWORD ;
+  end;
+
+(************************************************************************
+************************************************************************)
+
+const
+    ICDRAW_HURRYUP              = $80000000 ;   // don't draw just buffer (hurry up!)
+    ICDRAW_UPDATE               = $40000000 ;   // don't draw just update screen
+    ICDRAW_PREROLL              = $20000000 ;   // this frame is before real start
+    ICDRAW_NULLFRAME            = $10000000 ;   // repeat last frame
+    ICDRAW_NOTKEYFRAME          = $08000000 ;   // this frame is not a key frame
+
+type
+    PICDRAW                     = ^TICDRAW;
+    TICDRAW                     = packed record
+        dwFlags                 : DWORD ;   // flags
+        lpFormat                : PVOID ;   // format of frame to decompress
+        lpData                  : PVOID ;   // frame data to decompress
+        cbData                  : DWORD ;
+        lTime                   : LONG  ;   // time in drawbegin units (see dwRate and dwScale)
+    end;
+
+    PICDRAWSUGGEST              = ^TICDRAWSUGGEST;
+    TICDRAWSUGGEST              = packed record
+        lpbiIn                  : PBITMAPINFOHEADER ;   // format to be drawn
+        lpbiSuggest             : PBITMAPINFOHEADER ;   // location for suggested format (or NULL to get size)
+        dxSrc                   : int ;                 // source extent or 0
+        dySrc                   : int ;
+        dxDst                   : int ;                 // dest extent or 0
+        dyDst                   : int ;
+        hicDecompressor         : HIC ;                 // decompressor you can talk to
+    end;
+
+(************************************************************************
+************************************************************************)
+
+    PICPALETTE                  = ^TICPALETTE;
+    TICPALETTE                  = packed record
+        dwFlags                 : DWORD ;           // flags (from AVI index...)
+        iStart                  : int ;             // first palette to change
+        iLen                    : int ;             // count of entries to change.
+        lppe                    : PPALETTEENTRY ;   // palette
+    end;
+
+(************************************************************************
+
+    ICM function declarations
+
+************************************************************************)
+
+function    ICInfo(fccType, fccHandler: DWORD; lpicinfo: PICINFO) : BOOL ; stdcall ;
+function    ICInstall(fccType, fccHandler: DWORD; lParam: LPARAM; szDesc: LPSTR; wFlags: UINT) : BOOL ; stdcall ;
+function    ICRemove(fccType, fccHandler: DWORD; wFlags: UINT) : BOOL ; stdcall ;
+function    ICGetInfo(hic: HIC; picinfo: PICINFO; cb: DWORD) : DWORD ; stdcall ;
+
+function    ICOpen(fccType, fccHandler: DWORD; wMode: UINT) : HIC ; stdcall ;
+function    ICOpenFunction(fccType, fccHandler: DWORD; wMode: UINT; lpfnHandler: TFarProc) : HIC ; stdcall ;
+function    ICClose(hic: HIC) : DWORD; stdcall ;
+
+function    ICSendMessage(hic: HIC; msg: UINT; dw1, dw2: DWORD) : DWORD ; stdcall ;
+
+{-- Values for wFlags of ICInstall -------------------------------------------}
+
+const
+    ICINSTALL_UNICODE           = $8000 ;
+
+    ICINSTALL_FUNCTION          = $0001 ; // lParam is a DriverProc (function ptr)
+    ICINSTALL_DRIVER            = $0002 ; // lParam is a driver name (string)
+    ICINSTALL_HDRV              = $0004 ; // lParam is a HDRVR (driver handle)
+
+    ICINSTALL_DRIVERW           = $8002 ; // lParam is a unicode driver name
+
+{-- Query macros -------------------------------------------------------------}
+
+    ICMF_CONFIGURE_QUERY        = $00000001 ;
+    ICMF_ABOUT_QUERY            = $00000001 ;
+
+function    ICQueryAbout(hic: HIC): BOOL;
+function    ICAbout(hic: HIC; hwnd: HWND): DWORD;
+function    ICQueryConfigure(hic: HIC): BOOL;
+function    ICConfigure(hic: HIC; hwnd: HWND): DWORD;
+
+{-- Get/Set state macros -----------------------------------------------------}
+
+function    ICGetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
+function    ICSetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
+function    ICGetStateSize(hic: HIC): DWORD;
+
+{-- Get value macros ---------------------------------------------------------}
+
+function    ICGetDefaultQuality(hic: HIC): DWORD;
+function    ICGetDefaultKeyFrameRate(hic: HIC): DWORD;
+
+{-- Draw window macro --------------------------------------------------------}
+
+function    ICDrawWindow(hic: HIC; prc: PRECT): DWORD;
+
+(************************************************************************
+
+    compression functions
+
+************************************************************************/
+/*
+ *  ICCompress()
+ *
+ *  compress a single frame
+ *
+ *)
+function ICCompress(
+    hic             : HIC;
+    dwFlags         : DWORD;                // flags
+    lpbiOutput      : PBITMAPINFOHEADER;    // output format
+    lpData          : PVOID;                // output data
+    lpbiInput       : PBITMAPINFOHEADER;    // format of frame to compress
+    lpBits          : PVOID;                // frame data to compress
+    lpckid          : PDWORD;               // ckid for data in AVI file
+    lpdwFlags       : PDWORD;               // flags in the AVI index.
+    lFrameNum       : DWORD;                 // frame number of seq.
+    dwFrameSize     : DWORD;                // reqested size in bytes. (if non zero)
+    dwQuality       : DWORD;                // quality within one frame
+    lpbiPrev        : PBITMAPINFOHEADER;    // format of previous frame
+    lpPrev          : PVOID                 // previous frame
+    ): DWORD; cdecl;
+
+(*
+ *  ICCompressBegin()
+ *
+ *  start compression from a source format (lpbiInput) to a dest
+ *  format (lpbiOuput) is supported.
+ *
+ *)
+
+function    ICCompressBegin(hic: HIC; lpbiInput: PBITMAPINFOHEADER; lpbiOutput: PBITMAPINFOHEADER): DWORD;
+
+(*
+ *  ICCompressQuery()
+ *
+ *  determines if compression from a source format (lpbiInput) to a dest
+ *  format (lpbiOuput) is supported.
+ *
+ *)
+
+function    ICCompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+
+(*
+ *  ICCompressGetFormat()
+ *
+ *  get the output format, (format of compressed data)
+ *  if lpbiOutput is NULL return the size in bytes needed for format.
+ *
+ *)
+
+function    ICCompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+function    ICCompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
+
+(*
+ *  ICCompressSize()
+ *
+ *  return the maximal size of a compressed frame
+ *
+ *)
+
+function    ICCompressGetSize(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+function    ICCompressEnd(hic: HIC): DWORD;
+
+(************************************************************************
+
+    decompression functions
+
+************************************************************************)
+
+(*
+ *  ICDecompress()
+ *
+ *  decompress a single frame
+ *
+ *)
+
+function    ICDecompress(
+    hic             : HIC;
+    dwFlags         : DWORD;                // flags (from AVI index...)
+    lpbiFormat      : PBITMAPINFOHEADER;    // BITMAPINFO of compressed data
+                                            // biSizeImage has the chunk size
+    lpData          : PVOID;                // data
+    lpbi            : PBITMAPINFOHEADER;    // DIB to decompress to
+    lpBits          : PVOID
+    ): DWORD; cdecl;
+
+(*
+ *  ICDecompressBegin()
+ *
+ *  start compression from a source format (lpbiInput) to a dest
+ *  format (lpbiOutput) is supported.
+ *
+ *)
+
+function    ICDecompressBegin(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+
+(*
+ *  ICDecompressQuery()
+ *
+ *  determines if compression from a source format (lpbiInput) to a dest
+ *  format (lpbiOutput) is supported.
+ *
+ *)
+
+function    ICDecompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+
+(*
+ *  ICDecompressGetFormat()
+ *
+ *  get the output format, (format of un-compressed data)
+ *  if lpbiOutput is NULL return the size in bytes needed for format.
+ *
+ *)
+
+function    ICDecompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+function    ICDecompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
+
+(*
+ *  ICDecompressGetPalette()
+ *
+ *  get the output palette
+ *
+ *)
+
+function    ICDecompressGetPalette(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+function    ICDecompressSetPalette(hic: HIC; lpbiPalette: PBITMAPINFOHEADER): DWORD;
+
+function    ICDecompressEnd(hic: HIC): DWORD;
+
+(************************************************************************
+
+    decompression (ex) functions
+
+************************************************************************)
+
+//
+// on Win16 these functions are macros that call ICMessage. ICMessage will
+// not work on NT. rather than add new entrypoints we have given
+// them as static inline functions
+//
+
+(*
+ *  ICDecompressEx()
+ *
+ *  decompress a single frame
+ *
+ *)
+
+function    ICDecompressEx(
+    hic         : HIC;
+    dwFlags     : DWORD;
+    lpbiSrc     : PBITMAPINFOHEADER;
+    lpSrc       : PVOID;
+    xSrc        : int;
+    ySrc        : int;
+    dxSrc       : int;
+    dySrc       : int;
+    lpbiDst     : PBITMAPINFOHEADER;
+    lpDst       : PVOID;
+    xDst        : int;
+    yDst        : int;
+    dxDst       : int;
+    dyDst       : int
+    ): DWORD; stdcall;
+
+(*
+ *  ICDecompressExBegin()
+ *
+ *  start compression from a source format (lpbiInput) to a dest
+ *  format (lpbiOutput) is supported.
+ *
+ *)
+
+function    ICDecompressExBegin(
+    hic         : HIC;
+    dwFlags     : DWORD;
+    lpbiSrc     : PBITMAPINFOHEADER;
+    lpSrc       : PVOID;
+    xSrc        : int;
+    ySrc        : int;
+    dxSrc       : int;
+    dySrc       : int;
+    lpbiDst     : PBITMAPINFOHEADER;
+    lpDst       : PVOID;
+    xDst        : int;
+    yDst        : int;
+    dxDst       : int;
+    dyDst       : int
+    ): DWORD; stdcall;
+
+(*
+ *  ICDecompressExQuery()
+ *
+ *)
+
+function    ICDecompressExQuery(
+    hic         : HIC;
+    dwFlags     : DWORD;
+    lpbiSrc     : PBITMAPINFOHEADER;
+    lpSrc       : PVOID;
+    xSrc        : int;
+    ySrc        : int;
+    dxSrc       : int;
+    dySrc       : int;
+    lpbiDst     : PBITMAPINFOHEADER;
+    lpDst       : PVOID;
+    xDst        : int;
+    yDst        : int;
+    dxDst       : int;
+    dyDst       : int
+    ): DWORD; stdcall;
+
+function ICDecompressExEnd(hic: HIC): DWORD;
+
+(************************************************************************
+
+    drawing functions
+
+************************************************************************)
+
+(*
+ *  ICDrawBegin()
+ *
+ *  start decompressing data with format (lpbiInput) directly to the screen
+ *
+ *  return zero if the decompressor supports drawing.
+ *
+ *)
+
+function    ICDrawBegin(
+    hic         : HIC;
+    dwFlags     : DWORD;                // flags
+    hpal        : HPALETTE;             // palette to draw with
+    hwnd        : HWND;                 // window to draw to
+    hdc         : HDC;                  // HDC to draw to
+    xDst        : int;                  // destination rectangle
+    yDst        : int;
+    dxDst       : int;
+    dyDst       : int;
+    lpbi        : PBITMAPINFOHEADER;    // format of frame to draw
+    xSrc        : int;                  // source rectangle
+    ySrc        : int;
+    dxSrc       : int;
+    dySrc       : int;
+    dwRate      : DWORD;                // frames/second = (dwRate/dwScale)
+    dwScale     : DWORD
+    ): DWORD; cdecl;
+
+(*
+ *  ICDraw()
+ *
+ *  decompress data directly to the screen
+ *
+ *)
+
+function    ICDraw(
+    hic         : HIC;
+    dwFlags     : DWORD;                // flags
+    lpFormat    : PVOID;                // format of frame to decompress
+    lpData      : PVOID;                // frame data to decompress
+    cbData      : DWORD;                // size of data
+    lTime       : DWORD                  // time to draw this frame
+    ): DWORD; cdecl;
+
+// ICMessage is not supported on Win32, so provide a static inline function
+// to do the same job
+function    ICDrawSuggestFormat(
+    hic         : HIC;
+    lpbiIn      : PBITMAPINFOHEADER;
+    lpbiOut     : PBITMAPINFOHEADER;
+    dxSrc       : int;
+    dySrc       : int;
+    dxDst       : int;
+    dyDst       : int;
+    hicDecomp   : HIC
+    ): DWORD; stdcall;
+
+(*
+ *  ICDrawQuery()
+ *
+ *  determines if the compressor is willing to render the specified format.
+ *
+ *)
+
+function    ICDrawQuery(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
+function    ICDrawChangePalette(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
+function    ICGetBuffersWanted(hic: HIC; lpdwBuffers: PDWORD): DWORD;
+function    ICDrawEnd(hic: HIC): DWORD;
+function    ICDrawStart(hic: HIC): DWORD;
+function    ICDrawStartPlay(hic: HIC; lFrom, lTo: DWORD): DWORD;
+function    ICDrawStop(hic: HIC): DWORD;
+function    ICDrawStopPlay(hic: HIC): DWORD;
+function    ICDrawGetTime(hic: HIC; lplTime: PDWORD): DWORD;
+function    ICDrawSetTime(hic: HIC; lTime: DWORD): DWORD;
+function    ICDrawRealize(hic: HIC; hdc: HDC; fBackground: BOOL): DWORD;
+function    ICDrawFlush(hic: HIC): DWORD;
+function    ICDrawRenderBuffer(hic: HIC): DWORD;
+
+(************************************************************************
+
+    Status callback functions
+
+************************************************************************/
+
+/*
+ *  ICSetStatusProc()
+ *
+ *  Set the status callback function
+ *
+ *)
+
+
+// ICMessage is not supported on NT
+function    ICSetStatusProc(
+    hic         : HIC;
+    dwFlags     : DWORD;
+    lParam      : DWORD;
+    fpfnStatus  : TICStatusProc
+    ): DWORD; stdcall;
+
+(************************************************************************
+
+helper routines for DrawDib and MCIAVI...
+
+************************************************************************)
+
+function    ICLocate(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER; wFlags: WORD): HIC; stdcall;
+function    ICGetDisplayFormat(hic: HIC; lpbiIn, lpbiOut: PBITMAPINFOHEADER; BitDepth: int; dx, dy: int): HIC; stdcall;
+
+function    ICDecompressOpen(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER): HIC;
+function    ICDrawOpen(fccType, fccHandler: DWORD; lpbiIn: PBITMAPINFOHEADER): HIC;
+
+(************************************************************************
+Higher level functions
+************************************************************************)
+
+function    ICImageCompress(
+    hic         : HIC;                  // compressor to use
+    uiFlags     : UINT;                 // flags (none yet)
+    lpbiIn      : PBITMAPINFO;          // format to compress from
+    lpBits      : PVOID;                // data to compress
+    lpbiOut     : PBITMAPINFO;          // compress to this (NULL ==> default)
+    lQuality    : LONG;                 // quality to use
+    plSize      : PDWORD                 // compress to this size (0=whatever)
+    ): THANDLE; stdcall;
+
+function    ICImageDecompress(
+    hic         : HIC;                  // compressor to use
+    uiFlags     : UINT;                 // flags (none yet)
+    lpbiIn      : PBITMAPINFO;          // format to decompress from
+    lpBits      : PVOID;                // data to decompress
+    lpbiOut     : PBITMAPINFO           // decompress to this (NULL ==> default)
+    ): THANDLE; stdcall;
+
+{-- TCompVars ----------------------------------------------------------------}
+
+//
+// Structure used by ICSeqCompressFrame and ICCompressorChoose routines
+// Make sure this matches the autodoc in icm.c!
+//
+
+type
+  PCOMPVARS       = ^TCOMPVARS;
+  TCOMPVARS       = packed record
+        cbSize      : DWORD;            // set to sizeof(COMPVARS) before
+                                        // calling ICCompressorChoose
+        dwFlags     : DWORD;            // see below...
+        hic         : HIC;              // HIC of chosen compressor
+        fccType     : DWORD;            // basically ICTYPE_VIDEO
+        fccHandler  : DWORD;            // handler of chosen compressor or
+                                        // "" or "DIB "
+        lpbiIn      : PBITMAPINFO;      // input format
+        lpbiOut     : PBITMAPINFO;      // output format - will compress to this
+        lpBitsOut   : PVOID;
+        lpBitsPrev  : PVOID;
+        lFrame      : LONG;
+        lKey        : LONG;             // key frames how often?
+        lDataRate   : LONG;             // desired data rate KB/Sec
+        lQ          : LONG;             // desired quality
+        lKeyCount   : LONG;
+        lpState     : PVOID;            // state of compressor
+        cbState     : LONG;             // size of the state
+    end;
+
+// FLAGS for dwFlags element of COMPVARS structure:
+// set this flag if you initialize COMPVARS before calling ICCompressorChoose
+
+const
+    ICMF_COMPVARS_VALID         = $00000001;    // COMPVARS contains valid data
+
+//
+//  allows user to choose compressor, quality etc...
+//
+function    ICCompressorChoose(
+    hwnd        : HWND;                     // parent window for dialog
+    uiFlags     : UINT;                     // flags
+    pvIn        : PVOID;                    // input format (optional)
+    lpData      : PVOID;                    // input data (optional)
+    pc          : PCOMPVARS;                // data about the compressor/dlg
+    lpszTitle   : LPSTR                     // dialog title (optional)
+    ): BOOL; stdcall;
+
+// defines for uiFlags
+
+const
+    ICMF_CHOOSE_KEYFRAME        = $0001;    // show KeyFrame Every box
+    ICMF_CHOOSE_DATARATE        = $0002;    // show DataRate box
+    ICMF_CHOOSE_PREVIEW         = $0004;    // allow expanded preview dialog
+    ICMF_CHOOSE_ALLCOMPRESSORS  = $0008;    // don't only show those that
+                                            // can handle the input format
+                                            // or input data
+
+function    ICSeqCompressFrameStart(pc: PCOMPVARS; lpbiIn: PBITMAPINFO): BOOL; stdcall;
+procedure   ICSeqCompressFrameEnd(pc: PCOMPVARS); stdcall;
+
+function    ICSeqCompressFrame(
+    pc          : PCOMPVARS;                // set by ICCompressorChoose
+    uiFlags     : UINT;                     // flags
+    lpBits      : PVOID;                    // input DIB bits
+    pfKey       : PBOOL;                    // did it end up being a key frame?
+    plSize      : PDWORD                     // size to compress to/of returned image
+    ): PVOID; stdcall;
+
+procedure   ICCompressorFree(pc: PCOMPVARS); stdcall;
+
+
+(**************************************************************************
+ *
+ *  DRAWDIB - Routines for drawing to the display.
+ *
+ *************************************************************************)
+
+type
+    HDRAWDIB                    = THandle;  // hdd
+
+(*********************************************************************
+
+  DrawDib Flags
+
+**********************************************************************)
+
+const
+    DDF_UPDATE                  = $0002;    // re-draw the last DIB
+    DDF_SAME_HDC                = $0004;    // HDC same as last call (all setup)
+    DDF_SAME_DRAW               = $0008;    // draw params are the same
+    DDF_DONTDRAW                = $0010;    // dont draw frame, just decompress
+    DDF_ANIMATE                 = $0020;    // allow palette animation
+    DDF_BUFFER                  = $0040;    // always buffer image
+    DDF_JUSTDRAWIT              = $0080;    // just draw it with GDI
+    DDF_FULLSCREEN              = $0100;    // use DisplayDib
+    DDF_BACKGROUNDPAL           = $0200;    // Realize palette in background
+    DDF_NOTKEYFRAME             = $0400;    // this is a partial frame update, hint
+    DDF_HURRYUP                 = $0800;    // hurry up please!
+    DDF_HALFTONE                = $1000;    // always halftone
+
+    DDF_PREROLL                 = DDF_DONTDRAW; // Builing up a non-keyframe
+    DDF_SAME_DIB                = DDF_SAME_DRAW;
+    DDF_SAME_SIZE               = DDF_SAME_DRAW;
+
+(*********************************************************************
+
+    DrawDib functions
+
+*********************************************************************)
+
+{-- DrawDibOpen() ------------------------------------------------------------}
+
+function    DrawDibOpen: HDRAWDIB; stdcall;
+
+{-- DrawDibClose() -----------------------------------------------------------}
+
+function    DrawDibClose(hdd: HDRAWDIB): BOOL; stdcall;
+
+{-- DrawDibGetBuffer() -------------------------------------------------------}
+
+function    DrawDibGetBuffer(hdd: HDRAWDIB; lpbi: PBITMAPINFOHEADER; dwSize: DWORD; dwFlags: DWORD): PVOID; stdcall;
+
+{-- DrawDibGetPalette() - get the palette used for drawing DIBs --------------}
+
+function    DrawDibGetPalette(hdd: HDRAWDIB): HPALETTE; stdcall;
+
+{-- DrawDibSetPalette() - set the palette used for drawing DIBs --------------}
+
+function    DrawDibSetPalette(hdd: HDRAWDIB; hpal: HPALETTE): BOOL; stdcall;
+
+{-- DrawDibChangePalette() ---------------------------------------------------}
+
+function    DrawDibChangePalette(hdd: HDRAWDIB; iStart, iLen: int; lppe: PPALETTEENTRY): BOOL; stdcall;
+
+{-- DrawDibRealize() - realize the palette in a HDD --------------------------}
+
+function    DrawDibRealize(hdd: HDRAWDIB; hdc: HDC; fBackground: BOOL): UINT; stdcall;
+
+{-- DrawDibStart() - start of streaming playback -----------------------------}
+
+function    DrawDibStart(hdd: HDRAWDIB; rate: DWORD): BOOL; stdcall;
+
+{-- DrawDibStop() - start of streaming playback ------------------------------}
+
+function    DrawDibStop(hdd: HDRAWDIB): BOOL; stdcall;
+
+{-- DrawDibBegin() - prepare to draw -----------------------------------------}
+
+function    DrawDibBegin(
+    hdd         : HDRAWDIB;
+    hdc         : HDC;
+    dxDst       : int;
+    dyDst       : int;
+    lpbi        : PBITMAPINFOHEADER;
+    dxSrc       : int;
+    dySrc       : int;
+    wFlags      : UINT
+    ): BOOL; stdcall;
+
+{-- DrawDibDraw() - actually draw a DIB to the screen ------------------------}
+
+function    DrawDibDraw(
+    hdd         : HDRAWDIB;
+    hdc         : HDC;
+    xDst        : int;
+    yDst        : int;
+    dxDst       : int;
+    dyDst       : int;
+    lpbi        : PBITMAPINFOHEADER;
+    lpBits      : PVOID;
+    xSrc        : int;
+    ySrc        : int;
+    dxSrc       : int;
+    dySrc       : int;
+    wFlags      : UINT
+    ): BOOL; stdcall;
+
+{-- DrawDibUpdate() - redraw last image (may only be valid with DDF_BUFFER) --}
+
+function    DrawDibUpdate(hdd: HDRAWDIB; hdc: HDC; x, y: int): BOOL;
+
+{-- DrawDibEnd() -------------------------------------------------------------}
+
+function    DrawDibEnd(hdd: HDRAWDIB): BOOL; stdcall;
+
+{-- DrawDibTime() - for debugging purposes only ------------------------------}
+
+type
+    PDRAWDIBTIME        = ^TDRAWDIBTIME;
+    TDRAWDIBTIME        = packed record
+        timeCount       : LONG;
+        timeDraw        : LONG;
+        timeDecompress  : LONG;
+        timeDither      : LONG;
+        timeStretch     : LONG;
+        timeBlt         : LONG;
+        timeSetDIBits   : LONG;
+    end;
+
+function    DrawDibTime(hdd: HDRAWDIB; lpddtime: PDRAWDIBTIME): BOOL; stdcall;
+
+{-- Display profiling --------------------------------------------------------}
+
+const
+    PD_CAN_DRAW_DIB             = $0001;    // if you can draw at all
+    PD_CAN_STRETCHDIB           = $0002;    // basicly RC_STRETCHDIB
+    PD_STRETCHDIB_1_1_OK        = $0004;    // is it fast?
+    PD_STRETCHDIB_1_2_OK        = $0008;    // ...
+    PD_STRETCHDIB_1_N_OK        = $0010;    // ...
+
+function    DrawDibProfileDisplay(lpbi: PBITMAPINFOHEADER): DWORD; stdcall;
+
+(****************************************************************************
+ *
+ *  AVIFMT - AVI file format definitions
+ *
+ ****************************************************************************)
+
+//
+// The following is a short description of the AVI file format.  Please
+// see the accompanying documentation for a full explanation.
+//
+// An AVI file is the following RIFF form:
+//
+//  RIFF('AVI'
+//        LIST('hdrl'
+//          avih(<MainAVIHeader>)
+//                  LIST ('strl'
+//                      strh(<Stream header>)
+//                      strf(<Stream format>)
+//                      ... additional header data
+//            LIST('movi'
+//            { LIST('rec'
+//                    SubChunk...
+//                 )
+//                | SubChunk } ....
+//            )
+//            [ <AVIIndex> ]
+//      )
+//
+//  The main file header specifies how many streams are present.  For
+//  each one, there must be a stream header chunk and a stream format
+//  chunk, enlosed in a 'strl' LIST chunk.  The 'strf' chunk contains
+//  type-specific format information; for a video stream, this should
+//  be a BITMAPINFO structure, including palette.  For an audio stream,
+//  this should be a WAVEFORMAT (or PCMWAVEFORMAT) structure.
+//
+//  The actual data is contained in subchunks within the 'movi' LIST
+//  chunk.  The first two characters of each data chunk are the
+//  stream number with which that data is associated.
+//
+//  Some defined chunk types:
+//           Video Streams:
+//                  ##db:   RGB DIB bits
+//                  ##dc:   RLE8 compressed DIB bits
+//                  ##pc:   Palette Change
+//
+//           Audio Streams:
+//                  ##wb:   waveform audio bytes
+//
+// The grouping into LIST 'rec' chunks implies only that the contents of
+//   the chunk should be read into memory at the same time.  This
+//   grouping is used for files specifically intended to be played from
+//   CD-ROM.
+//
+// The index chunk at the end of the file should contain one entry for
+//   each data chunk in the file.
+//
+// Limitations for the current software:
+//  Only one video stream and one audio stream are allowed.
+//  The streams must start at the beginning of the file.
+//
+//
+// To register codec types please obtain a copy of the Multimedia
+// Developer Registration Kit from:
+//
+//  Microsoft Corporation
+//  Multimedia Systems Group
+//  Product Marketing
+//  One Microsoft Way
+//  Redmond, WA 98052-6399
+//
+
+{-- form types, list types and chunk types -----------------------------------}
+
+const
+    formtypeAVI                 = $20495641; // mmioFOURCC('A', 'V', 'I', ' ')
+    listtypeAVIHEADER           = $6C726468; // mmioFOURCC('h', 'd', 'r', 'l')
+    ckidAVIMAINHDR              = $68697661; // mmioFOURCC('a', 'v', 'i', 'h')
+    listtypeSTREAMHEADER        = $6C727473; // mmioFOURCC('s', 't', 'r', 'l')
+    ckidSTREAMHEADER            = $68727473; // mmioFOURCC('s', 't', 'r', 'h')
+    ckidSTREAMFORMAT            = $66727473; // mmioFOURCC('s', 't', 'r', 'f')
+    ckidSTREAMHANDLERDATA       = $64727473; // mmioFOURCC('s', 't', 'r', 'd')
+    ckidSTREAMNAME              = $6E727473; // mmioFOURCC('s', 't', 'r', 'n')
+
+    listtypeAVIMOVIE            = $69766F6D; // mmioFOURCC('m', 'o', 'v', 'i')
+    listtypeAVIRECORD           = $20636572; // mmioFOURCC('r', 'e', 'c', ' ')
+
+    ckidAVINEWINDEX             = $31786469; // mmioFOURCC('i', 'd', 'x', '1')
+
+{-- Stream types for the <fccType> field of the stream header ----------------}
+
+    streamtypeVIDEO             = $73646976; // mmioFOURCC('v', 'i', 'd', 's')
+    streamtypeAUDIO             = $73647561; // mmioFOURCC('a', 'u', 'd', 's')
+    streamtypeMIDI              = $7364696D; // mmioFOURCC('m', 'i', 'd', 's')
+    streamtypeTEXT              = $73747874; // mmioFOURCC('t', 'x', 't', 's')
+
+{-- Basic chunk types --------------------------------------------------------}
+
+    cktypeDIBbits               = $6264; // aviTWOCC('d', 'b')
+    cktypeDIBcompressed         = $6364; // aviTWOCC('d', 'c')
+    cktypePALchange             = $6370; // aviTWOCC('p', 'c')
+    cktypeWAVEbytes             = $6277; // aviTWOCC('w', 'b')
+
+{-- Chunk id to use for extra chunks for padding -----------------------------}
+
+    ckidAVIPADDING              = $4B4E554A; // mmioFOURCC('J', 'U', 'N', 'K')
+
+(*
+** Useful macros
+**
+** Warning: These are nasty macro, and MS C 6.0 compiles some of them
+** incorrectly if optimizations are on.  Ack.
+*)
+
+{-- Macro to get stream number out of a FOURCC ckid --------------------------}
+
+function    FromHex(n: BYTE): BYTE;
+function    StreamFromFOURCC(fcc: DWORD): BYTE;
+
+{-- Macro to get TWOCC chunk type out of a FOURCC ckid -----------------------}
+
+function    TWOCCFromFOURCC(fcc: DWORD): WORD;
+
+{-- Macro to make a ckid for a chunk out of a TWOCC and a stream num (0-255) -}
+
+function    ToHex(n: BYTE): BYTE;
+function    MAKEAVICKID(tcc: WORD; stream: BYTE): DWORD;
+
+{-- Main AVI file header -----------------------------------------------------}
+
+{-- flags for use in <dwFlags> in AVIFileHdr ---------------------------------}
+
+const
+    AVIF_HASINDEX               = $00000010;    // Index at end of file?
+    AVIF_MUSTUSEINDEX           = $00000020;
+    AVIF_ISINTERLEAVED          = $00000100;
+    AVIF_TRUSTCKTYPE            = $00000800;    // Use CKType to find key frames?
+    AVIF_WASCAPTUREFILE         = $00010000;
+    AVIF_COPYRIGHTED            = $00020000;
+
+{-- The AVI File Header LIST chunk should be padded to this size -------------}
+
+const
+    AVI_HEADERSIZE              = 2048;         // size of AVI header list
+
+type
+    PMainAVIHeader              = ^TMainAVIHeader;
+    TMainAVIHeader              = packed record
+        dwMicroSecPerFrame      : DWORD;        // frame display rate (or 0L)
+        dwMaxBytesPerSec        : DWORD;        // max. transfer rate
+        dwPaddingGranularity    : DWORD;        // pad to multiples of this
+                                                // size; normally 2K.
+        dwFlags                 : DWORD;        // the ever-present flags
+        dwTotalFrames           : DWORD;        // # frames in file
+        dwInitialFrames         : DWORD;
+        dwStreams               : DWORD;
+        dwSuggestedBufferSize   : DWORD;
+
+        dwWidth                 : DWORD;
+        dwHeight                : DWORD;
+
+        dwReserved              : array[0..3] of DWORD;
+    end;
+
+{-- Stream header ------------------------------------------------------------}
+
+const
+    AVISF_DISABLED              = $00000001;
+
+    AVISF_VIDEO_PALCHANGES      = $00010000;
+
+type
+    PAVIStreamHeader            = ^TAVIStreamHeader;
+    TAVIStreamHeader            = packed record
+        fccType                 : FOURCC;
+        fccHandler              : FOURCC;
+        dwFlags                 : DWORD;        // Contains AVITF_* flags
+        wPriority               : WORD;
+        wLanguage               : WORD;
+        dwInitialFrames         : DWORD;
+        dwScale                 : DWORD;
+        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
+        dwStart                 : DWORD;
+        dwLength                : DWORD;        // In units above...
+        dwSuggestedBufferSize   : DWORD;
+        dwQuality               : DWORD;
+        dwSampleSize            : DWORD;
+        rcFrame                 : TRECT;
+    end;
+
+{-- Flags for index ----------------------------------------------------------}
+
+const
+    AVIIF_NOTIME                = $00000100;    // this frame doesn't take any time
+    AVIIF_COMPUSE               = $0FFF0000;    // these bits are for compressor use
+
+type
+    PAVIINDEXENTRY              = ^TAVIINDEXENTRY;
+    TAVIINDEXENTRY              = packed record
+        ckid                    : DWORD;
+        dwFlags                 : DWORD;
+        dwChunkOffset           : DWORD;        // Position of chunk
+        dwChunkLength           : DWORD;        // Length of chunk
+    end;
+
+{-- Palette change chunk (used in video streams) -----------------------------}
+
+    PAVIPALCHANGE               = ^TAVIPALCHANGE;
+    TAVIPALCHANGE               = packed record
+        bFirstEntry             : BYTE;         // first entry to change
+        bNumEntries             : BYTE;         // # entries to change (0 if 256)
+        wFlags                  : WORD;         // Mostly to preserve alignment...
+        peNew                   : array[0..0] of TPALETTEENTRY; // New color specifications
+    end;
+
+(****************************************************************************
+ *
+ *  AVIFile - routines for reading/writing standard AVI files
+ *
+ ***************************************************************************)
+
+//
+// Ansi - Unicode thunking.
+//
+// Unicode or Ansi-only apps can call the avifile APIs.
+// any Win32 app who wants to use
+// any of the AVI COM interfaces must be UNICODE - the AVISTREAMINFO and
+// AVIFILEINFO structures used in the Info methods of these interfaces are
+// the unicode variants, and no thunking to or from ansi takes place
+// except in the AVIFILE api entrypoints.
+//
+// For Ansi/Unicode thunking: for each entrypoint or structure that
+// uses chars or strings, two versions are declared in the Win32 version,
+// ApiNameW and ApiNameA. The default name ApiName is #defined to one or
+// other of these depending on whether UNICODE is defined (during
+// compilation of the app that is including this header). The source will
+// contain ApiName and ApiNameA (with ApiName being the Win16 implementation,
+// and also #defined to ApiNameW, and ApiNameA being the thunk entrypoint).
+//
+
+// For GetFrame::SetFormat - use the best format for the display
+
+const
+    AVIGETFRAMEF_BESTDISPLAYFMT = 1;
+
+//
+// Structures used by AVIStreamInfo & AVIFileInfo.
+//
+// These are related to, but not identical to, the header chunks
+// in an AVI file.
+//
+
+{-- AVISTREAMINFO ------------------------------------------------------------}
+
+// for Unicode/Ansi thunking we need to declare three versions of this!
+
+type
+    PAVIStreamInfoW             = ^TAVIStreamInfoW;
+    TAVIStreamInfoW             = packed record
+        fccType                 : DWORD;
+        fccHandler              : DWORD;
+        dwFlags                 : DWORD;        // Contains AVITF_* flags
+        dwCaps                  : DWORD;
+        wPriority               : WORD;
+        wLanguage               : WORD;
+        dwScale                 : DWORD;
+        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
+        dwStart                 : DWORD;
+        dwLength                : DWORD;        // In units above...
+        dwInitialFrames         : DWORD;
+        dwSuggestedBufferSize   : DWORD;
+        dwQuality               : DWORD;
+        dwSampleSize            : DWORD;
+        rcFrame                 : TRECT;
+        dwEditCount             : DWORD;
+        dwFormatChangeCount     : DWORD;
+        szName                  : array[0..63] of WideChar;
+    end;
+
+    PAVIStreamInfoA             = ^TAVIStreamInfoA;
+    TAVIStreamInfoA             = packed record
+        fccType                 : DWORD;
+        fccHandler              : DWORD;
+        dwFlags                 : DWORD;        // Contains AVITF_* flags
+        dwCaps                  : DWORD;
+        wPriority               : WORD;
+        wLanguage               : WORD;
+        dwScale                 : DWORD;
+        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
+        dwStart                 : DWORD;
+        dwLength                : DWORD;        // In units above...
+        dwInitialFrames         : DWORD;
+        dwSuggestedBufferSize   : DWORD;
+        dwQuality               : DWORD;
+        dwSampleSize            : DWORD;
+        rcFrame                 : TRECT;
+        dwEditCount             : DWORD;
+        dwFormatChangeCount     : DWORD;
+        szName                  : array[0..63] of AnsiChar;
+    end;
+
+  PAVIStreamInfo = ^TAVIStreamInfo;
+{$IFDEF UNICODE}
+  TAVIStreamInfo = TAVIStreamInfoW;
+{$ELSE}
+  TAVIStreamInfo = TAVIStreamInfoA;
+{$ENDIF}
+
+const
+    AVISTREAMINFO_DISABLED      = $00000001;
+    AVISTREAMINFO_FORMATCHANGES = $00010000;
+
+{-- AVIFILEINFO --------------------------------------------------------------}
+
+type
+    PAVIFileInfoW               = ^TAVIFileInfoW;
+    TAVIFileInfoW               = packed record
+        dwMaxBytesPerSec        : DWORD;        // max. transfer rate
+        dwFlags                 : DWORD;        // the ever-present flags
+        dwCaps                  : DWORD;
+        dwStreams               : DWORD;
+        dwSuggestedBufferSize   : DWORD;
+
+        dwWidth                 : DWORD;
+        dwHeight                : DWORD;
+
+        dwScale                 : DWORD;
+        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
+        dwLength                : DWORD;
+
+        dwEditCount             : DWORD;
+
+        szFileType              : array[0..63] of WideChar;
+                                                // descriptive string for file type?
+    end;
+
+    PAVIFileInfoA               = ^TAVIFileInfoA;
+    TAVIFileInfoA               = packed record
+        dwMaxBytesPerSec        : DWORD;        // max. transfer rate
+        dwFlags                 : DWORD;        // the ever-present flags
+        dwCaps                  : DWORD;
+        dwStreams               : DWORD;
+        dwSuggestedBufferSize   : DWORD;
+
+        dwWidth                 : DWORD;
+        dwHeight                : DWORD;
+
+        dwScale                 : DWORD;
+        dwRate                  : DWORD;        // dwRate / dwScale == samples/second
+        dwLength                : DWORD;
+
+        dwEditCount             : DWORD;
+
+        szFileType              : array[0..63] of AnsiChar;
+                                                // descriptive string for file type?
+    end;
+
+  PAVIFileInfo = ^TAVIFileInfo;
+{$IFDEF UNICODE}
+  TAVIFileInfo = TAVIFileInfoW;
+{$ELSE}
+  TAVIFileInfo = TAVIFileInfoA;
+{$ENDIF}
+
+{-- Flags for dwFlags --------------------------------------------------------}
+
+const
+    AVIFILEINFO_HASINDEX            = $00000010;
+    AVIFILEINFO_MUSTUSEINDEX        = $00000020;
+    AVIFILEINFO_ISINTERLEAVED       = $00000100;
+    AVIFILEINFO_WASCAPTUREFILE      = $00010000;
+    AVIFILEINFO_COPYRIGHTED         = $00020000;
+
+{-- Flags for dwCaps ---------------------------------------------------------}
+
+    AVIFILECAPS_CANREAD             = $00000001;
+    AVIFILECAPS_CANWRITE            = $00000002;
+    AVIFILECAPS_ALLKEYFRAMES        = $00000010;
+    AVIFILECAPS_NOCOMPRESSION       = $00000020;
+
+type
+    TAVISAVECALLBACK                = function(i: int): BOOL; pascal;
+
+{-- AVICOMPRESSOPTIONS -------------------------------------------------------}
+
+// Make sure it matches the AutoDoc in avisave.c !!!
+
+type
+    PAVICOMPRESSOPTIONS             = ^TAVICOMPRESSOPTIONS;
+    TAVICOMPRESSOPTIONS             = packed record
+        fccType                     : DWORD;    // stream type, for consistency
+        fccHandler                  : DWORD;    // compressor
+        dwKeyFrameEvery             : DWORD;    // keyframe rate
+        dwQuality                   : DWORD;    // compress quality 0-10,000
+        dwBytesPerSecond            : DWORD;    // bytes per second
+        dwFlags                     : DWORD;    // flags... see below
+        lpFormat                    : PVOID;    // save format
+        cbFormat                    : DWORD;
+        lpParms                     : PVOID;    // compressor options
+        cbParms                     : DWORD;
+        dwInterleaveEvery           : DWORD;    // for non-video streams only
+    end;
+
+//
+// Defines for the dwFlags field of the AVICOMPRESSOPTIONS struct
+// Each of these flags determines if the appropriate field in the structure
+// (dwInterleaveEvery, dwBytesPerSecond, and dwKeyFrameEvery) is payed
+// attention to.  See the autodoc in avisave.c for details.
+//
+
+const
+    AVICOMPRESSF_INTERLEAVE         = $00000001;    // interleave
+    AVICOMPRESSF_DATARATE           = $00000002;    // use a data rate
+    AVICOMPRESSF_KEYFRAMES          = $00000004;    // use keyframes
+    AVICOMPRESSF_VALID              = $00000008;    // has valid data?
+
+(*	-	-	-	-	-	-	-	-	*/
+
+
+/****** AVI Stream Interface *******************************************)
+
+type
+    IAVIStream = interface(IUnknown)
+        function Create(lParam1, lParam2: LPARAM): HResult; stdcall;
+        function Info(var psi: TAVIStreamInfoW; lSize: LONG): HResult; stdcall;
+        function FindSample(lPos: LONG; lFlags: LONG): LONG; stdcall;
+        function ReadFormat(lPos: LONG; lpFormat: PVOID; var lpcbFormat: LONG): HResult; stdcall;
+        function SetFormat(lPos: LONG; lpFormat: PVOID; cbFormat: LONG): HResult; stdcall;
+        function Read(lStart: LONG; lSamples: LONG; lpBuffer: PVOID; cbBuffer: LONG; var plBytes, plSamples: LONG): HResult; stdcall;
+        function Write(lStart: LONG; lSamples: LONG; lpBuffer: PVOID; cbBuffer: LONG; dwFlags: DWORD; var plSampWritten, plBytesWritten: LONG): HResult; stdcall;
+        function Delete(lStart: LONG; lSamples: LONG): HResult; stdcall;
+        function ReadData(fcc: DWORD; lp: PVOID; var lpcb: LONG): HResult; stdcall;
+        function WriteData(fcc: DWORD; lp: PVOID; cb: LONG): HResult; stdcall;
+        function SetInfo(var lpInfo: TAVIStreamInfoW; cbInfo: LONG): HResult; stdcall;
+    end;
+
+    IAVIStreaming = interface(IUnknown)
+        function _Begin(lStart, lEnd : LONG; lRate : LONG): HResult; stdcall;
+        function _End: HResult; stdcall;
+    end;
+
+    IAVIEditStream = interface(IUnknown)
+        function Cut(var plStart, plLength: LONG; var ppResult: IAVIStream): HResult; stdcall;
+        function Copy(var plStart, plLength: LONG; var ppResult: IAVIStream): HResult; stdcall;
+        function Paste(var plPos: LONG; var plLength: LONG; pstream: IAVIStream; lStart, lEnd: LONG): HResult; stdcall;
+        function Clone(var ppResult: IAVIStream): HResult; stdcall;
+        function SetInfo(var lpInfo: TAVIStreamInfoW; cbInfo: LONG): HResult; stdcall;
+    end;
+
+{-- AVIFile ------------------------------------------------------------------}
+
+    IAVIFile = interface(IUnknown)
+        function Info(var pfi: TAVIFileInfoW; iSize: LONG): HResult; stdcall;
+        function GetStream(var ppStream: IAVISTREAM; fccType: DWORD; lParam: LONG): HResult; stdcall;
+        function CreateStream(var ppStream: IAVISTREAM; var psi: TAVIStreamInfoW): HResult; stdcall;
+        function WriteData(ckid: DWORD; lpData: PVOID; cbData: LONG): HResult; stdcall;
+        function ReadData(ckid: DWORD; lpData: PVOID; lpcbData: PLONG): HResult; stdcall;
+        function EndRecord: HResult; stdcall;
+        function DeleteStream(fccType: DWORD; lParam: LONG): HResult; stdcall;
+    end;
+
+{-- GetFrame -----------------------------------------------------------------}
+
+     // The functions 'BeginExtraction' and 'EndExtraction' have actually
+     // the names 'Begin' and 'End', but we cannot use that identifiers for
+     // obvious reasons.
+
+     IGetFrame = interface(IUnknown)
+       function GetFrame(lPos: LONG): PBitmapInfoHeader; stdcall;
+       function BeginExtraction(lStart, lEnd, lRate: LONG): HResult; stdcall;
+       function EndExtraction: HResult; stdcall;
+       function SetFormat(var lpbi: TBitmapInfoHeader; lpBits: Pointer; x, y, dx, dy: Integer): HResult; stdcall;
+     end;
+
+{-- GUIDs --------------------------------------------------------------------}
+
+const
+    IID_IAVIFile      : TGUID = (D1: $00020020; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
+    IID_IAVIStream    : TGUID = (D1: $00020021; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
+    IID_IAVIStreaming : TGUID = (D1: $00020022; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
+    IID_IGetFrame     : TGUID = (D1: $00020023; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
+    IID_IAVIEditStream: TGUID = (D1: $00020024; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
+
+    CLSID_AVISimpleUnMarshal : TGUID = (D1: $00020009; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
+    CLSID_AVIFile            : TGUID = (D1: $00020000; D2: $0; D3: $0; D4:($C0,$0,$0,$0,$0,$0,$0,$46));
+
+    AVIFILEHANDLER_CANREAD          = $0001;
+    AVIFILEHANDLER_CANWRITE         = $0002;
+    AVIFILEHANDLER_CANACCEPTNONRGB  = $0004;
+
+{-- Functions ----------------------------------------------------------------}
+procedure   AVIFileInit; stdcall;   // Call this first!
+procedure   AVIFileExit; stdcall;
+function    AVIFileAddRef(pfile: IAVIFile): ULONG; stdcall;
+function    AVIFileRelease(pfile: IAVIFile): ULONG; stdcall;
+function    AVIFileOpenA(var ppfile: IAVIFile; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
+function    AVIFileOpenW(var ppfile: IAVIFile; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
+
+{$IFDEF UNICODE}
+function    AVIFileOpen(var ppfile: IAVIFile; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
+{$ELSE}
+function    AVIFileOpen(var ppfile: IAVIFile; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;
+{$ENDIF}
+
+function    AVIFileInfoW(pfile: IAVIFile; var pfi: TAVIFILEINFOW; lSize: LONG): HResult; stdcall;
+function    AVIFileInfoA(pfile: IAVIFile; var pfi: TAVIFILEINFOA; lSize: LONG): HResult; stdcall;
+function    AVIFileInfo(pfile: IAVIFile; var pfi: TAVIFILEINFO; lSize: LONG): HResult; stdcall;
+function    AVIFileGetStream(pfile: IAVIFile; var ppavi: IAVISTREAM; fccType: DWORD; lParam: LONG): HResult; stdcall;
+function    AVIFileCreateStreamW(pfile: IAVIFile; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOW): HResult; stdcall;
+function    AVIFileCreateStreamA(pfile: IAVIFile; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOA): HResult; stdcall;
+function    AVIFileCreateStream(pfile: IAVIFile; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFO): HResult; stdcall;
+function    AVIFileWriteData(pfile: IAVIFile; ckid: DWORD; lpData: PVOID; cbData: LONG): HResult; stdcall;
+function    AVIFileReadData(pfile: IAVIFile; ckid: DWORD; lpData: PVOID; var lpcbData: LONG): HResult; stdcall;
+function    AVIFileEndRecord(pfile: IAVIFile): HResult; stdcall;
+function    AVIStreamAddRef(pavi: IAVIStream): ULONG; stdcall;
+function    AVIStreamRelease(pavi: IAVIStream): ULONG; stdcall;
+function    AVIStreamInfoW (pavi: IAVIStream; var psi: TAVISTREAMINFOW; lSize: LONG): HResult; stdcall;
+function    AVIStreamInfoA (pavi: IAVIStream; var psi: TAVISTREAMINFOA; lSize: LONG): HResult; stdcall;
+function    AVIStreamInfo(pavi: IAVIStream; var psi: TAVISTREAMINFO; lSize: LONG): HResult; stdcall;
+function    AVIStreamFindSample(pavi: IAVIStream; lPos: LONG; lFlags: LONG): LONG; stdcall;
+function    AVIStreamReadFormat(pavi: IAVIStream; lPos: LONG; lpFormat: PVOID; lpcbFormat: PLONG): HResult; stdcall;
+function    AVIStreamSetFormat(pavi: IAVIStream; lPos: LONG; lpFormat: PVOID; cbFormat: LONG): HResult; stdcall;
+function    AVIStreamReadData(pavi: IAVIStream; fcc: DWORD; lp: PVOID; lpcb: PLONG): HResult; stdcall;
+function    AVIStreamWriteData(pavi: IAVIStream; fcc: DWORD; lp: PVOID; cb: LONG): HResult; stdcall;
+function    AVIStreamRead(
+    pavi            : IAVISTREAM;
+    lStart          : LONG;
+    lSamples        : LONG;
+    lpBuffer        : PVOID;
+    cbBuffer        : LONG;
+    plBytes         : PLONG;
+    plSamples       : PLONG
+    ): HResult; stdcall;
+
+const
+    AVISTREAMREAD_CONVENIENT    = -1;
+
+function    AVIStreamWrite(
+    pavi            : IAVISTREAM;
+    lStart          : LONG;
+    lSamples        : LONG;
+    lpBuffer        : PVOID;
+    cbBuffer        : LONG;
+    dwFlags         : DWORD;
+    plSampWritten   : PLONG;
+    plBytesWritten  : PLONG
+    ): HResult; stdcall;
+
+// Right now, these just use AVIStreamInfo() to get information, then
+// return some of it.  Can they be more efficient?
+
+function    AVIStreamStart(pavi: IAVIStream): LONG; stdcall;
+function    AVIStreamLength(pavi: IAVIStream): LONG; stdcall;
+function    AVIStreamTimeToSample(pavi: IAVIStream; lTime: LONG): LONG; stdcall;
+function    AVIStreamSampleToTime(pavi: IAVIStream; lSample: LONG): LONG; stdcall;
+function    AVIStreamBeginStreaming(pavi: IAVIStream; lStart, lEnd: LONG; lRate: LONG): HResult; stdcall;
+function    AVIStreamEndStreaming(pavi: IAVIStream): HResult; stdcall;
+
+{-- Helper functions for using IGetFrame -------------------------------------}
+
+function    AVIStreamGetFrameOpen(pavi: IAVIStream; lpbiWanted: PBitmapInfoHeader): IGetFrame; stdcall;
+function    AVIStreamGetFrame(pg: IGetFrame; lPos: LONG): PBitmapInfoHeader; stdcall;
+function    AVIStreamGetFrameClose(pg: IGetFrame): HResult; stdcall;
+
+// !!! We need some way to place an advise on a stream....
+// STDAPI AVIStreamHasChanged   (PAVISTREAM pavi);
+
+{-- Shortcut function --------------------------------------------------------}
+
+function    AVIStreamOpenFromFileA(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
+                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
+function    AVIStreamOpenFromFileW(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
+                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
+
+{$IFDEF UNICODE}
+   function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
+     lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
+{$ELSE}
+   function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
+     lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall;
+{$ENDIF}
+
+{-- Use to create disembodied streams ----------------------------------------}
+
+function    AVIStreamCreate(var ppavi: IAVISTREAM; lParam1, lParam2: LONG; pclsidHandler: PCLSID): HResult; stdcall;
+
+// PHANDLER    AVIAPI AVIGetHandler         (PAVISTREAM pavi, PAVISTREAMHANDLER psh);
+// PAVISTREAM  AVIAPI AVIGetStream          (PHANDLER p);
+
+{-- Flags for AVIStreamFindSample --------------------------------------------}
+
+const
+    FIND_DIR                        = $0000000F;    // direction
+    FIND_NEXT                       = $00000001;    // go forward
+    FIND_PREV                       = $00000004;    // go backward
+    FIND_FROM_START                 = $00000008;    // start at the logical beginning
+
+    FIND_TYPE                       = $000000F0;    // type mask
+    FIND_KEY                        = $00000010;    // find key frame.
+    FIND_ANY                        = $00000020;    // find any (non-empty) sample
+    FIND_FORMAT                     = $00000040;    // find format change
+
+    FIND_RET                        = $0000F000;    // return mask
+    FIND_POS                        = $00000000;    // return logical position
+    FIND_LENGTH                     = $00001000;    // return logical size
+    FIND_OFFSET                     = $00002000;    // return physical position
+    FIND_SIZE                       = $00003000;    // return physical size
+    FIND_INDEX                      = $00004000;    // return physical index position
+
+{-- Stuff to support backward compat. ----------------------------------------}
+
+function    AVIStreamFindKeyFrame(var pavi: IAVISTREAM; lPos: LONG; lFlags: LONG): DWORD; stdcall; // AVIStreamFindSample
+
+// Non-portable: this is alias for method name
+// FindKeyFrame FindSample
+
+function    AVIStreamClose(pavi: IAVISTREAM): ULONG; stdcall; // AVIStreamRelease
+function    AVIFileClose(pfile: IAVIFILE): ULONG; stdcall; // AVIFileRelease
+procedure   AVIStreamInit; stdcall; // AVIFileInit
+procedure   AVIStreamExit; stdcall; // AVIFileExit
+
+const
+    SEARCH_NEAREST                  = FIND_PREV;
+    SEARCH_BACKWARD                 = FIND_PREV;
+    SEARCH_FORWARD                  = FIND_NEXT;
+    SEARCH_KEY                      = FIND_KEY;
+    SEARCH_ANY                      = FIND_ANY;
+
+{-- Helper macros ------------------------------------------------------------}
+
+function    AVIStreamSampleToSample(pavi1, pavi2: IAVISTREAM; l: LONG): LONG;
+function    AVIStreamNextSample(pavi: IAVISTREAM; l: LONG): LONG;
+function    AVIStreamPrevSample(pavi: IAVISTREAM; l: LONG): LONG;
+function    AVIStreamNearestSample(pavi: IAVISTREAM; l: LONG): LONG;
+function    AVIStreamNextKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
+function    AVIStreamPrevKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
+function    AVIStreamNearestKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
+function    AVIStreamIsKeyFrame(pavi: IAVISTREAM; l: LONG): BOOL;
+function    AVIStreamPrevSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
+function    AVIStreamNextSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
+function    AVIStreamNearestSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
+function    AVIStreamNextKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
+function    AVIStreamPrevKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
+function    AVIStreamNearestKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
+function    AVIStreamStartTime(pavi: IAVISTREAM): LONG;
+function    AVIStreamLengthTime(pavi: IAVISTREAM): LONG;
+function    AVIStreamEnd(pavi: IAVISTREAM): LONG;
+function    AVIStreamEndTime(pavi: IAVISTREAM): LONG;
+function    AVIStreamSampleSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): LONG;
+function    AVIStreamFormatSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): HResult;
+function    AVIStreamDataSize(pavi: IAVISTREAM; fcc: DWORD; plSize: PLONG): HResult;
+
+{== AVISave routines and structures ==========================================}
+
+const
+    comptypeDIB                     = $20424944; // mmioFOURCC('D', 'I', 'B', ' ')
+
+function    AVIMakeCompressedStream(
+    var ppsCompressed   : IAVISTREAM;
+    ppsSource           : IAVISTREAM;
+    lpOptions           : PAVICOMPRESSOPTIONS;
+    pclsidHandler       : PCLSID
+    ): HResult; stdcall;
+
+// Non-portable: uses variable number of params
+// EXTERN_C HRESULT CDECL AVISaveA (LPCSTR               szFile,
+//      CLSID FAR *pclsidHandler,
+//      AVISAVECALLBACK     lpfnCallback,
+//      int                 nStreams,
+//      PAVISTREAM      pfile,
+//      LPAVICOMPRESSOPTIONS lpOptions,
+//      ...);
+
+function    AVISaveVA(
+    szFile          : LPCSTR;
+    pclsidHandler   : PCLSID;
+    lpfnCallback    : TAVISAVECALLBACK;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): HResult; stdcall;
+
+// Non-portable: uses variable number of params
+// EXTERN_C HRESULT CDECL AVISaveW (LPCWSTR               szFile,
+//      CLSID FAR *pclsidHandler,
+//      AVISAVECALLBACK     lpfnCallback,
+//      int                 nStreams,
+//      PAVISTREAM      pfile,
+//      LPAVICOMPRESSOPTIONS lpOptions,
+//      ...);
+
+function    AVISaveVW(
+    szFile          : LPCWSTR;
+    pclsidHandler   : PCLSID;
+    lpfnCallback    : TAVISAVECALLBACK;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): HResult; stdcall;
+
+// #define AVISave      AVISaveA
+
+function    AVISaveV(
+    szFile          : LPCSTR;
+    pclsidHandler   : PCLSID;
+    lpfnCallback    : TAVISAVECALLBACK;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): HResult; stdcall; // AVISaveVA
+
+function    AVISaveOptions(
+    hwnd            : HWND;
+    uiFlags         : UINT;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): BOOL; stdcall;
+
+function    AVISaveOptionsFree(nStreams: int; var plpOptions: PAVICOMPRESSOPTIONS): HResult; stdcall;
+
+{-- FLAGS FOR uiFlags --------------------------------------------------------}
+
+// Same as the flags for ICCompressorChoose (see compman.h)
+// These determine what the compression options dialog for video streams
+// will look like.
+
+function    AVIBuildFilterW(lpszFilter: LPWSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall;
+function    AVIBuildFilterA(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall;
+
+function    AVIBuildFilter(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; // AVIBuildFilterA
+
+function    AVIMakeFileFromStreams(var ppfile: IAVIFILE; nStreams: int; var papStreams: IAVISTREAM): HResult; stdcall;
+
+function    AVIMakeStreamFromClipboard(cfFormat: UINT; hGlobal: THANDLE; var ppstream: IAVISTREAM): HResult; stdcall;
+
+{-- Clipboard routines -------------------------------------------------------}
+
+function    AVIPutFileOnClipboard(pf: IAVIFILE): HResult; stdcall;
+function    AVIGetFromClipboard(var lppf: IAVIFILE): HResult; stdcall;
+function    AVIClearClipboard: HResult; stdcall;
+
+{-- Editing routines ---------------------------------------------------------}
+
+function    CreateEditableStream(var ppsEditable: IAVISTREAM; psSource: IAVISTREAM): HResult; stdcall;
+function    EditStreamCut(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall;
+function    EditStreamCopy(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall;
+function    EditStreamPaste(pavi: IAVISTREAM; var plPos, plLength: LONG; pstream: IAVISTREAM; lStart, lEnd: LONG): HResult; stdcall;
+function    EditStreamClone(pavi: IAVISTREAM; var ppResult: IAVISTREAM): HResult; stdcall;
+function    EditStreamSetNameA(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall;
+function    EditStreamSetNameW(pavi: IAVISTREAM; lpszName: LPCWSTR): HResult; stdcall;
+function    EditStreamSetInfoW(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOW; cbInfo: LONG): HResult; stdcall;
+function    EditStreamSetInfoA(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall;
+function    EditStreamSetInfo(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall; // EditStreamSetInfoA
+function    EditStreamSetName(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall; // EditStreamSetNameA
+
+{-- Error handling -----------------------------------------------------------}
+
+const
+    AVIERR_OK                       = 0;
+
+// !!! Questions to be answered:
+// How can you get a string form of these errors?
+// Which of these errors should be replaced by errors in SCODE.H?
+
+const
+    AVIERR_UNSUPPORTED              = $80044065; // MAKE_AVIERR(101)
+    AVIERR_BADFORMAT                = $80044066; // MAKE_AVIERR(102)
+    AVIERR_MEMORY                   = $80044067; // MAKE_AVIERR(103)
+    AVIERR_INTERNAL                 = $80044068; // MAKE_AVIERR(104)
+    AVIERR_BADFLAGS                 = $80044069; // MAKE_AVIERR(105)
+    AVIERR_BADPARAM                 = $8004406A; // MAKE_AVIERR(106)
+    AVIERR_BADSIZE                  = $8004406B; // MAKE_AVIERR(107)
+    AVIERR_BADHANDLE                = $8004406C; // MAKE_AVIERR(108)
+    AVIERR_FILEREAD                 = $8004406D; // MAKE_AVIERR(109)
+    AVIERR_FILEWRITE                = $8004406E; // MAKE_AVIERR(110)
+    AVIERR_FILEOPEN                 = $8004406F; // MAKE_AVIERR(111)
+    AVIERR_COMPRESSOR               = $80044070; // MAKE_AVIERR(112)
+    AVIERR_NOCOMPRESSOR             = $80044071; // MAKE_AVIERR(113)
+    AVIERR_READONLY                 = $80044072; // MAKE_AVIERR(114)
+    AVIERR_NODATA                   = $80044073; // MAKE_AVIERR(115)
+    AVIERR_BUFFERTOOSMALL           = $80044074; // MAKE_AVIERR(116)
+    AVIERR_CANTCOMPRESS             = $80044075; // MAKE_AVIERR(117)
+    AVIERR_USERABORT                = $800440C6; // MAKE_AVIERR(198)
+    AVIERR_ERROR                    = $800440C7; // MAKE_AVIERR(199)
+
+{== MCIWnd - Window class for MCI objects ====================================}
+
+//
+//  MCIWnd
+//
+//    MCIWnd window class header file.
+//
+//    the MCIWnd window class is a window class for controling MCI devices
+//    MCI devices include, wave files, midi files, AVI Video, cd audio,
+//    vcr, video disc, and others..
+//
+//    to learn more about MCI and mci command sets see the
+//    "Microsoft Multimedia Programmers's guide" in the Win31 SDK
+//
+//    the easiest use of the MCIWnd class is like so:
+//
+//          hwnd = MCIWndCreate(hwndParent, hInstance, 0, "chimes.wav");
+//          ...
+//          MCIWndPlay(hwnd);
+//          MCIWndStop(hwnd);
+//          MCIWndPause(hwnd);
+//          ....
+//          MCIWndDestroy(hwnd);
+//
+//    this will create a window with a play/pause, stop and a playbar
+//    and start the wave file playing.
+//
+//    mciwnd.h defines macros for all the most common MCI commands, but
+//    any string command can be used if needed.
+//
+//    Note: unlike the mciSendString() API, no alias or file name needs
+//    to be specifed, since the device to use is implied by the window handle.
+//
+//          MCIWndSendString(hwnd, "setaudio stream to 2");
+//
+//    (C) Copyright Microsoft Corp. 1991-1995.  All rights reserved.
+//
+// WIN32:
+//
+//    MCIWnd supports both ansi and unicode interfaces. For any message that
+//    takes or returns a text string, two versions of the message are defined,
+//    appended with A or W for Ansi or Wide Char. The message or api itself
+//    is defined to be one or other of these depending on whether you have
+//    UNICODE defined in your application.
+//    Thus for the api MCIWndCreate, there are in fact two apis,
+//    MCIWndCreateA and MCIWndCreateW. If you call MCIWndCreate, this will be
+//    re-routed to MCIWndCreateA unless UNICODE is defined when building your
+//    application. In any one application, you can mix calls to the
+//    Ansi and Unicode entrypoints.
+//
+//    If you use SendMessage instead of the macros below such as MCIWndOpen(),
+//    you will see that the messages have changed for WIN32, to support Ansi
+//    and Unicode entrypoints. In particular, MCI_OPEN has been replaced by
+//    MCWNDM_OPENA, or MCIWNDM_OPENW (MCIWNDM_OPEN is defined to be one or
+//    other of these).
+//
+//    Also, note that the WIN32 implementation of MCIWnd uses UNICODE
+//    so all apis and messages supporting ANSI strings do so by mapping them
+//    UNICODE strings and then calling the corresponding UNICODE entrypoint.
+//
+
+function    MCIWndSM(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): DWORD;
+
+const                               
+    MCIWND_WINDOW_CLASS             = 'MCIWndClass' ;
+
+function    MCIWndCreateA(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl;
+function    MCIWndCreateW(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCWSTR): HWND; cdecl;
+function    MCIWndCreate(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl; // MCIWndCreateA
+function    MCIWndRegisterClass: BOOL; cdecl;
+
+{-- Flags for the MCIWndOpen command -----------------------------------------}
+
+const
+    MCIWNDOPENF_NEW                 = $0001;    // open a new file
+
+{-- Window styles ------------------------------------------------------------}
+
+    MCIWNDF_NOAUTOSIZEWINDOW        = $0001;    // when movie size changes
+    MCIWNDF_NOPLAYBAR               = $0002;    // no toolbar
+    MCIWNDF_NOAUTOSIZEMOVIE         = $0004;    // when window size changes
+    MCIWNDF_NOMENU                  = $0008;    // no popup menu from RBUTTONDOWN
+    MCIWNDF_SHOWNAME                = $0010;    // show name in caption
+    MCIWNDF_SHOWPOS                 = $0020;    // show position in caption
+    MCIWNDF_SHOWMODE                = $0040;    // show mode in caption
+    MCIWNDF_SHOWALL                 = $0070;    // show all
+
+    MCIWNDF_NOTIFYMODE              = $0100;    // tell parent of mode change
+    MCIWNDF_NOTIFYPOS               = $0200;    // tell parent of pos change
+    MCIWNDF_NOTIFYSIZE              = $0400;    // tell parent of size change
+    MCIWNDF_NOTIFYERROR             = $1000;    // tell parent of an error
+    MCIWNDF_NOTIFYALL               = $1F00;    // tell all
+
+    MCIWNDF_NOTIFYANSI              = $0080;
+
+// The MEDIA notification includes a text string.
+// To receive notifications in ANSI instead of unicode set the
+// MCIWNDF_NOTIFYANSI style bit. The macro below includes this bit
+// by default unless you define UNICODE in your application.
+
+    MCIWNDF_NOTIFYMEDIAA            = $0880;    // tell parent of media change
+    MCIWNDF_NOTIFYMEDIAW            = $0800;    // tell parent of media change
+
+    MCIWNDF_NOTIFYMEDIA             = MCIWNDF_NOTIFYMEDIAA;
+
+    MCIWNDF_RECORD                  = $2000;    // Give a record button
+    MCIWNDF_NOERRORDLG              = $4000;    // Show Error Dlgs for MCI cmds?
+    MCIWNDF_NOOPEN                  = $8000;    // Don't allow user to open things
+
+{-- Can macros ---------------------------------------------------------------}
+
+function    MCIWndCanPlay(hwnd: HWND): BOOL;
+function    MCIWndCanRecord(hwnd: HWND): BOOL;
+function    MCIWndCanSave(hwnd: HWND): BOOL;
+function    MCIWndCanWindow(hwnd: HWND): BOOL;
+function    MCIWndCanEject(hwnd: HWND): BOOL;
+function    MCIWndCanConfig(hwnd: HWND): BOOL;
+function    MCIWndPaletteKick(hwnd: HWND): BOOL;
+function    MCIWndSave(hwnd: HWND; szFile: LPCSTR): DWORD;
+function    MCIWndSaveDialog(hwnd: HWND): DWORD;
+
+// If you dont give a device it will use the current device....
+
+function    MCIWndNew(hwnd: HWND; lp: PVOID): DWORD;
+function    MCIWndRecord(hwnd: HWND): DWORD;
+function    MCIWndOpen(hwnd: HWND; sz: LPCSTR; f: BOOL): DWORD;
+function    MCIWndOpenDialog(hwnd: HWND): DWORD;
+function    MCIWndClose(hwnd: HWND): DWORD;
+function    MCIWndPlay(hwnd: HWND): DWORD;
+function    MCIWndStop(hwnd: HWND): DWORD;
+function    MCIWndPause(hwnd: HWND): DWORD;
+function    MCIWndResume(hwnd: HWND): DWORD;
+function    MCIWndSeek(hwnd: HWND; lPos: DWORD): DWORD;
+function    MCIWndEject(hwnd: HWND): DWORD;
+function    MCIWndHome(hwnd: HWND): DWORD;
+function    MCIWndEnd(hwnd: HWND): DWORD;
+function    MCIWndGetSource(hwnd: HWND; prc: PRECT): DWORD;
+function    MCIWndPutSource(hwnd: HWND; prc: PRECT): DWORD;
+function    MCIWndGetDest(hwnd: HWND; prc: PRECT): DWORD;
+function    MCIWndPutDest(hwnd: HWND; prc: PRECT): DWORD;
+function    MCIWndPlayReverse(hwnd: HWND): DWORD;
+function    MCIWndPlayFrom(hwnd: HWND; lPos: DWORD): DWORD;
+function    MCIWndPlayTo(hwnd: HWND; lPos: DWORD): DWORD;
+function    MCIWndPlayFromTo(hwnd: HWND; lStart, lEnd: DWORD): DWORD;
+function    MCIWndGetDeviceID(hwnd: HWND): UINT;
+function    MCIWndGetAlias(hwnd: HWND): UINT;
+function    MCIWndGetMode(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+function    MCIWndGetPosition(hwnd: HWND): DWORD;
+function    MCIWndGetPositionString(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+function    MCIWndGetStart(hwnd: HWND): DWORD;
+function    MCIWndGetLength(hwnd: HWND): DWORD;
+function    MCIWndGetEnd(hwnd: HWND): DWORD;
+function    MCIWndStep(hwnd: HWND; n: DWORD): DWORD;
+procedure   MCIWndDestroy(hwnd: HWND);
+procedure   MCIWndSetZoom(hwnd: HWND; iZoom: UINT);
+function    MCIWndGetZoom(hwnd: HWND): UINT;
+function    MCIWndSetVolume(hwnd: HWND; iVol: UINT): DWORD;
+function    MCIWndGetVolume(hwnd: HWND): DWORD;
+function    MCIWndSetSpeed(hwnd: HWND; iSpeed: UINT): DWORD;
+function    MCIWndGetSpeed(hwnd: HWND): DWORD;
+function    MCIWndSetTimeFormat(hwnd: HWND; lp: LPCSTR): DWORD;
+function    MCIWndGetTimeFormat(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+procedure   MCIWndValidateMedia(hwnd: HWND);
+procedure   MCIWndSetRepeat(hwnd: HWND; f: BOOL);
+function    MCIWndGetRepeat(hwnd: HWND): BOOL;
+function    MCIWndUseFrames(hwnd: HWND): DWORD;
+function    MCIWndUseTime(hwnd: HWND): DWORD;
+procedure   MCIWndSetActiveTimer(hwnd: HWND; active: UINT);
+procedure   MCIWndSetInactiveTimer(hwnd: HWND; inactive: UINT);
+procedure   MCIWndSetTimers(hwnd: HWND; active, inactive: UINT);
+function    MCIWndGetActiveTimer(hwnd: HWND): UINT;
+function    MCIWndGetInactiveTimer(hwnd: HWND): UINT;
+function    MCIWndRealize(hwnd: HWND; fBkgnd: BOOL): DWORD;
+function    MCIWndSendString(hwnd: HWND; sz: LPCSTR): DWORD;
+function    MCIWndReturnString(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+function    MCIWndGetError(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+
+// #define MCIWndActivate(hwnd, f)     (void)MCIWndSM(hwnd, WM_ACTIVATE, (WPARAM)(BOOL)(f), 0)
+
+function    MCIWndGetPalette(hwnd: HWND): HPALETTE;
+function    MCIWndSetPalette(hwnd: HWND; hpal: HPALETTE): DWORD;
+function    MCIWndGetFileName(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+function    MCIWndGetDevice(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+function    MCIWndGetStyles(hwnd: HWND): UINT;
+function    MCIWndChangeStyles(hwnd: HWND; mask: UINT; value: DWORD): DWORD;
+
+type
+    PUnknown    = ^IUnknown;
+
+function    MCIWndOpenInterface(hwnd: HWND; pUnk: PUnknown): DWORD;
+function    MCIWndSetOwner(hwnd: HWND; hwndP: HWND): DWORD;
+
+{-- Messages an app will send to MCIWND --------------------------------------}
+
+// all the text-related messages are defined out of order above (they need
+// to be defined before the MCIWndOpen() macros
+
+const
+    MCIWNDM_GETDEVICEID             = WM_USER + 100;
+    MCIWNDM_GETSTART                = WM_USER + 103;
+    MCIWNDM_GETLENGTH               = WM_USER + 104;
+    MCIWNDM_GETEND                  = WM_USER + 105;
+    MCIWNDM_EJECT                   = WM_USER + 107;
+    MCIWNDM_SETZOOM                 = WM_USER + 108;
+    MCIWNDM_GETZOOM                 = WM_USER + 109;
+    MCIWNDM_SETVOLUME               = WM_USER + 110;
+    MCIWNDM_GETVOLUME               = WM_USER + 111;
+    MCIWNDM_SETSPEED                = WM_USER + 112;
+    MCIWNDM_GETSPEED                = WM_USER + 113;
+    MCIWNDM_SETREPEAT               = WM_USER + 114;
+    MCIWNDM_GETREPEAT               = WM_USER + 115;
+    MCIWNDM_REALIZE                 = WM_USER + 118;
+    MCIWNDM_VALIDATEMEDIA           = WM_USER + 121;
+    MCIWNDM_PLAYFROM                = WM_USER + 122;
+    MCIWNDM_PLAYTO                  = WM_USER + 123;
+    MCIWNDM_GETPALETTE              = WM_USER + 126;
+    MCIWNDM_SETPALETTE              = WM_USER + 127;
+    MCIWNDM_SETTIMERS               = WM_USER + 129;
+    MCIWNDM_SETACTIVETIMER          = WM_USER + 130;
+    MCIWNDM_SETINACTIVETIMER        = WM_USER + 131;
+    MCIWNDM_GETACTIVETIMER          = WM_USER + 132;
+    MCIWNDM_GETINACTIVETIMER        = WM_USER + 133;
+    MCIWNDM_CHANGESTYLES            = WM_USER + 135;
+    MCIWNDM_GETSTYLES               = WM_USER + 136;
+    MCIWNDM_GETALIAS                = WM_USER + 137;
+    MCIWNDM_PLAYREVERSE             = WM_USER + 139;
+    MCIWNDM_GET_SOURCE              = WM_USER + 140;
+    MCIWNDM_PUT_SOURCE              = WM_USER + 141;
+    MCIWNDM_GET_DEST                = WM_USER + 142;
+    MCIWNDM_PUT_DEST                = WM_USER + 143;
+    MCIWNDM_CAN_PLAY                = WM_USER + 144;
+    MCIWNDM_CAN_WINDOW              = WM_USER + 145;
+    MCIWNDM_CAN_RECORD              = WM_USER + 146;
+    MCIWNDM_CAN_SAVE                = WM_USER + 147;
+    MCIWNDM_CAN_EJECT               = WM_USER + 148;
+    MCIWNDM_CAN_CONFIG              = WM_USER + 149;
+    MCIWNDM_PALETTEKICK             = WM_USER + 150;
+    MCIWNDM_OPENINTERFACE           = WM_USER + 151;
+    MCIWNDM_SETOWNER                = WM_USER + 152;
+
+{-- Define both A and W messages ---------------------------------------------}
+
+    MCIWNDM_SENDSTRINGA             = WM_USER + 101;
+    MCIWNDM_GETPOSITIONA            = WM_USER + 102;
+    MCIWNDM_GETMODEA                = WM_USER + 106;
+    MCIWNDM_SETTIMEFORMATA          = WM_USER + 119;
+    MCIWNDM_GETTIMEFORMATA          = WM_USER + 120;
+    MCIWNDM_GETFILENAMEA            = WM_USER + 124;
+    MCIWNDM_GETDEVICEA              = WM_USER + 125;
+    MCIWNDM_GETERRORA               = WM_USER + 128;
+    MCIWNDM_NEWA                    = WM_USER + 134;
+    MCIWNDM_RETURNSTRINGA           = WM_USER + 138;
+    MCIWNDM_OPENA                   = WM_USER + 153;
+
+    MCIWNDM_SENDSTRINGW             = WM_USER + 201;
+    MCIWNDM_GETPOSITIONW            = WM_USER + 202;
+    MCIWNDM_GETMODEW                = WM_USER + 206;
+    MCIWNDM_SETTIMEFORMATW          = WM_USER + 219;
+    MCIWNDM_GETTIMEFORMATW          = WM_USER + 220;
+    MCIWNDM_GETFILENAMEW            = WM_USER + 224;
+    MCIWNDM_GETDEVICEW              = WM_USER + 225;
+    MCIWNDM_GETERRORW               = WM_USER + 228;
+    MCIWNDM_NEWW                    = WM_USER + 234;
+    MCIWNDM_RETURNSTRINGW           = WM_USER + 238;
+    MCIWNDM_OPENW                   = WM_USER + 252;
+
+{-- Map defaults to A --------------------------------------------------------}
+
+    MCIWNDM_SENDSTRING              = MCIWNDM_SENDSTRINGA;
+    MCIWNDM_GETPOSITION             = MCIWNDM_GETPOSITIONA;
+    MCIWNDM_GETMODE                 = MCIWNDM_GETMODEA;
+    MCIWNDM_SETTIMEFORMAT           = MCIWNDM_SETTIMEFORMATA;
+    MCIWNDM_GETTIMEFORMAT           = MCIWNDM_GETTIMEFORMATA;
+    MCIWNDM_GETFILENAME             = MCIWNDM_GETFILENAMEA;
+    MCIWNDM_GETDEVICE               = MCIWNDM_GETDEVICEA;
+    MCIWNDM_GETERROR                = MCIWNDM_GETERRORA;
+    MCIWNDM_NEW                     = MCIWNDM_NEWA;
+    MCIWNDM_RETURNSTRING            = MCIWNDM_RETURNSTRINGA;
+    MCIWNDM_OPEN                    = MCIWNDM_OPENA;
+
+// note that the source text for MCIWND will thus contain
+// support for eg MCIWNDM_SENDSTRING (both the 16-bit entrypoint and
+// in win32 mapped to MCIWNDM_SENDSTRINGW), and MCIWNDM_SENDSTRINGA (the
+// win32 ansi thunk).
+
+{-- Messages MCIWND will send to an app --------------------------------------}
+
+const
+    MCIWNDM_NOTIFYMODE              = WM_USER + 200;    // wp = hwnd, lp = mode
+    MCIWNDM_NOTIFYPOS               = WM_USER + 201;    // wp = hwnd, lp = pos
+    MCIWNDM_NOTIFYSIZE              = WM_USER + 202;    // wp = hwnd
+    MCIWNDM_NOTIFYMEDIA             = WM_USER + 203;    // wp = hwnd, lp = fn
+    MCIWNDM_NOTIFYERROR             = WM_USER + 205;    // wp = hwnd, lp = error
+
+{-- Special seek values for START and END ------------------------------------}
+
+    MCIWND_START                    = dword(-1) ;
+    MCIWND_END                      = dword(-2) ;
+
+{== VIDEO - Video capture driver interface ===================================}
+
+type
+    HVIDEO                          = THandle;
+    PHVIDEO                         = ^HVIDEO;
+
+{-- Error return values ------------------------------------------------------}
+
+const
+    DV_ERR_OK                       = 0;                    // No error
+    DV_ERR_BASE                     = 1;                    // Error Base 
+    DV_ERR_NONSPECIFIC              = DV_ERR_BASE;
+    DV_ERR_BADFORMAT                = DV_ERR_BASE + 1;      // unsupported video format 
+    DV_ERR_STILLPLAYING             = DV_ERR_BASE + 2;      // still something playing 
+    DV_ERR_UNPREPARED               = DV_ERR_BASE + 3;      // header not prepared 
+    DV_ERR_SYNC                     = DV_ERR_BASE + 4;      // device is synchronous 
+    DV_ERR_TOOMANYCHANNELS          = DV_ERR_BASE + 5;      // number of channels exceeded 
+    DV_ERR_NOTDETECTED              = DV_ERR_BASE + 6;      // HW not detected 
+    DV_ERR_BADINSTALL               = DV_ERR_BASE + 7;      // Can not get Profile 
+    DV_ERR_CREATEPALETTE            = DV_ERR_BASE + 8;
+    DV_ERR_SIZEFIELD                = DV_ERR_BASE + 9;
+    DV_ERR_PARAM1                   = DV_ERR_BASE + 10;
+    DV_ERR_PARAM2                   = DV_ERR_BASE + 11;
+    DV_ERR_CONFIG1                  = DV_ERR_BASE + 12;
+    DV_ERR_CONFIG2                  = DV_ERR_BASE + 13;
+    DV_ERR_FLAGS                    = DV_ERR_BASE + 14;
+    DV_ERR_13                       = DV_ERR_BASE + 15;
+
+    DV_ERR_NOTSUPPORTED             = DV_ERR_BASE + 16;     // function not suported 
+    DV_ERR_NOMEM                    = DV_ERR_BASE + 17;     // out of memory 
+    DV_ERR_ALLOCATED                = DV_ERR_BASE + 18;     // device is allocated 
+    DV_ERR_BADDEVICEID              = DV_ERR_BASE + 19;
+    DV_ERR_INVALHANDLE              = DV_ERR_BASE + 20;
+    DV_ERR_BADERRNUM                = DV_ERR_BASE + 21;
+    DV_ERR_NO_BUFFERS               = DV_ERR_BASE + 22;     // out of buffers 
+
+    DV_ERR_MEM_CONFLICT             = DV_ERR_BASE + 23;     // Mem conflict detected 
+    DV_ERR_IO_CONFLICT              = DV_ERR_BASE + 24;     // I/O conflict detected 
+    DV_ERR_DMA_CONFLICT             = DV_ERR_BASE + 25;     // DMA conflict detected
+    DV_ERR_INT_CONFLICT             = DV_ERR_BASE + 26;     // Interrupt conflict detected
+    DV_ERR_PROTECT_ONLY             = DV_ERR_BASE + 27;     // Can not run in standard mode
+    DV_ERR_LASTERROR                = DV_ERR_BASE + 27;
+    DV_ERR_USER_MSG                 = DV_ERR_BASE + 1000;   // Hardware specific errors
+
+{-- Callback messages --------------------------------------------------------}
+
+// Note that the values for all installable driver callback messages are
+// identical, (ie. MM_DRVM_DATA has the same value for capture drivers,
+// installable video codecs, and the audio compression manager).
+
+const
+    DV_VM_OPEN                      = MM_DRVM_OPEN;     // Obsolete messages
+    DV_VM_CLOSE                     = MM_DRVM_CLOSE;
+    DV_VM_DATA                      = MM_DRVM_DATA;
+    DV_VM_ERROR                     = MM_DRVM_ERROR;
+
+{== Structures ===============================================================}
+
+{-- Video data block header --------------------------------------------------}
+
+type
+    PVIDEOHDR               = ^TVIDEOHDR;
+    TVIDEOHDR               = record
+        lpData              : PBYTE;                // pointer to locked data buffer
+        dwBufferLength      : DWORD;                // Length of data buffer
+        dwBytesUsed         : DWORD;                // Bytes actually used
+        dwTimeCaptured      : DWORD;                // Milliseconds from start of stream
+        dwUser              : DWORD;                // for client's use
+        dwFlags             : DWORD;                // assorted flags (see defines)
+        dwReserved          : array[0..3] of DWORD; // reserved for driver
+    end;
+
+{-- dwFlags field of VIDEOHDR ------------------------------------------------}
+
+const
+    VHDR_DONE                       = $00000001;    // Done bit
+    VHDR_PREPARED                   = $00000002;    // Set if this header has been prepared
+    VHDR_INQUEUE                    = $00000004;    // Reserved for driver
+    VHDR_KEYFRAME                   = $00000008;    // Key Frame
+
+{-- Channel capabilities structure -------------------------------------------}
+
+type
+    PCHANNEL_CAPS           = ^TCHANNEL_CAPS;
+    TCHANNEL_CAPS           = record
+        dwFlags             : DWORD;    // Capability flags
+        dwSrcRectXMod       : DWORD;    // Granularity of src rect in x
+        dwSrcRectYMod       : DWORD;    // Granularity of src rect in y
+        dwSrcRectWidthMod   : DWORD;    // Granularity of src rect width
+        dwSrcRectHeightMod  : DWORD;    // Granularity of src rect height
+        dwDstRectXMod       : DWORD;    // Granularity of dst rect in x
+        dwDstRectYMod       : DWORD;    // Granularity of dst rect in y
+        dwDstRectWidthMod   : DWORD;    // Granularity of dst rect width
+        dwDstRectHeightMod  : DWORD;    // Granularity of dst rect height
+    end;
+
+{-- dwFlags of CHANNEL_CAPS --------------------------------------------------}
+
+const
+    VCAPS_OVERLAY                   = $00000001;    // overlay channel 
+    VCAPS_SRC_CAN_CLIP              = $00000002;    // src rect can clip
+    VCAPS_DST_CAN_CLIP              = $00000004;    // dst rect can clip
+    VCAPS_CAN_SCALE                 = $00000008;    // allows src != dst
+
+{== API flags ================================================================}
+
+{-- Types of channels to open with the videoOpen function --------------------}
+
+const
+    VIDEO_EXTERNALIN                = $0001;
+    VIDEO_EXTERNALOUT               = $0002;
+    VIDEO_IN                        = $0004;
+    VIDEO_OUT                       = $0008;
+
+{-- Is a driver dialog available for this channel ----------------------------}
+
+    VIDEO_DLG_QUERY                 = $0010;
+
+{-- videoConfigure (both GET and SET) ----------------------------------------}
+
+    VIDEO_CONFIGURE_QUERY           = $8000;
+
+{-- videoConfigure (SET only) ------------------------------------------------}
+
+    VIDEO_CONFIGURE_SET             = $1000;
+
+{-- videoConfigure (GET only) ------------------------------------------------}
+
+    VIDEO_CONFIGURE_GET             = $2000;
+    VIDEO_CONFIGURE_QUERYSIZE       = $0001;
+
+    VIDEO_CONFIGURE_CURRENT         = $0010;
+    VIDEO_CONFIGURE_NOMINAL         = $0020;
+    VIDEO_CONFIGURE_MIN             = $0040;
+    VIDEO_CONFIGURE_MAX             = $0080;
+
+{== Configure messages =======================================================}
+
+    DVM_USER                        = $4000;
+
+    DVM_CONFIGURE_START             = $1000;
+    DVM_CONFIGURE_END               = $1FFF;
+    DVM_PALETTE                     = DVM_CONFIGURE_START + 1;
+    DVM_FORMAT                      = DVM_CONFIGURE_START + 2;
+    DVM_PALETTERGB555               = DVM_CONFIGURE_START + 3;
+    DVM_SRC_RECT                    = DVM_CONFIGURE_START + 4;
+    DVM_DST_RECT                    = DVM_CONFIGURE_START + 5;
+
+{== AVICAP - Window class for AVI capture ====================================}
+
+function    AVICapSM(hwnd: HWND; m: UINT; w: WPARAM; l: LPARAM): DWORD;
+
+{-- Window messages WM_CAP... which can be sent to an AVICAP window ----------}
+
+// UNICODE
+//
+// The Win32 version of AVICAP on NT supports UNICODE applications:
+// for each API or message that takes a char or string parameter, there are
+// two versions, ApiNameA and ApiNameW. The default name ApiName is #defined
+// to one or other depending on whether UNICODE is defined. Apps can call
+// the A and W apis directly, and mix them.
+//
+// The 32-bit AVICAP on NT uses unicode exclusively internally.
+// ApiNameA() will be implemented as a call to ApiNameW() together with
+// translation of strings.
+
+// Defines start of the message range
+const
+    WM_CAP_START                    = WM_USER;
+    WM_CAP_UNICODE_START            = WM_USER + 100;
+
+    WM_CAP_GET_CAPSTREAMPTR         = WM_CAP_START + 1;
+
+    WM_CAP_SET_CALLBACK_ERRORW      = WM_CAP_UNICODE_START + 2;
+    WM_CAP_SET_CALLBACK_STATUSW     = WM_CAP_UNICODE_START + 3;
+    WM_CAP_SET_CALLBACK_ERRORA      = WM_CAP_START + 2;
+    WM_CAP_SET_CALLBACK_STATUSA     = WM_CAP_START + 3;
+    WM_CAP_SET_CALLBACK_ERROR       = WM_CAP_SET_CALLBACK_ERRORA;
+    WM_CAP_SET_CALLBACK_STATUS      = WM_CAP_SET_CALLBACK_STATUSA;
+
+    WM_CAP_SET_CALLBACK_YIELD       = WM_CAP_START + 4;
+    WM_CAP_SET_CALLBACK_FRAME       = WM_CAP_START + 5;
+    WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START + 6;
+    WM_CAP_SET_CALLBACK_WAVESTREAM  = WM_CAP_START + 7;
+    WM_CAP_GET_USER_DATA            = WM_CAP_START + 8;
+    WM_CAP_SET_USER_DATA            = WM_CAP_START + 9;
+
+    WM_CAP_DRIVER_CONNECT           = WM_CAP_START + 10;
+    WM_CAP_DRIVER_DISCONNECT        = WM_CAP_START + 11;
+
+    WM_CAP_DRIVER_GET_NAMEA         = WM_CAP_START + 12;
+    WM_CAP_DRIVER_GET_VERSIONA      = WM_CAP_START + 13;
+    WM_CAP_DRIVER_GET_NAMEW         = WM_CAP_UNICODE_START + 12;
+    WM_CAP_DRIVER_GET_VERSIONW      = WM_CAP_UNICODE_START + 13;
+    WM_CAP_DRIVER_GET_NAME          = WM_CAP_DRIVER_GET_NAMEA;
+    WM_CAP_DRIVER_GET_VERSION       = WM_CAP_DRIVER_GET_VERSIONA;
+
+    WM_CAP_DRIVER_GET_CAPS          = WM_CAP_START + 14;
+
+    WM_CAP_FILE_SET_CAPTURE_FILEA   = WM_CAP_START + 20;
+    WM_CAP_FILE_GET_CAPTURE_FILEA   = WM_CAP_START + 21;
+    WM_CAP_FILE_SAVEASA             = WM_CAP_START + 23;
+    WM_CAP_FILE_SAVEDIBA            = WM_CAP_START + 25;
+    WM_CAP_FILE_SET_CAPTURE_FILEW   = WM_CAP_UNICODE_START + 20;
+    WM_CAP_FILE_GET_CAPTURE_FILEW   = WM_CAP_UNICODE_START + 21;
+    WM_CAP_FILE_SAVEASW             = WM_CAP_UNICODE_START + 23;
+    WM_CAP_FILE_SAVEDIBW            = WM_CAP_UNICODE_START + 25;
+    WM_CAP_FILE_SET_CAPTURE_FILE    = WM_CAP_FILE_SET_CAPTURE_FILEA;
+    WM_CAP_FILE_GET_CAPTURE_FILE    = WM_CAP_FILE_GET_CAPTURE_FILEA;
+    WM_CAP_FILE_SAVEAS              = WM_CAP_FILE_SAVEASA;
+    WM_CAP_FILE_SAVEDIB             = WM_CAP_FILE_SAVEDIBA;
+
+    // out of order to save on ifdefs
+
+    WM_CAP_FILE_ALLOCATE            = WM_CAP_START + 22;
+    WM_CAP_FILE_SET_INFOCHUNK       = WM_CAP_START + 24;
+
+    WM_CAP_EDIT_COPY                = WM_CAP_START + 30;
+
+    WM_CAP_SET_AUDIOFORMAT          = WM_CAP_START + 35;
+    WM_CAP_GET_AUDIOFORMAT          = WM_CAP_START + 36;
+
+    WM_CAP_DLG_VIDEOFORMAT          = WM_CAP_START + 41;
+    WM_CAP_DLG_VIDEOSOURCE          = WM_CAP_START + 42;
+    WM_CAP_DLG_VIDEODISPLAY         = WM_CAP_START + 43;
+    WM_CAP_GET_VIDEOFORMAT          = WM_CAP_START + 44;
+    WM_CAP_SET_VIDEOFORMAT          = WM_CAP_START + 45;
+    WM_CAP_DLG_VIDEOCOMPRESSION     = WM_CAP_START + 46;
+
+    WM_CAP_SET_PREVIEW              = WM_CAP_START + 50;
+    WM_CAP_SET_OVERLAY              = WM_CAP_START + 51;
+    WM_CAP_SET_PREVIEWRATE          = WM_CAP_START + 52;
+    WM_CAP_SET_SCALE                = WM_CAP_START + 53;
+    WM_CAP_GET_STATUS               = WM_CAP_START + 54;
+    WM_CAP_SET_SCROLL               = WM_CAP_START + 55;
+
+    WM_CAP_GRAB_FRAME               = WM_CAP_START + 60;
+    WM_CAP_GRAB_FRAME_NOSTOP        = WM_CAP_START + 61;
+
+    WM_CAP_SEQUENCE                 = WM_CAP_START + 62;
+    WM_CAP_SEQUENCE_NOFILE          = WM_CAP_START + 63;
+    WM_CAP_SET_SEQUENCE_SETUP       = WM_CAP_START + 64;
+    WM_CAP_GET_SEQUENCE_SETUP       = WM_CAP_START + 65;
+
+    WM_CAP_SET_MCI_DEVICEA          = WM_CAP_START + 66;
+    WM_CAP_GET_MCI_DEVICEA          = WM_CAP_START + 67;
+    WM_CAP_SET_MCI_DEVICEW          = WM_CAP_UNICODE_START + 66;
+    WM_CAP_GET_MCI_DEVICEW          = WM_CAP_UNICODE_START + 67;
+    WM_CAP_SET_MCI_DEVICE           = WM_CAP_SET_MCI_DEVICEA;
+    WM_CAP_GET_MCI_DEVICE           = WM_CAP_GET_MCI_DEVICEA;
+
+    WM_CAP_STOP                     = WM_CAP_START + 68;
+    WM_CAP_ABORT                    = WM_CAP_START + 69;
+
+    WM_CAP_SINGLE_FRAME_OPEN        = WM_CAP_START + 70;
+    WM_CAP_SINGLE_FRAME_CLOSE       = WM_CAP_START + 71;
+    WM_CAP_SINGLE_FRAME             = WM_CAP_START + 72;
+
+    WM_CAP_PAL_OPENA                = WM_CAP_START + 80;
+    WM_CAP_PAL_SAVEA                = WM_CAP_START + 81;
+    WM_CAP_PAL_OPENW                = WM_CAP_UNICODE_START + 80;
+    WM_CAP_PAL_SAVEW                = WM_CAP_UNICODE_START + 81;
+    WM_CAP_PAL_OPEN                 = WM_CAP_PAL_OPENA;
+    WM_CAP_PAL_SAVE                 = WM_CAP_PAL_SAVEA;
+
+    WM_CAP_PAL_PASTE                = WM_CAP_START + 82;
+    WM_CAP_PAL_AUTOCREATE           = WM_CAP_START + 83;
+    WM_CAP_PAL_MANUALCREATE         = WM_CAP_START + 84;
+
+    // Following added post VFW 1.1
+
+    WM_CAP_SET_CALLBACK_CAPCONTROL  = WM_CAP_START + 85;
+
+    // Defines end of the message range
+
+    WM_CAP_UNICODE_END              = WM_CAP_PAL_SAVEW;
+    WM_CAP_END                      = WM_CAP_UNICODE_END;
+
+{-- Callback definitions -----------------------------------------------------}
+
+type
+    TCAPYIELDCALLBACK               = function(hWnd: HWND): DWORD; stdcall;
+
+    TCAPSTATUSCALLBACKW             = function(hWnd: HWND; nID: int; lpsz: LPCWSTR): DWORD; stdcall;
+    TCAPERRORCALLBACKW              = function(hWnd: HWND; nID: int; lpsz: LPCWSTR): DWORD; stdcall;
+    TCAPSTATUSCALLBACKA             = function(hWnd: HWND; nID: int; lpsz: LPCSTR): DWORD; stdcall;
+    TCAPERRORCALLBACKA              = function(hWnd: HWND; nID: int; lpsz: LPCSTR): DWORD; stdcall;
+
+    TCAPSTATUSCALLBACK              = TCAPSTATUSCALLBACKA;
+    TCAPERRORCALLBACK               = TCAPERRORCALLBACKA;
+
+    TCAPVIDEOCALLBACK               = function(hWnd: HWND; lpVHdr: PVIDEOHDR): DWORD; stdcall;
+    TCAPWAVECALLBACK                = function(hWnd: HWND; lpWHdr: PWAVEHDR): DWORD; stdcall;
+    TCAPCONTROLCALLBACK             = function(hWnd: HWND; nState: int): DWORD; stdcall;
+
+{-- Structures ---------------------------------------------------------------}
+
+type
+    PCAPDRIVERCAPS                  = ^TCAPDRIVERCAPS;
+    TCAPDRIVERCAPS                  = record
+        wDeviceIndex                : UINT;     // Driver index in system.ini
+        fHasOverlay                 : BOOL;     // Can device overlay?
+        fHasDlgVideoSource          : BOOL;     // Has Video source dlg?
+        fHasDlgVideoFormat          : BOOL;     // Has Format dlg?
+        fHasDlgVideoDisplay         : BOOL;     // Has External out dlg?
+        fCaptureInitialized         : BOOL;     // Driver ready to capture?
+        fDriverSuppliesPalettes     : BOOL;     // Can driver make palettes?
+
+        // following always NULL on Win32.
+        hVideoIn                    : THANDLE;   // Driver In channel
+        hVideoOut                   : THANDLE;   // Driver Out channel
+        hVideoExtIn                 : THANDLE;   // Driver Ext In channel
+        hVideoExtOut                : THANDLE;   // Driver Ext Out channel
+    end;
+
+    PCAPSTATUS                      = ^TCAPSTATUS;
+    TCAPSTATUS                      = record
+        uiImageWidth                : UINT    ; // Width of the image
+        uiImageHeight               : UINT    ; // Height of the image
+        fLiveWindow                 : BOOL    ; // Now Previewing video?
+        fOverlayWindow              : BOOL    ; // Now Overlaying video?
+        fScale                      : BOOL    ; // Scale image to client?
+        ptScroll                    : TPOINT  ; // Scroll position
+        fUsingDefaultPalette        : BOOL    ; // Using default driver palette?
+        fAudioHardware              : BOOL    ; // Audio hardware present?
+        fCapFileExists              : BOOL    ; // Does capture file exist?
+        dwCurrentVideoFrame         : DWORD   ; // # of video frames cap'td
+        dwCurrentVideoFramesDropped : DWORD   ; // # of video frames dropped
+        dwCurrentWaveSamples        : DWORD   ; // # of wave samples cap'td
+        dwCurrentTimeElapsedMS      : DWORD   ; // Elapsed capture duration
+        hPalCurrent                 : HPALETTE; // Current palette in use
+        fCapturingNow               : BOOL    ; // Capture in progress?
+        dwReturn                    : DWORD   ; // Error value after any operation
+        wNumVideoAllocated          : UINT    ; // Actual number of video buffers
+        wNumAudioAllocated          : UINT    ; // Actual number of audio buffers
+    end;
+
+    // Default values in parenthesis
+
+    PCAPTUREPARMS                   = ^TCAPTUREPARMS;
+    TCAPTUREPARMS                   = record
+        dwRequestMicroSecPerFrame   : DWORD ;   // Requested capture rate
+        fMakeUserHitOKToCapture     : BOOL  ;   // Show "Hit OK to cap" dlg?
+        wPercentDropForError        : UINT  ;   // Give error msg if > (10%)
+        fYield                      : BOOL  ;   // Capture via background task?
+        dwIndexSize                 : DWORD ;   // Max index size in frames (32K)
+        wChunkGranularity           : UINT  ;   // Junk chunk granularity (2K)
+        fUsingDOSMemory             : BOOL  ;   // Use DOS buffers?
+        wNumVideoRequested          : UINT  ;   // # video buffers, If 0, autocalc
+        fCaptureAudio               : BOOL  ;   // Capture audio?
+        wNumAudioRequested          : UINT  ;   // # audio buffers, If 0, autocalc
+        vKeyAbort                   : UINT  ;   // Virtual key causing abort
+        fAbortLeftMouse             : BOOL  ;   // Abort on left mouse?
+        fAbortRightMouse            : BOOL  ;   // Abort on right mouse?
+        fLimitEnabled               : BOOL  ;   // Use wTimeLimit?
+        wTimeLimit                  : UINT  ;   // Seconds to capture
+        fMCIControl                 : BOOL  ;   // Use MCI video source?
+        fStepMCIDevice              : BOOL  ;   // Step MCI device?
+        dwMCIStartTime              : DWORD ;   // Time to start in MS
+        dwMCIStopTime               : DWORD ;   // Time to stop in MS
+        fStepCaptureAt2x            : BOOL  ;   // Perform spatial averaging 2x
+        wStepCaptureAverageFrames   : UINT  ;   // Temporal average n Frames
+        dwAudioBufferSize           : DWORD ;   // Size of audio bufs (0 = default)
+        fDisableWriteCache          : BOOL  ;   // Attempt to disable write cache
+        AVStreamMaster              : UINT  ;   // Which stream controls length?
+    end;
+
+{-- AVStreamMaster -----------------------------------------------------------}
+
+//  Since Audio and Video streams generally use non-synchronized capture
+//  clocks, this flag determines whether the audio stream is to be considered
+//  the master or controlling clock when writing the AVI file:
+//
+//  AVSTREAMMASTER_AUDIO  - Audio is master, video frame duration is forced
+//                          to match audio duration (VFW 1.0, 1.1 default)
+//  AVSTREAMMASTER_NONE   - No master, audio and video streams may be of
+//                          different lengths
+
+const
+    AVSTREAMMASTER_AUDIO            = 0;        // Audio master (VFW 1.0, 1.1)
+    AVSTREAMMASTER_NONE             = 1;        // No master
+
+type
+    PCAPINFOCHUNK                   = ^TCAPINFOCHUNK;
+    TCAPINFOCHUNK                   = record
+        fccInfoID                   : FOURCC;   // Chunk ID, "ICOP" for copyright
+        lpData                      : PVOID;    // pointer to data
+        cbData                      : DWORD;     // size of lpData
+    end;
+
+{-- CapControlCallback states ------------------------------------------------}
+
+const
+    CONTROLCALLBACK_PREROLL         = 1;        // Waiting to start capture 
+    CONTROLCALLBACK_CAPTURING       = 2;        // Now capturing
+
+{-- Message crackers for above -----------------------------------------------}
+
+// message wrapper macros are defined for the default messages only. Apps
+// that wish to mix Ansi and UNICODE message sending will have to
+// reference the _A and _W messages directly
+
+function    capSetCallbackOnError(hwnd: HWND; fpProc: TCAPERRORCALLBACK): BOOL;
+function    capSetCallbackOnStatus(hwnd: HWND; fpProc: TCAPSTATUSCALLBACK): BOOL;
+function    capSetCallbackOnYield(hwnd: HWND; fpProc: TCAPYIELDCALLBACK): BOOL;
+function    capSetCallbackOnFrame(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
+function    capSetCallbackOnVideoStream(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
+function    capSetCallbackOnWaveStream(hwnd: HWND; fpProc: TCAPWAVECALLBACK): BOOL;
+function    capSetCallbackOnCapControl(hwnd: HWND; fpProc: TCAPCONTROLCALLBACK): BOOL;
+
+function    capSetUserData(hwnd: HWND; lUser: DWORD): BOOL;
+function    capGetUserData(hwnd: HWND): DWORD;
+
+function    capDriverConnect(hwnd: HWND; i: INT): BOOL;
+function    capDriverDisconnect(hwnd: HWND): BOOL;
+function    capDriverGetName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
+function    capDriverGetVersion(hwnd: HWND; szVer: LPSTR; wSize: WORD): BOOL;
+function    capDriverGetCaps(hwnd: HWND; s: PCAPDRIVERCAPS; wSize: WORD): BOOL;
+
+function    capFileSetCaptureFile(hwnd: HWND; szName: LPCSTR): BOOL;
+function    capFileGetCaptureFile(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
+function    capFileAlloc(hwnd: HWND; dwSize: DWORD): BOOL;
+function    capFileSaveAs(hwnd: HWND; szName: LPCSTR): BOOL;
+function    capFileSetInfoChunk(hwnd: HWND; lpInfoChunk: PCAPINFOCHUNK): BOOL;
+function    capFileSaveDIB(hwnd: HWND; szName: LPCSTR): BOOL;
+
+function    capEditCopy(hwnd: HWND): BOOL;
+
+function    capSetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): BOOL;
+function    capGetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): DWORD;
+function    capGetAudioFormatSize(hwnd: HWND): DWORD;
+
+function    capDlgVideoFormat(hwnd: HWND): BOOL;
+function    capDlgVideoSource(hwnd: HWND): BOOL;
+function    capDlgVideoDisplay(hwnd: HWND): BOOL;
+function    capDlgVideoCompression(hwnd: HWND): BOOL;
+
+function    capGetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): DWORD;
+function    capGetVideoFormatSize(hwnd: HWND): DWORD;
+function    capSetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): BOOL;
+
+function    capPreview(hwnd: HWND; f: BOOL): BOOL;
+function    capPreviewRate(hwnd: HWND; wMS: WORD): BOOL;
+function    capOverlay(hwnd: HWND; f: BOOL): BOOL;
+function    capPreviewScale(hwnd: HWND; f: BOOL): BOOL;
+function    capGetStatus(hwnd: HWND; s: PCAPSTATUS; wSize: WORD): BOOL;
+function    capSetScrollPos(hwnd: HWND; lpP: PPOINT): BOOL;
+
+function    capGrabFrame(hwnd: HWND): BOOL;
+function    capGrabFrameNoStop(hwnd: HWND): BOOL;
+
+function    capCaptureSequence(hwnd: HWND): BOOL;
+function    capCaptureSequenceNoFile(hwnd: HWND): BOOL;
+function    capCaptureStop(hwnd: HWND): BOOL;
+function    capCaptureAbort(hwnd: HWND): BOOL;
+
+function    capCaptureSingleFrameOpen(hwnd: HWND): BOOL;
+function    capCaptureSingleFrameClose(hwnd: HWND): BOOL;
+function    capCaptureSingleFrame(hwnd: HWND): BOOL;
+
+function    capCaptureGetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
+function    capCaptureSetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
+
+function    capSetMCIDeviceName(hwnd: HWND; szName: LPCSTR): BOOL;
+function    capGetMCIDeviceName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
+
+function    capPaletteOpen(hwnd: HWND; szName: LPCSTR): BOOL;
+function    capPaletteSave(hwnd: HWND; szName: LPCSTR): BOOL;
+function    capPalettePaste(hwnd: HWND): BOOL;
+function    capPaletteAuto(hwnd: HWND; iFrames, iColors: INT): BOOL;
+function    capPaletteManual(hwnd: HWND; fGrab: BOOL; iColors: INT): BOOL;
+
+{-- The only exported functions from AVICAP.DLL ------------------------------}
+
+function    capCreateCaptureWindowA(
+    lpszWindowName      : LPCSTR;
+    dwStyle             : DWORD;
+    x, y                : int;
+    nWidth, nHeight     : int;
+    hwndParent          : HWND;
+    nID                 : int
+    ): HWND; stdcall;
+
+function    capGetDriverDescriptionA(
+    wDriverIndex        : UINT;
+    lpszName            : LPSTR;
+    cbName              : int;
+    lpszVer             : LPSTR;
+    cbVer               : int
+    ): BOOL; stdcall;
+
+function    capCreateCaptureWindowW(
+    lpszWindowName      : LPCWSTR;
+    dwStyle             : DWORD;
+    x, y                : int;
+    nWidth, nHeight     : int;
+    hwndParent          : HWND;
+    nID                 : int
+    ): HWND; stdcall;
+
+function    capGetDriverDescriptionW(
+    wDriverIndex        : UINT;
+    lpszName            : LPWSTR;
+    cbName              : int;
+    lpszVer             : LPWSTR;
+    cbVer               : int
+    ): BOOL; stdcall;
+
+function    capCreateCaptureWindow(
+    lpszWindowName      : LPCSTR;
+    dwStyle             : DWORD;
+    x, y                : int;
+    nWidth, nHeight     : int;
+    hwndParent          : HWND;
+    nID                 : int
+    ): HWND; stdcall; // capCreateCaptureWindowA
+
+function    capGetDriverDescription(
+    wDriverIndex        : UINT;
+    lpszName            : LPSTR;
+    cbName              : int;
+    lpszVer             : LPSTR;
+    cbVer               : int
+    ): BOOL; stdcall; // capGetDriverDescriptionA
+
+{-- New information chunk IDs ------------------------------------------------}
+
+const
+    infotypeDIGITIZATION_TIME       = $54494449; // mmioFOURCC ('I','D','I','T')
+    infotypeSMPTE_TIME              = $504D5349; // mmioFOURCC ('I','S','M','P')
+
+{-- String IDs from status and error callbacks -------------------------------}
+
+    IDS_CAP_BEGIN                   = 300;  // "Capture Start" 
+    IDS_CAP_END                     = 301;  // "Capture End" 
+
+    IDS_CAP_INFO                    = 401;  // "%s" 
+    IDS_CAP_OUTOFMEM                = 402;  // "Out of memory" 
+    IDS_CAP_FILEEXISTS              = 403;  // "File '%s' exists -- overwrite it?" 
+    IDS_CAP_ERRORPALOPEN            = 404;  // "Error opening palette '%s'" 
+    IDS_CAP_ERRORPALSAVE            = 405;  // "Error saving palette '%s'" 
+    IDS_CAP_ERRORDIBSAVE            = 406;  // "Error saving frame '%s'" 
+    IDS_CAP_DEFAVIEXT               = 407;  // "avi" 
+    IDS_CAP_DEFPALEXT               = 408;  // "pal" 
+    IDS_CAP_CANTOPEN                = 409;  // "Cannot open '%s'"
+    IDS_CAP_SEQ_MSGSTART            = 410;  // "Select OK to start capture\nof video sequence\nto %s."
+    IDS_CAP_SEQ_MSGSTOP             = 411;  // "Hit ESCAPE or click to end capture" 
+
+    IDS_CAP_VIDEDITERR              = 412;  // "An error occurred while trying to run VidEdit." 
+    IDS_CAP_READONLYFILE            = 413;  // "The file '%s' is a read-only file." 
+    IDS_CAP_WRITEERROR              = 414;  // "Unable to write to file '%s'.\nDisk may be full." 
+    IDS_CAP_NODISKSPACE             = 415;  // "There is no space to create a capture file on the specified device." 
+    IDS_CAP_SETFILESIZE             = 416;  // "Set File Size" 
+    IDS_CAP_SAVEASPERCENT           = 417;  // "SaveAs: %2ld%%  Hit Escape to abort." 
+
+    IDS_CAP_DRIVER_ERROR            = 418;  // Driver specific error message 
+
+    IDS_CAP_WAVE_OPEN_ERROR         = 419;  // "Error: Cannot open the wave input device.\nCheck sample size, frequency, and channels." 
+    IDS_CAP_WAVE_ALLOC_ERROR        = 420;  // "Error: Out of memory for wave buffers." 
+    IDS_CAP_WAVE_PREPARE_ERROR      = 421;  // "Error: Cannot prepare wave buffers." 
+    IDS_CAP_WAVE_ADD_ERROR          = 422;  // "Error: Cannot add wave buffers." 
+    IDS_CAP_WAVE_SIZE_ERROR         = 423;  // "Error: Bad wave size." 
+
+    IDS_CAP_VIDEO_OPEN_ERROR        = 424;  // "Error: Cannot open the video input device." 
+    IDS_CAP_VIDEO_ALLOC_ERROR       = 425;  // "Error: Out of memory for video buffers."
+    IDS_CAP_VIDEO_PREPARE_ERROR     = 426;  // "Error: Cannot prepare video buffers." 
+    IDS_CAP_VIDEO_ADD_ERROR         = 427;  // "Error: Cannot add video buffers." 
+    IDS_CAP_VIDEO_SIZE_ERROR        = 428;  // "Error: Bad video size." 
+
+    IDS_CAP_FILE_OPEN_ERROR         = 429;  // "Error: Cannot open capture file." 
+    IDS_CAP_FILE_WRITE_ERROR        = 430;  // "Error: Cannot write to capture file.  Disk may be full." 
+    IDS_CAP_RECORDING_ERROR         = 431;  // "Error: Cannot write to capture file.  Data rate too high or disk full." 
+    IDS_CAP_RECORDING_ERROR2        = 432;  // "Error while recording" 
+    IDS_CAP_AVI_INIT_ERROR          = 433;  // "Error: Unable to initialize for capture."
+    IDS_CAP_NO_FRAME_CAP_ERROR      = 434;  // "Warning: No frames captured.\nConfirm that vertical sync interrupts\nare configured and enabled." 
+    IDS_CAP_NO_PALETTE_WARN         = 435;  // "Warning: Using default palette." 
+    IDS_CAP_MCI_CONTROL_ERROR       = 436;  // "Error: Unable to access MCI device." 
+    IDS_CAP_MCI_CANT_STEP_ERROR     = 437;  // "Error: Unable to step MCI device." 
+    IDS_CAP_NO_AUDIO_CAP_ERROR      = 438;  // "Error: No audio data captured.\nCheck audio card settings." 
+    IDS_CAP_AVI_DRAWDIB_ERROR       = 439;  // "Error: Unable to draw this data format."
+    IDS_CAP_COMPRESSOR_ERROR        = 440;  // "Error: Unable to initialize compressor."
+    IDS_CAP_AUDIO_DROP_ERROR        = 441;  // "Error: Audio data was lost during capture, reduce capture rate."
+
+{-- Status string IDs --------------------------------------------------------}
+
+    IDS_CAP_STAT_LIVE_MODE          = 500;  // "Live window" 
+    IDS_CAP_STAT_OVERLAY_MODE       = 501;  // "Overlay window" 
+    IDS_CAP_STAT_CAP_INIT           = 502;  // "Setting up for capture - Please wait" 
+    IDS_CAP_STAT_CAP_FINI           = 503;  // "Finished capture, now writing frame %ld" 
+    IDS_CAP_STAT_PALETTE_BUILD      = 504;  // "Building palette map" 
+    IDS_CAP_STAT_OPTPAL_BUILD       = 505;  // "Computing optimal palette" 
+    IDS_CAP_STAT_I_FRAMES           = 506;  // "%d frames" 
+    IDS_CAP_STAT_L_FRAMES           = 507;  // "%ld frames" 
+    IDS_CAP_STAT_CAP_L_FRAMES       = 508;  // "Captured %ld frames" 
+    IDS_CAP_STAT_CAP_AUDIO          = 509;  // "Capturing audio" 
+    IDS_CAP_STAT_VIDEOCURRENT       = 510;  // "Captured %ld frames (%ld dropped) %d.%03d sec." 
+    IDS_CAP_STAT_VIDEOAUDIO         = 511;  // "Captured %d.%03d sec.  %ld frames (%ld dropped) (%d.%03d fps).  %ld audio bytes (%d,%03d sps)" 
+    IDS_CAP_STAT_VIDEOONLY          = 512;  // "Captured %d.%03d sec.  %ld frames (%ld dropped) (%d.%03d fps)" 
+    IDS_CAP_STAT_FRAMESDROPPED      = 513;  // "Dropped %ld of %ld frames (%d.%02d%%) during capture."
+
+{== FilePreview dialog =======================================================}
+
+function    GetOpenFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall;
+function    GetSaveFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall;
+
+function    GetOpenFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall;
+function    GetSaveFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall;
+
+function    GetOpenFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; // GetOpenFileNamePreviewA
+function    GetSaveFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; // GetSaveFileNamePreviewA
+
+implementation
+
+function MKFOURCC( ch0, ch1, ch2, ch3: AnsiChar ): FOURCC;
+begin
+  Result := (DWord(Ord(ch0))) or
+            (DWord(Ord(ch1)) shl 8) or
+            (DWord(Ord(ch2)) shl 16) or
+            (DWord(Ord(ch3)) shl 24);
+end;
+
+function mmioFOURCC( ch0, ch1, ch2, ch3: AnsiChar ): FOURCC;
+begin
+  Result := MKFOURCC(ch0,ch1,ch2,ch3);
+end;
+
+function aviTWOCC(ch0, ch1: AnsiChar): TWOCC;
+begin
+  Result := (Word(Ord(ch0))) or (Word(Ord(ch1)) shl 8);
+end;
+
+{-- Query macros -------------------------------------------------------------}
+
+function ICQueryAbout(hic: HIC): BOOL;
+begin
+  Result := ICSendMessage(hic, ICM_ABOUT, dword(-1), ICMF_ABOUT_QUERY) = ICERR_OK;
+end;
+
+function ICAbout(hic: HIC; hwnd: HWND): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_ABOUT, hwnd, 0);
+end;
+
+function ICQueryConfigure(hic: HIC): BOOL;
+begin
+  Result := ICSendMessage(hic, ICM_CONFIGURE, dword(-1), ICMF_CONFIGURE_QUERY) = ICERR_OK;
+end;
+
+function ICConfigure(hic: HIC; hwnd: HWND): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_CONFIGURE, hwnd, 0);
+end;
+
+{-- Get/Set state macros -----------------------------------------------------}
+
+function ICGetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_GETSTATE, DWORD(pv), cb);
+end;
+
+function ICSetState(hic: HIC; pv: PVOID; cb: DWORD): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_SETSTATE, DWORD(pv), cb);
+end;
+
+function ICGetStateSize(hic: HIC): DWORD;
+begin
+  Result := ICGetState(hic, nil, 0);
+end;
+
+{-- Get value macros ---------------------------------------------------------}
+
+function ICGetDefaultQuality(hic: HIC): DWORD;
+begin
+  ICSendMessage(hic, ICM_GETDEFAULTQUALITY, DWORD(@Result), sizeof(Result));
+end;
+
+function ICGetDefaultKeyFrameRate(hic: HIC): DWORD;
+begin
+  ICSendMessage(hic, ICM_GETDEFAULTKEYFRAMERATE, DWORD(@Result), sizeof(Result));
+end;
+
+{-- Draw window macro --------------------------------------------------------}
+
+function ICDrawWindow(hic: HIC; prc: PRECT): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_DRAW_WINDOW, DWORD(prc), sizeof(prc^));
+end;
+
+{-- ICCompressBegin() - start compression from a source fmt to a dest fmt ----}
+
+function ICCompressBegin(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_COMPRESS_BEGIN, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+{-- ICCompressQuery() - determines if compression from src to dst is supp ----}
+
+function ICCompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_COMPRESS_QUERY, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+{-- ICCompressGetFormat() - get the output format (fmt of compressed) --------}
+
+// if lpbiOutput is nil return the size in bytes needed for format.
+
+function ICCompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+  Result := ICSendMessage(hic, ICM_COMPRESS_GET_FORMAT, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+function ICCompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
+begin
+  Result := ICCompressGetFormat(hic, lpbi, nil);
+end;
+
+{-- ICCompressSize() - return the maximal size of a compressed frame ---------}
+
+function    ICCompressGetSize(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_COMPRESS_GET_SIZE, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+function    ICCompressEnd(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_COMPRESS_END, 0, 0);
+end;
+
+{-- ICDecompressBegin() - start compression from src fmt to a dest fmt -------}
+
+function    ICDecompressBegin(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DECOMPRESS_BEGIN, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+{-- ICDecompressQuery() - determines if compression is supported -------------}
+
+function    ICDecompressQuery(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DECOMPRESS_QUERY, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+{-- ICDecompressGetFormat - get the output fmt (fmt of uncompressed data) ----}
+
+// if lpbiOutput is NULL return the size in bytes needed for format.
+
+function    ICDecompressGetFormat(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DECOMPRESS_GET_FORMAT, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+function    ICDecompressGetFormatSize(hic: HIC; lpbi: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICDecompressGetFormat(hic, lpbi, nil);
+end;
+
+{-- ICDecompressGetPalette() - get the output palette ------------------------}
+
+function    ICDecompressGetPalette(hic: HIC; lpbiInput, lpbiOutput: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DECOMPRESS_GET_PALETTE, DWORD(lpbiInput), DWORD(lpbiOutput));
+end;
+
+function    ICDecompressSetPalette(hic: HIC; lpbiPalette: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DECOMPRESS_SET_PALETTE, DWORD(lpbiPalette), 0);
+end;
+
+function    ICDecompressEnd(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DECOMPRESS_END, 0, 0);
+end;
+
+{-- ICDecompressEx() - decompress a single frame -----------------------------}
+
+function    ICDecompressEx(
+    hic     : HIC;
+    dwFlags : DWORD;
+    lpbiSrc : PBITMAPINFOHEADER;
+    lpSrc   : PVOID;
+    xSrc    : int;
+    ySrc    : int;
+    dxSrc   : int;
+    dySrc   : int;
+    lpbiDst : PBITMAPINFOHEADER;
+    lpDst   : PVOID;
+    xDst    : int;
+    yDst    : int;
+    dxDst   : int;
+    dyDst   : int
+    ): DWORD; stdcall;
+var
+    ic : TICDECOMPRESSEX;
+begin
+    ic.dwFlags  := dwFlags;
+    ic.lpbiSrc  := lpbiSrc;
+    ic.lpSrc    := lpSrc;
+    ic.xSrc     := xSrc;
+    ic.ySrc     := ySrc;
+    ic.dxSrc    := dxSrc;
+    ic.dySrc    := dySrc;
+    ic.lpbiDst  := lpbiDst;
+    ic.lpDst    := lpDst;
+    ic.xDst     := xDst;
+    ic.yDst     := yDst;
+    ic.dxDst    := dxDst;
+    ic.dyDst    := dyDst;
+
+    // note that ICM swaps round the length and pointer
+    // length in lparam2, pointer in lparam1
+    Result := ICSendMessage(hic, ICM_DECOMPRESSEX, DWORD(@ic), sizeof(ic));
+end;
+
+{-- ICDecompressExBegin() - start compression from a src fmt to a dest fmt ---}
+
+function    ICDecompressExBegin(
+    hic     : HIC;
+    dwFlags : DWORD;
+    lpbiSrc : PBITMAPINFOHEADER;
+    lpSrc   : PVOID;
+    xSrc    : int;
+    ySrc    : int;
+    dxSrc   : int;
+    dySrc   : int;
+    lpbiDst : PBITMAPINFOHEADER;
+    lpDst   : PVOID;
+    xDst    : int;
+    yDst    : int;
+    dxDst   : int;
+    dyDst   : int
+    ): DWORD; stdcall;
+var
+    ic : TICDECOMPRESSEX ;
+begin
+    ic.dwFlags  := dwFlags;
+    ic.lpbiSrc  := lpbiSrc;
+    ic.lpSrc    := lpSrc;
+    ic.xSrc     := xSrc;
+    ic.ySrc     := ySrc;
+    ic.dxSrc    := dxSrc;
+    ic.dySrc    := dySrc;
+    ic.lpbiDst  := lpbiDst;
+    ic.lpDst    := lpDst;
+    ic.xDst     := xDst;
+    ic.yDst     := yDst;
+    ic.dxDst    := dxDst;
+    ic.dyDst    := dyDst;
+
+    // note that ICM swaps round the length and pointer
+    // length in lparam2, pointer in lparam1
+    Result      := ICSendMessage(hic, ICM_DECOMPRESSEX_BEGIN, DWORD(@ic), sizeof(ic));
+end;
+
+{-- ICDecompressExQuery() ----------------------------------------------------}
+
+function    ICDecompressExQuery(
+    hic     : HIC;
+    dwFlags : DWORD;
+    lpbiSrc : PBITMAPINFOHEADER;
+    lpSrc   : PVOID;
+    xSrc    : int;
+    ySrc    : int;
+    dxSrc   : int;
+    dySrc   : int;
+    lpbiDst : PBITMAPINFOHEADER;
+    lpDst   : PVOID;
+    xDst    : int;
+    yDst    : int;
+    dxDst   : int;
+    dyDst   : int
+    ): DWORD; stdcall;
+var
+    ic : TICDECOMPRESSEX;
+begin
+    ic.dwFlags  := dwFlags;
+    ic.lpbiSrc  := lpbiSrc;
+    ic.lpSrc    := lpSrc;
+    ic.xSrc     := xSrc;
+    ic.ySrc     := ySrc;
+    ic.dxSrc    := dxSrc;
+    ic.dySrc    := dySrc;
+    ic.lpbiDst  := lpbiDst;
+    ic.lpDst    := lpDst;
+    ic.xDst     := xDst;
+    ic.yDst     := yDst;
+    ic.dxDst    := dxDst;
+    ic.dyDst    := dyDst;
+
+    // note that ICM swaps round the length and pointer
+    // length in lparam2, pointer in lparam1
+    Result      := ICSendMessage(hic, ICM_DECOMPRESSEX_QUERY, DWORD(@ic), sizeof(ic));
+end;
+
+function    ICDecompressExEnd(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DECOMPRESSEX_END, 0, 0)
+end;
+
+function    ICDrawSuggestFormat(
+    hic         : HIC;
+    lpbiIn      : PBITMAPINFOHEADER;
+    lpbiOut     : PBITMAPINFOHEADER;
+    dxSrc       : int;
+    dySrc       : int;
+    dxDst       : int;
+    dyDst       : int;
+    hicDecomp   : HIC
+    ): DWORD; stdcall;
+var
+    ic : TICDRAWSUGGEST;
+begin
+    ic.lpbiIn           := lpbiIn;
+    ic.lpbiSuggest      := lpbiOut;
+    ic.dxSrc            := dxSrc;
+    ic.dySrc            := dySrc;
+    ic.dxDst            := dxDst;
+    ic.dyDst            := dyDst;
+    ic.hicDecompressor  := hicDecomp;
+
+    // note that ICM swaps round the length and pointer
+    // length in lparam2, pointer in lparam1
+    Result := ICSendMessage(hic, ICM_DRAW_SUGGESTFORMAT, DWORD(@ic), sizeof(ic));
+end;
+
+{-- ICDrawQuery() - determines if the compressor is willing to render fmt ----}
+
+function    ICDrawQuery(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_QUERY, DWORD(lpbiInput), 0);
+end;
+
+function    ICDrawChangePalette(hic: HIC; lpbiInput: PBITMAPINFOHEADER): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_CHANGEPALETTE, DWORD(lpbiInput), 0);
+end;
+
+function    ICGetBuffersWanted(hic: HIC; lpdwBuffers: PDWORD): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_GETBUFFERSWANTED, DWORD(lpdwBuffers), 0);
+end;
+
+function    ICDrawEnd(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_END, 0, 0);
+end;
+
+function    ICDrawStart(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_START, 0, 0);
+end;
+
+function    ICDrawStartPlay(hic: HIC; lFrom, lTo: DWORD): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_START_PLAY, lFrom, lTo);
+end;
+
+function    ICDrawStop(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_STOP, 0, 0);
+end;
+
+function    ICDrawStopPlay(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_STOP_PLAY, 0, 0);
+end;
+
+function    ICDrawGetTime(hic: HIC; lplTime: PDWORD): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_GETTIME, DWORD(lplTime), 0);
+end;
+
+function    ICDrawSetTime(hic: HIC; lTime: DWORD): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_SETTIME, lTime, 0);
+end;
+
+function    ICDrawRealize(hic: HIC; hdc: HDC; fBackground: BOOL): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_REALIZE, DWORD(hdc), DWORD(fBackground));
+end;
+
+function    ICDrawFlush(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_FLUSH, 0, 0);
+end;
+
+function    ICDrawRenderBuffer(hic: HIC): DWORD;
+begin
+    Result := ICSendMessage(hic, ICM_DRAW_RENDERBUFFER, 0, 0);
+end;
+
+{-- ICSetStatusProc() - Set the status callback function ---------------------}
+
+// ICMessage is not supported on NT
+
+function    ICSetStatusProc(
+    hic         : HIC;
+    dwFlags     : DWORD;
+    lParam      : DWORD;
+    fpfnStatus  : TICStatusProc
+    ): DWORD; stdcall;
+var
+    ic : TICSETSTATUSPROC;
+begin
+    ic.dwFlags  := dwFlags;
+    ic.lParam   := lParam;
+    ic.Status   := fpfnStatus;
+
+    // note that ICM swaps round the length and pointer
+    // length in lparam2, pointer in lparam1
+    Result      := ICSendMessage(hic, ICM_SET_STATUS_PROC, DWORD(@ic), sizeof(ic));
+end;
+
+{== Helper routines for DrawDib and MCIAVI... ================================}
+
+function    ICDecompressOpen(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER): HIC;
+begin
+    Result := ICLocate(fccType, fccHandler, lpbiIn, lpbiOut, ICMODE_DECOMPRESS);
+end;
+
+function    ICDrawOpen(fccType, fccHandler: DWORD; lpbiIn: PBITMAPINFOHEADER): HIC;
+begin
+    Result := ICLocate(fccType, fccHandler, lpbiIn, nil, ICMODE_DRAW);
+end;
+
+{-- DrawDibUpdate() - redraw last image (may only be valid with DDF_BUFFER) --}
+
+function    DrawDibUpdate(hdd: HDRAWDIB; hdc: HDC; x, y: int): BOOL;
+begin
+    Result  := DrawDibDraw(hdd, hdc, x, y, 0, 0, nil, nil, 0, 0, 0, 0, DDF_UPDATE);
+end;
+
+{== Useful macros ============================================================}
+
+{-- Macro to get stream number out of a FOURCC ckid --------------------------}
+
+function    FromHex(n: BYTE): BYTE;
+begin
+    if n >= Ord('A') then
+        Result := Ord(n) + 10 - Ord('A')
+    else
+        Result := Ord(n) - Ord('0');
+end;
+
+function    StreamFromFOURCC(fcc: DWORD): BYTE;
+begin
+    Result :=  (FromHex(Lo(LoWord(fcc))) shl 4) + FromHex(Hi(LoWord(fcc)));
+end;
+
+{-- Macro to get TWOCC chunk type out of a FOURCC ckid -----------------------}
+
+function    TWOCCFromFOURCC(fcc: DWORD): WORD;
+begin
+    Result := HiWord(fcc);
+end;
+
+{-- Macro to make a ckid for a chunk out of a TWOCC and a stream num (0-255) -}
+
+function    ToHex(n: BYTE): BYTE;
+begin
+    if n > 9 then
+        Result := n - 10 + Ord('A')
+    else
+        Result := n + Ord('0');
+end;
+
+function    MAKEAVICKID(tcc: WORD; stream: BYTE): DWORD;
+begin
+    Result := MakeLONG((ToHex(stream and $0F) shl 8) or ToHex((stream and $F0) shr 4),tcc);
+end;
+
+{-- Helper macros ------------------------------------------------------------}
+
+function    AVIStreamSampleToSample(pavi1, pavi2: IAVISTREAM; l: LONG): LONG;
+begin
+    Result  := AVIStreamTimeToSample(pavi1,AVIStreamSampleToTime(pavi2, l));
+end;
+
+function    AVIStreamNextSample(pavi: IAVISTREAM; l: LONG): LONG;
+begin
+    Result  := AVIStreamFindSample(pavi,l+1,FIND_NEXT or FIND_ANY);
+end;
+
+function    AVIStreamPrevSample(pavi: IAVISTREAM; l: LONG): LONG;
+begin
+    Result  := AVIStreamFindSample(pavi,l-1,FIND_PREV or FIND_ANY);
+end;
+
+function    AVIStreamNearestSample(pavi: IAVISTREAM; l: LONG): LONG;
+begin
+    Result  := AVIStreamFindSample(pavi,l,FIND_PREV or FIND_ANY);
+end;
+
+function    AVIStreamNextKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
+begin
+    Result  := AVIStreamFindSample(pavi,l+1,FIND_NEXT or FIND_KEY);
+end;
+
+function    AVIStreamPrevKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
+begin
+    Result  := AVIStreamFindSample(pavi,l-1,FIND_PREV or FIND_KEY);
+end;
+
+function    AVIStreamNearestKeyFrame(pavi: IAVISTREAM; l: LONG): LONG;
+begin
+    Result  := AVIStreamFindSample(pavi,l,FIND_PREV or FIND_KEY)
+end;
+
+function    AVIStreamIsKeyFrame(pavi: IAVISTREAM; l: LONG): BOOL;
+begin
+    Result  := AVIStreamNearestKeyFrame(pavi,l) = l;
+end;
+
+function    AVIStreamPrevSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamPrevSample(pavi,AVIStreamTimeToSample(pavi,t)));
+end;
+
+function    AVIStreamNextSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamNextSample(pavi,AVIStreamTimeToSample(pavi,t)));
+end;
+
+function    AVIStreamNearestSampleTime(pavi: IAVISTREAM; t: LONG): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamNearestSample(pavi,AVIStreamTimeToSample(pavi,t)));
+end;
+
+function    AVIStreamNextKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamNextKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)));
+end;
+
+function    AVIStreamPrevKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamPrevKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)));
+end;
+
+function    AVIStreamNearestKeyFrameTime(pavi: IAVISTREAM; t: LONG): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamNearestKeyFrame(pavi,AVIStreamTimeToSample(pavi, t)));
+end;
+
+function    AVIStreamStartTime(pavi: IAVISTREAM): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamStart(pavi));
+end;
+
+function    AVIStreamLengthTime(pavi: IAVISTREAM): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamLength(pavi));
+end;
+
+function    AVIStreamEnd(pavi: IAVISTREAM): LONG;
+begin
+    Result  := AVIStreamStart(pavi) + AVIStreamLength(pavi);
+end;
+
+function    AVIStreamEndTime(pavi: IAVISTREAM): LONG;
+begin
+    Result  := AVIStreamSampleToTime(pavi, AVIStreamEnd(pavi));
+end;
+
+function    AVIStreamSampleSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): LONG;
+begin
+    Result  := AVIStreamRead(pavi,lPos,1,nil,0,plSize,nil);
+end;
+
+function    AVIStreamFormatSize(pavi: IAVISTREAM; lPos: LONG; plSize: PLONG): HResult;
+begin
+    Result  := AVIStreamReadFormat(pavi,lPos,nil,plSize);
+end;
+
+function    AVIStreamDataSize(pavi: IAVISTREAM; fcc: DWORD; plSize: PLONG): HResult;
+begin
+    Result  := AVIStreamReadData(pavi,fcc,nil,plSize)
+end;
+
+{== MCIWnd ===================================================================}
+
+function    MCIWndSM(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): DWORD;
+begin
+    Result := SendMessage(hWnd, Msg, wParam, lParam);
+end;
+
+{-- Can macros ---------------------------------------------------------------}
+
+function    MCIWndCanPlay(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_PLAY,0,0) <> 0;
+end;
+
+function    MCIWndCanRecord(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_RECORD,0,0) <> 0;
+end;
+
+function    MCIWndCanSave(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_SAVE,0,0) <> 0;
+end;
+
+function    MCIWndCanWindow(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_WINDOW,0,0) <> 0;
+end;
+
+function    MCIWndCanEject(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_EJECT,0,0) <> 0;
+end;
+
+function    MCIWndCanConfig(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd,MCIWNDM_CAN_CONFIG,0,0) <> 0;
+end;
+
+function    MCIWndPaletteKick(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd,MCIWNDM_PALETTEKICK,0,0) <> 0;
+end;
+
+function    MCIWndSave(hwnd: HWND; szFile: LPCSTR): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_SAVE, 0, LPARAM(szFile));
+end;
+
+function    MCIWndSaveDialog(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSave(hwnd, LPCSTR(-1));
+end;
+
+// If you dont give a device it will use the current device....
+
+function    MCIWndNew(hwnd: HWND; lp: PVOID): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_NEW, 0, LPARAM(lp));
+end;
+
+function    MCIWndRecord(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_RECORD, 0, 0);
+end;
+
+function    MCIWndOpen(hwnd: HWND; sz: LPCSTR; f: BOOL): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_OPEN, WPARAM(f), LPARAM(sz));
+end;
+
+function    MCIWndOpenDialog(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndOpen(hwnd, LPCSTR(-1), False);
+end;
+
+function    MCIWndClose(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_CLOSE, 0, 0);
+end;
+
+function    MCIWndPlay(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_PLAY, 0, 0);
+end;
+
+function    MCIWndStop(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_STOP, 0, 0);
+end;
+
+function    MCIWndPause(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_PAUSE, 0, 0);
+end;
+
+function    MCIWndResume(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_RESUME, 0, 0);
+end;
+
+function    MCIWndSeek(hwnd: HWND; lPos: DWORD): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_SEEK, 0, lPos);
+end;
+
+function    MCIWndEject(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_EJECT, 0, 0);
+end;
+
+function    MCIWndHome(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSeek(hwnd, MCIWND_START);
+end;
+
+function    MCIWndEnd(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSeek(hwnd, MCIWND_END);
+end;
+
+function    MCIWndGetSource(hwnd: HWND; prc: PRECT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GET_SOURCE, 0, LPARAM(prc));
+end;
+
+function    MCIWndPutSource(hwnd: HWND; prc: PRECT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_PUT_SOURCE, 0, LPARAM(prc));
+end;
+
+function    MCIWndGetDest(hwnd: HWND; prc: PRECT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GET_DEST, 0, LPARAM(prc));
+end;
+
+function    MCIWndPutDest(hwnd: HWND; prc: PRECT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_PUT_DEST, 0, LPARAM(prc));
+end;
+
+function    MCIWndPlayReverse(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_PLAYREVERSE, 0, 0);
+end;
+
+function    MCIWndPlayFrom(hwnd: HWND; lPos: DWORD): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_PLAYFROM, 0, lPos);
+end;
+
+function    MCIWndPlayTo(hwnd: HWND; lPos: DWORD): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_PLAYTO, 0, lPos);
+end;
+
+function    MCIWndPlayFromTo(hwnd: HWND; lStart, lEnd: DWORD): DWORD;
+begin
+    MCIWndSeek(hwnd, lStart);
+    Result  := MCIWndPlayTo(hwnd, lEnd);
+end;
+
+function    MCIWndGetDeviceID(hwnd: HWND): UINT;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETDEVICEID, 0, 0);
+end;
+
+function    MCIWndGetAlias(hwnd: HWND): UINT;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETALIAS, 0, 0);
+end;
+
+function    MCIWndGetMode(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETMODE, len, LPARAM(lp));
+end;
+
+function    MCIWndGetPosition(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETPOSITION, 0, 0);
+end;
+
+function    MCIWndGetPositionString(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETPOSITION, len, LPARAM(lp));
+end;
+
+function    MCIWndGetStart(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETSTART, 0, 0);
+end;
+
+function    MCIWndGetLength(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETLENGTH, 0, 0);
+end;
+
+function    MCIWndGetEnd(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETEND, 0, 0);
+end;
+
+function    MCIWndStep(hwnd: HWND; n: DWORD): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCI_STEP, 0, n);
+end;
+
+procedure   MCIWndDestroy(hwnd: HWND);
+begin
+    MCIWndSM(hwnd, WM_CLOSE, 0, 0);
+end;
+
+procedure   MCIWndSetZoom(hwnd: HWND; iZoom: UINT);
+begin
+    MCIWndSM(hwnd, MCIWNDM_SETZOOM, 0, iZoom);
+end;
+
+function    MCIWndGetZoom(hwnd: HWND): UINT;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETZOOM, 0, 0);
+end;
+
+function    MCIWndSetVolume(hwnd: HWND; iVol: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_SETVOLUME, 0, iVol);
+end;
+
+function    MCIWndGetVolume(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETVOLUME, 0, 0);
+end;
+
+function    MCIWndSetSpeed(hwnd: HWND; iSpeed: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_SETSPEED, 0, iSpeed);
+end;
+
+function    MCIWndGetSpeed(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETSPEED, 0, 0);
+end;
+
+function    MCIWndSetTimeFormat(hwnd: HWND; lp: LPCSTR): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_SETTIMEFORMAT, 0, LPARAM(lp));
+end;
+
+function    MCIWndGetTimeFormat(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETTIMEFORMAT, len, LPARAM(lp));
+end;
+
+procedure   MCIWndValidateMedia(hwnd: HWND);
+begin
+    MCIWndSM(hwnd, MCIWNDM_VALIDATEMEDIA, 0, 0);
+end;
+
+procedure   MCIWndSetRepeat(hwnd: HWND; f: BOOL);
+begin
+    MCIWndSM(hwnd, MCIWNDM_SETREPEAT, 0, LPARAM(f));
+end;
+
+function    MCIWndGetRepeat(hwnd: HWND): BOOL;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETREPEAT, 0, 0) <> 0;
+end;
+
+function    MCIWndUseFrames(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSetTimeFormat(hwnd, 'frames');
+end;
+
+function    MCIWndUseTime(hwnd: HWND): DWORD;
+begin
+    Result  := MCIWndSetTimeFormat(hwnd, 'ms');
+end;
+
+procedure   MCIWndSetActiveTimer(hwnd: HWND; active: UINT);
+begin
+    MCIWndSM(hwnd, MCIWNDM_SETACTIVETIMER, active, 0);
+end;
+
+procedure   MCIWndSetInactiveTimer(hwnd: HWND; inactive: UINT);
+begin
+    MCIWndSM(hwnd, MCIWNDM_SETINACTIVETIMER, inactive, 0);
+end;
+
+procedure   MCIWndSetTimers(hwnd: HWND; active, inactive: UINT);
+begin
+    MCIWndSM(hwnd, MCIWNDM_SETTIMERS, active, inactive);
+end;
+
+function    MCIWndGetActiveTimer(hwnd: HWND): UINT;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETACTIVETIMER, 0, 0);
+end;
+
+function    MCIWndGetInactiveTimer(hwnd: HWND): UINT;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETINACTIVETIMER, 0, 0);
+end;
+
+function    MCIWndRealize(hwnd: HWND; fBkgnd: BOOL): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_REALIZE, WPARAM(fBkgnd), 0);
+end;
+
+function    MCIWndSendString(hwnd: HWND; sz: LPCSTR): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_SENDSTRING, 0, LPARAM(sz));
+end;
+
+function    MCIWndReturnString(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_RETURNSTRING, len, LPARAM(lp));
+end;
+
+function    MCIWndGetError(hwnd: HWND; lp: LPSTR; len: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETERROR, len, LPARAM(lp));
+end;
+
+function    MCIWndGetPalette(hwnd: HWND): HPALETTE;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETPALETTE, 0, 0);
+end;
+
+function    MCIWndSetPalette(hwnd: HWND; hpal: HPALETTE): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_SETPALETTE, hpal, 0);
+end;
+
+function    MCIWndGetFileName(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETFILENAME, len, LPARAM(lp));
+end;
+
+function    MCIWndGetDevice(hwnd: HWND; lp: LPCSTR; len: UINT): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETDEVICE, len, LPARAM(lp));
+end;
+
+function    MCIWndGetStyles(hwnd: HWND): UINT;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_GETSTYLES, 0, 0);
+end;
+
+function    MCIWndChangeStyles(hwnd: HWND; mask: UINT; value: DWORD): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_CHANGESTYLES, mask, value);
+end;
+
+function    MCIWndOpenInterface(hwnd: HWND; pUnk: PUNKNOWN): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_OPENINTERFACE, 0, LPARAM(pUnk));
+end;
+
+function    MCIWndSetOwner(hwnd: HWND; hwndP: HWND): DWORD;
+begin
+    Result  := MCIWndSM(hwnd, MCIWNDM_SETOWNER, hwndP, 0);
+end;
+
+{== AVICAP - Window class for AVI capture ====================================}
+
+function    AVICapSM(hwnd: HWND; m: UINT; w: WPARAM; l: LPARAM): DWORD;
+begin
+    if IsWindow(hwnd) then
+        Result := SendMessage(hwnd,m,w,l)
+    else
+        Result := 0;
+end;
+
+{-- Message crackers for above -----------------------------------------------}
+
+function    capSetCallbackOnError(hwnd: HWND; fpProc: TCAPERRORCALLBACK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_ERROR, 0, LPARAM(@fpProc)) <> 0;
+end;
+
+function    capSetCallbackOnStatus(hwnd: HWND; fpProc: TCAPSTATUSCALLBACK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_STATUS, 0, LPARAM(@fpProc)) <> 0;
+end;
+
+function    capSetCallbackOnYield(hwnd: HWND; fpProc: TCAPYIELDCALLBACK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_YIELD, 0, LPARAM(@fpProc)) <> 0;
+end;
+
+function    capSetCallbackOnFrame(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_FRAME, 0, LPARAM(@fpProc)) <> 0;
+end;
+
+function    capSetCallbackOnVideoStream(hwnd: HWND; fpProc: TCAPVIDEOCALLBACK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, LPARAM(@fpProc)) <> 0;
+end;
+
+function    capSetCallbackOnWaveStream(hwnd: HWND; fpProc: TCAPWAVECALLBACK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_WAVESTREAM, 0, LPARAM(@fpProc)) <> 0;
+end;
+
+function    capSetCallbackOnCapControl(hwnd: HWND; fpProc: TCAPCONTROLCALLBACK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_CALLBACK_CAPCONTROL, 0, LPARAM(@fpProc)) <> 0;
+end;
+
+function    capSetUserData(hwnd: HWND; lUser: DWORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_USER_DATA, 0, lUser) <> 0;
+end;
+
+function    capGetUserData(hwnd: HWND): DWORD;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_USER_DATA, 0, 0);
+end;
+
+function    capDriverConnect(hwnd: HWND; i: INT): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_CONNECT, i, 0) <> 0;
+end;
+
+function    capDriverDisconnect(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0) <> 0;
+end;
+
+function    capDriverGetName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_GET_NAME, wSize, LPARAM(szName)) <> 0;
+end;
+
+function    capDriverGetVersion(hwnd: HWND; szVer: LPSTR; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_GET_VERSION, wSize, LPARAM(szVer)) <> 0;
+end;
+
+function    capDriverGetCaps(hwnd: HWND; s: PCAPDRIVERCAPS; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DRIVER_GET_CAPS, wSize, LPARAM(s)) <> 0;
+end;
+
+function    capFileSetCaptureFile(hwnd: HWND; szName: LPCSTR): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_FILE_SET_CAPTURE_FILE, 0, LPARAM(szName)) <> 0;
+end;
+
+function    capFileGetCaptureFile(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_FILE_GET_CAPTURE_FILE, wSize, LPARAM(szName)) <> 0;
+end;
+
+function    capFileAlloc(hwnd: HWND; dwSize: DWORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_FILE_ALLOCATE, 0, dwSize) <> 0;
+end;
+
+function    capFileSaveAs(hwnd: HWND; szName: LPCSTR): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_FILE_SAVEAS, 0, LPARAM(szName)) <> 0;
+end;
+
+function    capFileSetInfoChunk(hwnd: HWND; lpInfoChunk: PCAPINFOCHUNK): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_FILE_SET_INFOCHUNK, 0, LPARAM(lpInfoChunk)) <> 0;
+end;
+
+function    capFileSaveDIB(hwnd: HWND; szName: LPCSTR): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_FILE_SAVEDIB, 0, LPARAM(szName)) <> 0;
+end;
+
+function    capEditCopy(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_EDIT_COPY, 0, 0) <> 0;
+end;
+
+function    capSetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_AUDIOFORMAT, wSize, LPARAM(s)) <> 0;
+end;
+
+function    capGetAudioFormat(hwnd: HWND; s: PWAVEFORMATEX; wSize: WORD): DWORD;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_AUDIOFORMAT, wSize, LPARAM(s));
+end;
+
+function    capGetAudioFormatSize(hwnd: HWND): DWORD;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_AUDIOFORMAT, 0, 0);
+end;
+
+function    capDlgVideoFormat(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEOFORMAT, 0, 0) <> 0;
+end;
+
+function    capDlgVideoSource(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEOSOURCE, 0, 0) <> 0;
+end;
+
+function    capDlgVideoDisplay(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEODISPLAY, 0, 0) <> 0;
+end;
+
+function    capDlgVideoCompression(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_DLG_VIDEOCOMPRESSION, 0, 0) <> 0;
+end;
+
+function    capGetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): DWORD;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, wSize, LPARAM(s));
+end;
+
+function    capGetVideoFormatSize(hwnd: HWND): DWORD;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, 0, 0);
+end;
+
+function    capSetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_VIDEOFORMAT, wSize, LPARAM(s)) <> 0;
+end;
+
+function    capPreview(hwnd: HWND; f: BOOL): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_PREVIEW, WPARAM(f), 0) <> 0;
+end;
+
+function    capPreviewRate(hwnd: HWND; wMS: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_PREVIEWRATE, wMS, 0) <> 0;
+end;
+
+function    capOverlay(hwnd: HWND; f: BOOL): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_OVERLAY, WPARAM(f), 0) <> 0;
+end;
+
+function    capPreviewScale(hwnd: HWND; f: BOOL): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_SCALE, WPARAM(f), 0) <> 0;
+end;
+
+function    capGetStatus(hwnd: HWND; s: PCAPSTATUS; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_STATUS, wSize, LPARAM(s)) <> 0;
+end;
+
+function    capSetScrollPos(hwnd: HWND; lpP: PPOINT): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_SCROLL, 0, LPARAM(lpP)) <> 0;
+end;
+
+function    capGrabFrame(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GRAB_FRAME, 0, 0) <> 0;
+end;
+
+function    capGrabFrameNoStop(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0) <> 0;
+end;
+
+function    capCaptureSequence(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SEQUENCE, 0, 0) <> 0;
+end;
+
+function    capCaptureSequenceNoFile(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SEQUENCE_NOFILE, 0, 0) <> 0;
+end;
+
+function    capCaptureStop(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_STOP, 0, 0) <> 0;
+end;
+
+function    capCaptureAbort(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_ABORT, 0, 0) <> 0;
+end;
+
+function    capCaptureSingleFrameOpen(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SINGLE_FRAME_OPEN, 0, 0) <> 0;
+end;
+
+function    capCaptureSingleFrameClose(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SINGLE_FRAME_CLOSE, 0, 0) <> 0;
+end;
+
+function    capCaptureSingleFrame(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SINGLE_FRAME, 0, 0) <> 0;
+end;
+
+function    capCaptureGetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_SEQUENCE_SETUP, wSize, LPARAM(s)) <> 0;
+end;
+
+function    capCaptureSetSetup(hwnd: HWND; s: PCAPTUREPARMS; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_SEQUENCE_SETUP, wSize, LPARAM(s)) <> 0;
+end;
+
+function    capSetMCIDeviceName(hwnd: HWND; szName: LPCSTR): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_SET_MCI_DEVICE, 0, LPARAM(szName)) <> 0;
+end;
+
+function    capGetMCIDeviceName(hwnd: HWND; szName: LPSTR; wSize: WORD): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_GET_MCI_DEVICE, wSize, LPARAM(szName)) <> 0;
+end;
+
+function    capPaletteOpen(hwnd: HWND; szName: LPCSTR): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_PAL_OPEN, 0, LPARAM(szName)) <> 0;
+end;
+
+function    capPaletteSave(hwnd: HWND; szName: LPCSTR): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_PAL_SAVE, 0, LPARAM(szName)) <> 0;
+end;
+
+function    capPalettePaste(hwnd: HWND): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_PAL_PASTE, 0, 0) <> 0;
+end;
+
+function    capPaletteAuto(hwnd: HWND; iFrames, iColors: INT): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_PAL_AUTOCREATE, iFrames, iColors) <> 0;
+end;
+
+function    capPaletteManual(hwnd: HWND; fGrab: BOOL; iColors: INT): BOOL;
+begin
+    Result  := AVICapSM(hwnd, WM_CAP_PAL_MANUALCREATE, WPARAM(fGrab), iColors) <> 0;
+end;
+
+{== Externals ================================================================}
+
+const
+    VFWDLL      = 'MSVFW32.DLL';
+    AVIFILDLL   = 'AVIFIL32.DLL';
+    AVICAPDLL   = 'AVICAP32.DLL';
+
+{-- Returns version of VFW ---------------------------------------------------}
+
+function    VideoForWindowsVersion: DWord; pascal; external VFWDLL;
+
+{-- Call these to start stop using VfW from your app -------------------------}
+
+{ TODO: Where are these functions? }
+                            {
+ function    InitVFW: LONG; stdcall;
+ function    TermVFW: LONG; stdcall; }
+
+{-- ICM function declarations ------------------------------------------------}
+
+function    ICInfo(fccType, fccHandler: DWORD; lpicinfo: PICINFO) : BOOL ; stdcall ; external VFWDLL;
+function    ICInstall(fccType, fccHandler: DWORD; lParam: LPARAM; szDesc: LPSTR; wFlags: UINT) : BOOL ; stdcall ; external VFWDLL;
+function    ICRemove(fccType, fccHandler: DWORD; wFlags: UINT) : BOOL ; stdcall ; external VFWDLL;
+function    ICGetInfo(hic: HIC; picinfo: PICINFO; cb: DWORD) : DWORD ; stdcall ; external VFWDLL;
+
+function    ICOpen(fccType, fccHandler: DWORD; wMode: UINT) : HIC ; stdcall ; external VFWDLL;
+function    ICOpenFunction(fccType, fccHandler: DWORD; wMode: UINT; lpfnHandler: TFarProc) : HIC ; stdcall ; external VFWDLL;
+function    ICClose(hic: HIC) : DWORD ; stdcall ; external VFWDLL;
+
+function    ICSendMessage(hic: HIC; msg: UINT; dw1, dw2: DWORD) : DWORD ; stdcall ; external VFWDLL;
+
+{== Compression functions ====================================================}
+
+{-- ICCompress() - compress a single frame -----------------------------------}
+
+function    ICCompress(
+    hic             : HIC;
+    dwFlags         : DWORD;                // flags
+    lpbiOutput      : PBITMAPINFOHEADER;    // output format
+    lpData          : PVOID;                // output data
+    lpbiInput       : PBITMAPINFOHEADER;    // format of frame to compress
+    lpBits          : PVOID;                // frame data to compress
+    lpckid          : PDWORD;               // ckid for data in AVI file
+    lpdwFlags       : PDWORD;               // flags in the AVI index.
+    lFrameNum       : DWORD;                 // frame number of seq.
+    dwFrameSize     : DWORD;                // reqested size in bytes. (if non zero)
+    dwQuality       : DWORD;                // quality within one frame
+    lpbiPrev        : PBITMAPINFOHEADER;    // format of previous frame
+    lpPrev          : PVOID                 // previous frame
+    ) : DWORD; cdecl; external VFWDLL;
+
+{== Decompression functions ==================================================}
+
+{-- ICDecompress() - decompress a single frame -------------------------------}
+
+function    ICDecompress(
+    hic             : HIC;
+    dwFlags         : DWORD;                // flags (from AVI index...)
+    lpbiFormat      : PBITMAPINFOHEADER;    // BITMAPINFO of compressed data
+                                            // biSizeImage has the chunk size
+    lpData          : PVOID;                // data
+    lpbi            : PBITMAPINFOHEADER;    // DIB to decompress to
+    lpBits          : PVOID
+    ): DWORD; cdecl; external VFWDLL;
+
+{== Drawing functions ========================================================}
+
+{-- ICDrawBegin() - start decompressing data with fmt directly to screen -----}
+
+// return zero if the decompressor supports drawing.
+
+function    ICDrawBegin(
+    hic         : HIC;
+    dwFlags     : DWORD;                // flags
+    hpal        : HPALETTE;             // palette to draw with
+    hwnd        : HWND;                 // window to draw to
+    hdc         : HDC;                  // HDC to draw to
+    xDst        : int;                  // destination rectangle
+    yDst        : int;
+    dxDst       : int;
+    dyDst       : int;
+    lpbi        : PBITMAPINFOHEADER;    // format of frame to draw
+    xSrc        : int;                  // source rectangle
+    ySrc        : int;
+    dxSrc       : int;
+    dySrc       : int;
+    dwRate      : DWORD;                // frames/second = (dwRate/dwScale)
+    dwScale     : DWORD
+    ): DWORD; cdecl; external VFWDLL;
+
+{-- ICDraw() - decompress data directly to the screen ------------------------}
+
+function    ICDraw(
+    hic         : HIC;
+    dwFlags     : DWORD;                // flags
+    lpFormat    : PVOID;                // format of frame to decompress
+    lpData      : PVOID;                // frame data to decompress
+    cbData      : DWORD;                // size of data
+    lTime       : DWORD                  // time to draw this frame
+    ): DWORD; cdecl; external VFWDLL;
+
+{== Helper routines for DrawDib and MCIAVI... ================================}
+
+function    ICLocate(fccType, fccHandler: DWORD; lpbiIn, lpbiOut: PBITMAPINFOHEADER; wFlags: WORD): HIC; stdcall; external VFWDLL;
+function    ICGetDisplayFormat(hic: HIC; lpbiIn, lpbiOut: PBITMAPINFOHEADER; BitDepth: int; dx, dy: int): HIC; stdcall; external VFWDLL;
+
+{== Higher level functions ===================================================}
+
+function    ICImageCompress(
+    hic         : HIC;                  // compressor to use
+    uiFlags     : UINT;                 // flags (none yet)
+    lpbiIn      : PBITMAPINFO;          // format to compress from
+    lpBits      : PVOID;                // data to compress
+    lpbiOut     : PBITMAPINFO;          // compress to this (NULL ==> default)
+    lQuality    : LONG;                 // quality to use
+    plSize      : PDWORD                 // compress to this size (0=whatever)
+    ): THANDLE; stdcall; external VFWDLL;
+
+function    ICImageDecompress(
+    hic         : HIC;                  // compressor to use
+    uiFlags     : UINT;                 // flags (none yet)
+    lpbiIn      : PBITMAPINFO;          // format to decompress from
+    lpBits      : PVOID;                // data to decompress
+    lpbiOut     : PBITMAPINFO           // decompress to this (NULL ==> default)
+    ): THANDLE; stdcall; external VFWDLL;
+
+{-- ICCompressorChoose() - allows user to choose compressor, quality etc... --}
+
+function    ICCompressorChoose(
+    hwnd        : HWND;                     // parent window for dialog
+    uiFlags     : UINT;                     // flags
+    pvIn        : PVOID;                    // input format (optional)
+    lpData      : PVOID;                    // input data (optional)
+    pc          : PCOMPVARS;                // data about the compressor/dlg
+    lpszTitle   : LPSTR                     // dialog title (optional)
+    ): BOOL; stdcall; external VFWDLL;
+
+function    ICSeqCompressFrameStart(pc: PCOMPVARS; lpbiIn: PBITMAPINFO): BOOL; stdcall; external VFWDLL;
+procedure   ICSeqCompressFrameEnd(pc: PCOMPVARS); stdcall; external VFWDLL;
+
+function    ICSeqCompressFrame(
+    pc          : PCOMPVARS;                // set by ICCompressorChoose
+    uiFlags     : UINT;                     // flags
+    lpBits      : PVOID;                    // input DIB bits
+    pfKey       : PBOOL;                    // did it end up being a key frame?
+    plSize      : PDWORD                     // size to compress to/of returned image
+    ): PVOID; stdcall; external VFWDLL;
+
+procedure   ICCompressorFree(pc: PCOMPVARS); stdcall; external VFWDLL;
+
+{== DrawDib functions ========================================================}
+
+{-- DrawDibOpen() ------------------------------------------------------------}
+
+function    DrawDibOpen: HDRAWDIB; stdcall; external VFWDLL;
+
+{-- DrawDibClose() -----------------------------------------------------------}
+
+function    DrawDibClose(hdd: HDRAWDIB): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibGetBuffer() -------------------------------------------------------}
+
+function    DrawDibGetBuffer(hdd: HDRAWDIB; lpbi: PBITMAPINFOHEADER; dwSize: DWORD; dwFlags: DWORD): PVOID; stdcall; external VFWDLL;
+
+{-- DrawDibGetPalette() - get the palette used for drawing DIBs --------------}
+
+function    DrawDibGetPalette(hdd: HDRAWDIB): HPALETTE; stdcall; external VFWDLL;
+
+{-- DrawDibSetPalette() - set the palette used for drawing DIBs --------------}
+
+function    DrawDibSetPalette(hdd: HDRAWDIB; hpal: HPALETTE): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibChangePalette() ---------------------------------------------------}
+
+function    DrawDibChangePalette(hdd: HDRAWDIB; iStart, iLen: int; lppe: PPALETTEENTRY): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibRealize() - realize the palette in a HDD --------------------------}
+
+function    DrawDibRealize(hdd: HDRAWDIB; hdc: HDC; fBackground: BOOL): UINT; stdcall; external VFWDLL;
+
+{-- DrawDibStart() - start of streaming playback -----------------------------}
+
+function    DrawDibStart(hdd: HDRAWDIB; rate: DWORD): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibStop() - start of streaming playback ------------------------------}
+
+function    DrawDibStop(hdd: HDRAWDIB): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibBegin() - prepare to draw -----------------------------------------}
+
+function    DrawDibBegin(
+    hdd         : HDRAWDIB;
+    hdc         : HDC;
+    dxDst       : int;
+    dyDst       : int;
+    lpbi        : PBITMAPINFOHEADER;
+    dxSrc       : int;
+    dySrc       : int;
+    wFlags      : UINT
+    ): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibDraw() - actually draw a DIB to the screen ------------------------}
+
+function    DrawDibDraw(
+    hdd         : HDRAWDIB;
+    hdc         : HDC;
+    xDst        : int;
+    yDst        : int;
+    dxDst       : int;
+    dyDst       : int;
+    lpbi        : PBITMAPINFOHEADER;
+    lpBits      : PVOID;
+    xSrc        : int;
+    ySrc        : int;
+    dxSrc       : int;
+    dySrc       : int;
+    wFlags      : UINT
+    ): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibEnd() -------------------------------------------------------------}
+
+function    DrawDibEnd(hdd: HDRAWDIB): BOOL; stdcall; external VFWDLL;
+
+{-- DrawDibTime() - for debugging purposes only ------------------------------}
+
+function    DrawDibTime(hdd: HDRAWDIB; lpddtime: PDRAWDIBTIME): BOOL; stdcall; external VFWDLL;
+
+{-- Display profiling --------------------------------------------------------}
+
+function    DrawDibProfileDisplay(lpbi: PBITMAPINFOHEADER): DWORD; stdcall; external VFWDLL;
+
+{-- Functions ----------------------------------------------------------------}
+
+procedure   AVIFileInit; stdcall; external AVIFILDLL; // Call this first!
+procedure   AVIFileExit; stdcall; external AVIFILDLL;
+
+function    AVIFileAddRef(pfile: IAVIFILE): ULONG; stdcall; external AVIFILDLL;
+function    AVIFileRelease(pfile: IAVIFILE): ULONG; stdcall; external AVIFILDLL;
+
+function    AVIFileOpenA(var ppfile: IAVIFILE; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
+function    AVIFileOpenW(var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
+
+{$IFDEF UNICODE}
+function    AVIFileOpen(var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;  external AVIFILDLL name 'AVIFileOpenW';
+{$ELSE}
+function    AVIFileOpen(var ppfile: IAVIFILE; szFile: LPCSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall;  external AVIFILDLL name 'AVIFileOpenA';
+{$ENDIF}
+
+function    AVIFileInfoW(pfile: IAVIFILE; var pfi: TAVIFILEINFOW; lSize: LONG): HResult; stdcall; external AVIFILDLL;
+function    AVIFileInfoA(pfile: IAVIFILE; var pfi: TAVIFILEINFOA; lSize: LONG): HResult; stdcall; external AVIFILDLL;
+
+{$IFDEF UNICODE}
+function    AVIFileInfo(pfile: IAVIFILE; var pfi: TAVIFILEINFO; lSize: LONG): HResult; stdcall;  external AVIFILDLL name 'AVIFileInfoW';
+{$ELSE}
+function    AVIFileInfo(pfile: IAVIFILE; var pfi: TAVIFILEINFO; lSize: LONG): HResult; stdcall;  external AVIFILDLL name 'AVIFileInfoA';
+{$ENDIF}
+
+function    AVIFileGetStream(pfile: IAVIFILE; var ppavi: IAVISTREAM; fccType: DWORD; lParam: LONG): HResult; stdcall; external AVIFILDLL;
+
+function    AVIFileCreateStreamW(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOW): HResult; stdcall; external AVIFILDLL;
+function    AVIFileCreateStreamA(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFOA): HResult; stdcall; external AVIFILDLL;
+
+{$IFDEF UNICODE}
+function    AVIFileCreateStream(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFO): HResult; stdcall; external AVIFILDLL name 'AVIFileCreateStreamW';
+{$ELSE}
+function    AVIFileCreateStream(pfile: IAVIFILE; var ppavi: IAVISTREAM; var psi: TAVISTREAMINFO): HResult; stdcall; external AVIFILDLL name 'AVIFileCreateStreamA';
+{$ENDIF}
+
+function    AVIFileWriteData(pfile: IAVIFILE; ckid: DWORD; lpData: PVOID; cbData: LONG): HResult; stdcall; external AVIFILDLL;
+function    AVIFileReadData(pfile: IAVIFILE; ckid: DWORD; lpData: PVOID; var lpcbData: LONG): HResult; stdcall; external AVIFILDLL;
+function    AVIFileEndRecord(pfile: IAVIFILE): HResult; stdcall; external AVIFILDLL;
+
+function    AVIStreamAddRef(pavi: IAVISTREAM): ULONG; stdcall; external AVIFILDLL;
+function    AVIStreamRelease(pavi: IAVISTREAM): ULONG; stdcall; external AVIFILDLL;
+
+function    AVIStreamInfoW (pavi: IAVISTREAM; var psi: TAVISTREAMINFOW; lSize: LONG): HResult; stdcall; external AVIFILDLL;
+function    AVIStreamInfoA (pavi: IAVISTREAM; var psi: TAVISTREAMINFOA; lSize: LONG): HResult; stdcall; external AVIFILDLL;
+
+{$IFDEF UNICODE}
+function    AVIStreamInfo(pavi: IAVISTREAM; var psi: TAVISTREAMINFO; lSize: LONG): HResult; stdcall; external AVIFILDLL name 'AVIStreamInfoW';
+{$ELSE}
+function    AVIStreamInfo(pavi: IAVISTREAM; var psi: TAVISTREAMINFO; lSize: LONG): HResult; stdcall; external AVIFILDLL name 'AVIStreamInfoA';
+{$ENDIF}
+
+
+function    AVIStreamFindSample(pavi: IAVISTREAM; lPos: LONG; lFlags: LONG): LONG; stdcall; external AVIFILDLL;
+function    AVIStreamReadFormat(pavi: IAVISTREAM; lPos: LONG; lpFormat: PVOID; lpcbFormat: PLONG): HResult; stdcall; external AVIFILDLL;
+function    AVIStreamSetFormat(pavi: IAVISTREAM; lPos: LONG; lpFormat: PVOID; cbFormat: LONG): HResult; stdcall; external AVIFILDLL;
+function    AVIStreamReadData(pavi: IAVISTREAM; fcc: DWORD; lp: PVOID; lpcb: PLONG): HResult; stdcall; external AVIFILDLL;
+function    AVIStreamWriteData(pavi: IAVISTREAM; fcc: DWORD; lp: PVOID; cb: LONG): HResult; stdcall; external AVIFILDLL;
+
+function    AVIStreamRead(
+    pavi            : IAVISTREAM;
+    lStart          : LONG;
+    lSamples        : LONG;
+    lpBuffer        : PVOID;
+    cbBuffer        : LONG;
+    plBytes         : PLONG;
+    plSamples       : PLONG
+    ): HResult; stdcall; external AVIFILDLL;
+
+function    AVIStreamWrite(
+    pavi            : IAVISTREAM;
+    lStart          : LONG;
+    lSamples        : LONG;
+    lpBuffer        : PVOID;
+    cbBuffer        : LONG;
+    dwFlags         : DWORD;
+    plSampWritten   : PLONG;
+    plBytesWritten  : PLONG
+    ): HResult; stdcall; external AVIFILDLL;
+
+// Right now, these just use AVIStreamInfo() to get information, then
+// return some of it.  Can they be more efficient?
+
+function    AVIStreamStart(pavi: IAVISTREAM): LONG; stdcall; external AVIFILDLL;
+function    AVIStreamLength(pavi: IAVISTREAM): LONG; stdcall; external AVIFILDLL;
+function    AVIStreamTimeToSample(pavi: IAVISTREAM; lTime: LONG): LONG; stdcall; external AVIFILDLL;
+function    AVIStreamSampleToTime(pavi: IAVISTREAM; lSample: LONG): LONG; stdcall; external AVIFILDLL;
+
+function    AVIStreamBeginStreaming(pavi: IAVISTREAM; lStart, lEnd: LONG; lRate: LONG): HResult; stdcall; external AVIFILDLL;
+function    AVIStreamEndStreaming(pavi: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
+
+{-- Helper functions for using IGetFrame -------------------------------------}
+
+function    AVIStreamGetFrameOpen_(pavi: IAVISTREAM; lpbiWanted: PBitmapInfoHeader): pointer; stdcall; external AVIFILDLL name 'AVIStreamGetFrameOpen';
+function    AVIStreamGetFrame(pg: IGETFRAME; lPos: LONG): PBitmapInfoHeader; stdcall; external AVIFILDLL;
+function    AVIStreamGetFrameClose(pg: IGETFRAME): HResult; stdcall; external AVIFILDLL;
+
+function    AVIStreamGetFrameOpen(pavi: IAVIStream; lpbiWanted: PBitmapInfoHeader): IGetFrame; stdcall;
+begin
+  pointer(Result) := AVIStreamGetFrameOpen_(pavi, lpbiWanted);
+end;
+
+// !!! We need some way to place an advise on a stream....
+// STDAPI AVIStreamHasChanged   (PAVISTREAM pavi);
+
+{-- Shortcut function --------------------------------------------------------}
+
+function    AVIStreamOpenFromFileA(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
+                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
+function    AVIStreamOpenFromFileW(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
+                                   lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
+
+{$IFDEF UNICODE}
+function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCWSTR; fccType: DWORD;
+  lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL name 'AVIStreamOpenFromFileW';
+{$ELSE}
+function AVIStreamOpenFromFile(var ppavi: IAVISTREAM; szFile: LPCSTR; fccType: DWORD;
+  lParam: LONG; mode: UINT; pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL name 'AVIStreamOpenFromFileA';
+{$ENDIF}
+
+{-- Use to create disembodied streams ----------------------------------------}
+
+function    AVIStreamCreate(var ppavi: IAVISTREAM; lParam1, lParam2: LONG;
+                            pclsidHandler: PCLSID): HResult; stdcall; external AVIFILDLL;
+
+// PHANDLER    AVIAPI AVIGetHandler         (PAVISTREAM pavi, PAVISTREAMHANDLER psh);
+// PAVISTREAM  AVIAPI AVIGetStream          (PHANDLER p);
+
+{-- Stuff to support backward compat. ----------------------------------------}
+
+function    AVIStreamFindKeyFrame(var pavi: IAVISTREAM; lPos: LONG; lFlags: LONG): DWORD; stdcall; external AVIFILDLL name 'AVIStreamFindSample';
+
+// Non-portable: this is alias for method name
+// FindKeyFrame FindSample
+
+function    AVIStreamClose(pavi: IAVISTREAM): ULONG; stdcall; external AVIFILDLL name 'AVIStreamRelease';
+function    AVIFileClose(pfile: IAVIFILE): ULONG; stdcall; external AVIFILDLL name 'AVIFileRelease';
+procedure   AVIStreamInit; stdcall; external AVIFILDLL name 'AVIFileInit';
+procedure   AVIStreamExit; stdcall; external AVIFILDLL name 'AVIFileExit';
+
+{== AVISave routines and structures ==========================================}
+
+function    AVIMakeCompressedStream(
+    var ppsCompressed   : IAVISTREAM;
+    ppsSource           : IAVISTREAM;
+    lpOptions           : PAVICOMPRESSOPTIONS;
+    pclsidHandler       : PCLSID
+    ): HResult; stdcall; external AVIFILDLL;
+
+// Non-portable: uses variable number of params
+// EXTERN_C HRESULT CDECL AVISaveA (LPCSTR               szFile,
+//      CLSID FAR *pclsidHandler,
+//      AVISAVECALLBACK     lpfnCallback,
+//      int                 nStreams,
+//      PAVISTREAM      pfile,
+//      LPAVICOMPRESSOPTIONS lpOptions,
+//      ...);
+
+function    AVISaveVA(
+    szFile          : LPCSTR;
+    pclsidHandler   : PCLSID;
+    lpfnCallback    : TAVISAVECALLBACK;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): HResult; stdcall; external AVIFILDLL;
+
+// Non-portable: uses variable number of params
+// EXTERN_C HRESULT CDECL AVISaveW (LPCWSTR               szFile,
+//      CLSID FAR *pclsidHandler,
+//      AVISAVECALLBACK     lpfnCallback,
+//      int                 nStreams,
+//      PAVISTREAM      pfile,
+//      LPAVICOMPRESSOPTIONS lpOptions,
+//      ...);
+
+function    AVISaveVW(
+    szFile          : LPCWSTR;
+    pclsidHandler   : PCLSID;
+    lpfnCallback    : TAVISAVECALLBACK;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): HResult; stdcall; external AVIFILDLL;
+
+// #define AVISave      AVISaveA
+
+function    AVISaveV(
+    szFile          : LPCSTR;
+    pclsidHandler   : PCLSID;
+    lpfnCallback    : TAVISAVECALLBACK;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): HResult; stdcall; external AVIFILDLL name 'AVISaveVA';
+
+function    AVISaveOptions(
+    hwnd            : HWND;
+    uiFlags         : UINT;
+    nStreams        : int;
+    var ppavi       : IAVISTREAM;
+    var plpOptions  : PAVICOMPRESSOPTIONS
+    ): BOOL; stdcall; external AVIFILDLL;
+
+function    AVISaveOptionsFree(nStreams: int; var plpOptions: PAVICOMPRESSOPTIONS): HResult; stdcall; external AVIFILDLL;
+
+{-----------------------------------------------------------------------------}
+
+function    AVIBuildFilterW(lpszFilter: LPWSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; external AVIFILDLL;
+function    AVIBuildFilterA(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; external AVIFILDLL;
+
+function    AVIBuildFilter(lpszFilter: LPSTR; cbFilter: LONG; fSaving: BOOL): HResult; stdcall; external AVIFILDLL name 'AVIBuildFilterA';
+
+function    AVIMakeFileFromStreams(var ppfile: IAVIFILE; nStreams: int; var papStreams: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
+
+function    AVIMakeStreamFromClipboard(cfFormat: UINT; hGlobal: THANDLE; var ppstream: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
+
+{-- Clipboard routines -------------------------------------------------------}
+
+function    AVIPutFileOnClipboard(pf: IAVIFILE): HResult; stdcall; external AVIFILDLL;
+function    AVIGetFromClipboard(var lppf: IAVIFILE): HResult; stdcall; external AVIFILDLL;
+function    AVIClearClipboard: HResult; stdcall; external AVIFILDLL;
+
+{-- Editing routines ---------------------------------------------------------}
+
+function    CreateEditableStream(var ppsEditable: IAVISTREAM; psSource: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
+
+function    EditStreamCut(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
+function    EditStreamCopy(pavi: IAVISTREAM; var plStart, plLength: LONG; var ppResult: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
+function    EditStreamPaste(pavi: IAVISTREAM; var plPos, plLength: LONG; pstream: IAVISTREAM; lStart, lEnd: LONG): HResult; stdcall; external AVIFILDLL;
+function    EditStreamClone(pavi: IAVISTREAM; var ppResult: IAVISTREAM): HResult; stdcall; external AVIFILDLL;
+
+function    EditStreamSetNameA(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall; external AVIFILDLL;
+function    EditStreamSetNameW(pavi: IAVISTREAM; lpszName: LPCWSTR): HResult; stdcall; external AVIFILDLL;
+function    EditStreamSetInfoW(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOW; cbInfo: LONG): HResult; stdcall; external AVIFILDLL;
+function    EditStreamSetInfoA(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall; external AVIFILDLL;
+
+function    EditStreamSetInfo(pavi: IAVISTREAM; lpInfo: PAVISTREAMINFOA; cbInfo: LONG): HResult; stdcall; external AVIFILDLL name 'EditStreamSetInfoA';
+function    EditStreamSetName(pavi: IAVISTREAM; lpszName: LPCSTR): HResult; stdcall; external AVIFILDLL name 'EditStreamSetNameA';
+
+{-- MCIWnd -------------------------------------------------------------------}
+
+function    MCIWndCreateA(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl; external VFWDLL;
+function    MCIWndCreateW(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCWSTR): HWND; cdecl; external VFWDLL;
+
+function    MCIWndCreate(hwndParent: HWND; hInstance: HINST; dwStyle: DWORd; szFile: LPCSTR): HWND; cdecl;  external VFWDLL name 'MCIWndCreateA';
+
+function    MCIWndRegisterClass: BOOL; cdecl; external VFWDLL;
+
+{== AVICAP - Window class for AVI capture ====================================}
+
+{-- The only exported functions from AVICAP.DLL ------------------------------}
+
+function    capCreateCaptureWindowA(
+    lpszWindowName      : LPCSTR;
+    dwStyle             : DWORD;
+    x, y                : int;
+    nWidth, nHeight     : int;
+    hwndParent          : HWND;
+    nID                 : int
+    ): HWND; stdcall; external AVICAPDLL;
+
+function    capGetDriverDescriptionA(
+    wDriverIndex        : UINT;
+    lpszName            : LPSTR;
+    cbName              : int;
+    lpszVer             : LPSTR;
+    cbVer               : int
+    ): BOOL; stdcall; external AVICAPDLL;
+
+function    capCreateCaptureWindowW(
+    lpszWindowName      : LPCWSTR;
+    dwStyle             : DWORD;
+    x, y                : int;
+    nWidth, nHeight     : int;
+    hwndParent          : HWND;
+    nID                 : int
+    ): HWND; stdcall; external AVICAPDLL;
+
+function    capGetDriverDescriptionW(
+    wDriverIndex        : UINT;
+    lpszName            : LPWSTR;
+    cbName              : int;
+    lpszVer             : LPWSTR;
+    cbVer               : int
+    ): BOOL; stdcall; external AVICAPDLL;
+
+function    capCreateCaptureWindow(
+    lpszWindowName      : LPCSTR;
+    dwStyle             : DWORD;
+    x, y                : int;
+    nWidth, nHeight     : int;
+    hwndParent          : HWND;
+    nID                 : int
+    ): HWND; stdcall; external AVICAPDLL name 'capCreateCaptureWindowA';
+
+function    capGetDriverDescription(
+    wDriverIndex        : UINT;
+    lpszName            : LPSTR;
+    cbName              : int;
+    lpszVer             : LPSTR;
+    cbVer               : int
+    ): BOOL; stdcall; external AVICAPDLL name 'capGetDriverDescriptionA';
+
+{== FilePreview dialog =======================================================}
+
+function GetOpenFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL;
+function GetSaveFileNamePreviewA(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL;
+
+function GetOpenFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall; external VFWDLL;
+function GetSaveFileNamePreviewW(lpofn: POPENFILENAMEW): BOOL; stdcall; external VFWDLL;
+
+function GetOpenFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL name 'GetOpenFileNamePreviewA';
+function GetSaveFileNamePreview(lpofn: POPENFILENAMEA): BOOL; stdcall; external VFWDLL name 'GetSaveFileNamePreviewA';
+
+end.

+ 1 - 1
Source/FileX.pas → Source/Formats.FileX.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit FileX;
+unit Formats.FileX;
 
 (* Simple X format support for Delphi (Microsoft's favorite format) *)
 

+ 1 - 1
Source/GLAVIRecorder.pas

@@ -12,7 +12,7 @@ interface
 
 uses
   Winapi.Windows, 
-  WinApi.Messages,
+  Winapi.Messages,
   System.Classes, 
   System.SysUtils, 
   System.UITypes,

+ 2 - 1
Source/GLBaseClasses.pas

@@ -62,7 +62,7 @@ type
     procedure DoProgress(const progressTime: TGLProgressTimes); virtual;
   end;
 
-  // A base class describing the "update" interface.  
+  // A base class describing the "update" interface.
   TGLUpdateAbleComponent = class(TGLCadenceAbleComponent, IGLNotifyAble)
   public
     procedure NotifyChange(Sender: TObject); virtual;
@@ -170,3 +170,4 @@ end;
 
 end.
 
+

+ 3 - 4
Source/GLCrossPlatform.pas

@@ -11,13 +11,12 @@ interface
 {$I GLScene.inc}
 
 uses
-  Windows,
+  Winapi.Windows,
 
   System.Types,
   System.Classes,
   System.SysUtils,
   System.StrUtils,
-  VCL.Consts,
   VCL.Graphics,
   VCL.Controls,
   VCL.Forms,
@@ -288,12 +287,12 @@ end;
 
 procedure QueryPerformanceCounter(out val: Int64);
 begin
-  Windows.QueryPerformanceCounter(val);
+  Winapi.Windows.QueryPerformanceCounter(val);
 end;
 
 function QueryPerformanceFrequency(out val: Int64): Boolean;
 begin
-  Result := Boolean(Windows.QueryPerformanceFrequency(val));
+  Result := Boolean(Winapi.Windows.QueryPerformanceFrequency(val));
 end;
 
 function StartPrecisionTimer: Int64;

+ 1 - 1
Source/GLFileLWO.pas

@@ -16,7 +16,7 @@ uses
   System.Math,
   GLVectorFileObjects,
   Scene.VectorLists,
-  FileLWObjects;
+  Formats.FileLWObjects;
 
 type
   TGLLWOVectorFile = class(TGLVectorFile)

+ 1 - 1
Source/GLFileX.pas

@@ -23,7 +23,7 @@ uses
   GLMaterial,
 
   // Misc
-  FileX;
+  Formats.FileX;
 
 type
   TGLXVectorFile = class(TGLVectorFile)

+ 505 - 0
Source/GLS.AVIRecorder.pas

@@ -0,0 +1,505 @@
+//
+// This unit is part of the GLScene Engine, http://glscene.org
+//
+
+unit GLS.AVIRecorder;
+
+(* Component to make it easy to record GLScene frames into an AVI file *)
+
+interface
+
+{$I GLScene.inc}
+
+uses
+  Winapi.Windows,
+  System.Classes,
+  System.SysUtils, 
+  System.UITypes,
+  VCL.Controls, 
+  VCL.Forms, 
+  VCL.Extctrls, 
+  VCL.Graphics, 
+  VCL.Dialogs,
+   
+  Formats.FileVFW,
+
+  GLGraphics,
+  GLScene,
+  GLSceneViewer;
+
+type
+  TAVICompressor = (acDefault, acShowDialog, acDivX);
+
+  PAVIStream = ^IAVIStream;
+
+  (*Frame size restriction. 
+    Forces frame dimensions to be a multiple of 2, 4, or 8. Some compressors
+    require this. e.g. DivX 5.2.1 requires mutiples of 2. *)
+  TAVISizeRestriction = (srNoRestriction, srForceBlock2x2, srForceBlock4x4,
+    srForceBlock8x8);
+
+  TAVIRecorderState = (rsNone, rsRecording);
+
+  (* Image retrieval mode for frame capture. 
+     Following modes are supported: 
+     irmSnapShot : retrieve OpenGL framebuffer content using glReadPixels
+     irmRenderToBitmap : renders the whole scene to a bitmap, this is
+     the slowest mode, but it won't be affected by driver-side specifics.
+     irmBitBlt : tranfers the framebuffer using the BitBlt function,
+     usually the fastest solution *)
+  TAVIImageRetrievalMode = (irmSnapShot, irmRenderToBitmap, irmBitBlt);
+
+  TAVIRecorderPostProcessEvent = procedure(Sender: TObject; frame: TBitmap)
+    of object;
+
+  // Component to make it easy to record GLScene frames into an AVI file. 
+  TGLAVIRecorder = class(TComponent)
+  private
+    AVIBitmap: TBitmap;
+    AVIFrameIndex: integer;
+    AVI_DPI: integer;
+    asi: TAVIStreamInfo;
+    pfile: IAVIFile;
+    Stream, Stream_c: IAVIStream; // AVI stream and stream to be compressed
+    FBitmapInfo: PBitmapInfoHeader;
+    FBitmapBits: Pointer;
+    FBitmapSize: Dword;
+    FTempName: String;
+    // so that we know the filename to delete case of user abort
+    FAVIFilename: string;
+    FFPS: byte;
+    FWidth: integer;
+    FHeight: integer;
+    FSizeRestriction: TAVISizeRestriction;
+    FImageRetrievalMode: TAVIImageRetrievalMode;
+    RecorderState: TAVIRecorderState;
+    FOnPostProcessEvent: TAVIRecorderPostProcessEvent;
+    FBuffer: TGLSceneBuffer;
+    procedure SetHeight(const val: integer);
+    procedure SetWidth(const val: integer);
+    procedure SetSizeRestriction(const val: TAVISizeRestriction);
+    procedure SetGLSceneViewer(const Value: TGLSceneViewer);
+    procedure SetGLNonVisualViewer(const Value: TGLNonVisualViewer);
+  protected
+    // Maybe we should make a generic TGLAVIRecorder, and then use sub-class of it 
+    FGLSceneViewer: TGLSceneViewer;
+    // FGLNonVisualViewer accepts GLNonVisualViewer and GLFullScreenViewer
+    FGLNonVisualViewer: TGLNonVisualViewer;
+    (* FCompressor determines if the user is to choose a compressor via a dialog box, or
+      just use a default compressor without showing a dialog box. *)
+    FCompressor: TAVICompressor;
+    (* Some video compressor assumes input dimensions to be multiple of 2, 4 or 8.
+       Restricted() is for rounding off the width and height.
+       Currently I can't find a simple way to know which compressor imposes
+       what resiction, so the SizeRestiction property is there for the user to set.
+       The source code of VirtualDub (http://www.virtualdub.org/)
+       may give us some cues on this.
+       ( BTW, VirtualDub is an excellent freeware for editing your AVI. For
+       converting AVI into MPG, try AVI2MPG1 - http://www.mnsi.net/~jschlic1 *)
+    function Restricted(s: integer): integer;
+    procedure InternalAddAVIFrame;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    function CreateAVIFile(DPI: integer = 0): boolean;
+    procedure AddAVIFrame; overload;
+    procedure AddAVIFrame(bmp: TBitmap); overload;
+    procedure CloseAVIFile(UserAbort: boolean = false);
+    function Recording: boolean;
+  published
+    property FPS: byte read FFPS write FFPS default 25;
+    property GLSceneViewer: TGLSceneViewer read FGLSceneViewer
+      write SetGLSceneViewer;
+    property GLNonVisualViewer: TGLNonVisualViewer read FGLNonVisualViewer
+      write SetGLNonVisualViewer;
+    property Width: integer read FWidth write SetWidth;
+    property Height: integer read FHeight write SetHeight;
+    property Filename: String read FAVIFilename write FAVIFilename;
+    property Compressor: TAVICompressor read FCompressor write FCompressor
+      default acDefault;
+    property SizeRestriction: TAVISizeRestriction read FSizeRestriction
+      write SetSizeRestriction default srForceBlock8x8;
+    property ImageRetrievalMode: TAVIImageRetrievalMode read FImageRetrievalMode
+      write FImageRetrievalMode default irmBitBlt;
+    property OnPostProcessEvent: TAVIRecorderPostProcessEvent
+      read FOnPostProcessEvent write FOnPostProcessEvent;
+  end;
+
+// ---------------------------------------------------------------------
+implementation
+// ---------------------------------------------------------------------
+
+// DIB support rountines for AVI output
+
+procedure InitializeBitmapInfoHeader(Bitmap: HBITMAP;
+  var BI: TBitmapInfoHeader);
+var
+  BM: Winapi.Windows.TBitmap;
+begin
+  GetObject(Bitmap, SizeOf(BM), @BM);
+  with BI do
+  begin
+    biSize := SizeOf(BI);
+    biWidth := BM.bmWidth;
+    biHeight := BM.bmHeight;
+    biPlanes := 1;
+    biXPelsPerMeter := 0;
+    biYPelsPerMeter := 0;
+    biClrUsed := 0;
+    biClrImportant := 0;
+    biCompression := BI_RGB;
+    biBitCount := 24;
+    // force 24 bits. Most video compressors would deal with 24-bit frames only.
+    biSizeImage := (((biWidth * biBitCount) + 31) div 32) * 4 * biHeight;
+  end;
+end;
+
+procedure InternalGetDIBSizes(Bitmap: HBITMAP; var InfoHeaderSize: integer;
+  var ImageSize: Dword);
+var
+  BI: TBitmapInfoHeader;
+begin
+  InitializeBitmapInfoHeader(Bitmap, BI);
+  InfoHeaderSize := SizeOf(TBitmapInfoHeader);
+  ImageSize := BI.biSizeImage;
+end;
+
+function InternalGetDIB(Bitmap: HBITMAP; var bitmapInfo; var bits): boolean;
+var
+  focus: HWND;
+  dc: HDC;
+  errCode: integer;
+begin
+  InitializeBitmapInfoHeader(Bitmap, TBitmapInfoHeader(bitmapInfo));
+  focus := GetFocus;
+  dc := GetDC(focus);
+  try
+    errCode := GetDIBits(dc, Bitmap, 0, TBitmapInfoHeader(bitmapInfo).biHeight,
+      @bits, TBitmapInfo(bitmapInfo), DIB_RGB_COLORS);
+    Result := (errCode <> 0);
+  finally
+    ReleaseDC(focus, dc);
+  end;
+end;
+
+// ------------------
+// ------------------ TAVIRecorder ------------------
+// ------------------
+
+constructor TGLAVIRecorder.Create(AOwner: TComponent);
+begin
+  inherited;
+  FWidth := 320; // default values
+  FHeight := 200;
+  FFPS := 25;
+  FCompressor := acDefault;
+  RecorderState := rsNone;
+  FSizeRestriction := srForceBlock8x8;
+  FImageRetrievalMode := irmBitBlt;
+end;
+
+destructor TGLAVIRecorder.Destroy;
+begin
+  // if still open here, abort it
+  if RecorderState = rsRecording then
+    CloseAVIFile(True);
+  inherited;
+end;
+
+function TGLAVIRecorder.Restricted(s: integer): integer;
+begin
+  case FSizeRestriction of
+    srForceBlock2x2:
+      Result := (s div 2) * 2;
+    srForceBlock4x4:
+      Result := (s div 4) * 4;
+    srForceBlock8x8:
+      Result := (s div 8) * 8;
+  else
+    Result := s;
+  end;
+end;
+
+procedure TGLAVIRecorder.SetHeight(const val: integer);
+begin
+  if (RecorderState <> rsRecording) and (val <> FHeight) and (val > 0) then
+    FHeight := Restricted(val);
+end;
+
+procedure TGLAVIRecorder.SetWidth(const val: integer);
+begin
+  if (RecorderState <> rsRecording) and (val <> FWidth) and (val > 0) then
+    FWidth := Restricted(val);
+end;
+
+procedure TGLAVIRecorder.SetSizeRestriction(const val: TAVISizeRestriction);
+begin
+  if val <> FSizeRestriction then
+  begin
+    FSizeRestriction := val;
+    FHeight := Restricted(FHeight);
+    FWidth := Restricted(FWidth);
+  end;
+end;
+
+procedure TGLAVIRecorder.AddAVIFrame;
+var
+  bmp32: TGLBitmap32;
+  bmp: TBitmap;
+begin
+  if RecorderState <> rsRecording then
+    raise Exception.Create('Cannot add frame to AVI. AVI file not created.');
+
+  if FBuffer <> nil then
+    case ImageRetrievalMode of
+      irmSnapShot:
+        begin
+          bmp32 := FBuffer.CreateSnapShot;
+          try
+            bmp := bmp32.Create32BitsBitmap;
+            try
+              AVIBitmap.Canvas.Draw(0, 0, bmp);
+            finally
+              bmp.Free;
+            end;
+          finally
+            bmp32.Free;
+          end;
+        end;
+      irmBitBlt:
+        begin
+          FBuffer.RenderingContext.Activate;
+          try
+            BitBlt(AVIBitmap.Canvas.Handle, 0, 0, AVIBitmap.Width,
+              AVIBitmap.Height, wglGetCurrentDC, 0, 0, SRCCOPY);
+          finally
+            FBuffer.RenderingContext.Deactivate;
+          end;
+        end;
+      irmRenderToBitmap:
+        begin
+          FBuffer.RenderToBitmap(AVIBitmap, AVI_DPI);
+        end;
+    else
+      Assert(false);
+    end;
+
+  InternalAddAVIFrame;
+end;
+
+procedure TGLAVIRecorder.AddAVIFrame(bmp: TBitmap);
+begin
+  if RecorderState <> rsRecording then
+    raise Exception.Create('Cannot add frame to AVI. AVI file not created.');
+  AVIBitmap.Canvas.Draw(0, 0, bmp);
+
+  InternalAddAVIFrame;
+end;
+
+procedure TGLAVIRecorder.InternalAddAVIFrame;
+begin
+  if Assigned(FOnPostProcessEvent) then
+    FOnPostProcessEvent(Self, AVIBitmap);
+  with AVIBitmap do
+  begin
+    InternalGetDIB(Handle, FBitmapInfo^, FBitmapBits^);
+    if AVIStreamWrite(Stream_c, AVIFrameIndex, 1, FBitmapBits, FBitmapSize,
+      AVIIF_KEYFRAME, nil, nil) <> AVIERR_OK then
+      raise Exception.Create('Add Frame Error');
+    Inc(AVIFrameIndex);
+  end;
+end;
+
+function TGLAVIRecorder.CreateAVIFile(DPI: integer = 0): boolean;
+var
+  SaveDialog: TSaveDialog;
+  gaAVIOptions: TAVICOMPRESSOPTIONS;
+  galpAVIOptions: PAVICOMPRESSOPTIONS;
+  bitmapInfoSize: integer;
+  AVIResult: Cardinal;
+  ResultString: String;
+begin
+  FTempName := FAVIFilename;
+
+  if FTempName = '' then
+  begin
+    // if user didn't supply a filename, then ask for it
+    SaveDialog := TSaveDialog.Create(Application);
+    try
+      with SaveDialog do
+      begin
+        Options := [ofHideReadOnly, ofNoReadOnlyReturn];
+        DefaultExt := '.avi';
+        Filter := 'AVI Files (*.avi)|*.avi';
+        if Execute then
+          FTempName := SaveDialog.Filename;
+      end;
+    finally
+      SaveDialog.Free;
+    end;
+  end;
+
+  Result := (FTempName <> '');
+  if Result then
+  begin
+    if FileExists(FTempName) then
+    begin
+      Result := (MessageDlg(Format('Overwrite file %s?', [FTempName]),
+        mtConfirmation, [mbYes, mbNo], 0) = mrYes);
+      // AVI streamers don't trim the file they're written to, so start from zero
+      if Result then
+        DeleteFile(FTempName);
+    end;
+  end;
+
+  if not Result then
+    Exit;
+
+  AVIFileInit; // initialize the AVI lib.
+
+  AVIBitmap := TBitmap.Create;
+  AVIFrameIndex := 0;
+
+  RecorderState := rsRecording;
+
+  try
+    AVIBitmap.PixelFormat := pf24Bit;
+    AVIBitmap.Width := FWidth;
+    AVIBitmap.Height := FHeight;
+
+    // note: a filename with extension other then AVI give generate an error.
+    if AVIFileOpen(pfile, PChar(FTempName), OF_WRITE or OF_CREATE, nil) <> AVIERR_OK
+    then
+      raise Exception.Create
+        ('Cannot create AVI file. Disk full or file in use?');
+
+    with AVIBitmap do
+    begin
+      InternalGetDIBSizes(Handle, bitmapInfoSize, FBitmapSize);
+      FBitmapInfo := AllocMem(bitmapInfoSize);
+      FBitmapBits := AllocMem(FBitmapSize);
+      InternalGetDIB(Handle, FBitmapInfo^, FBitmapBits^);
+    end;
+
+    FillChar(asi, SizeOf(asi), 0);
+
+    with asi do
+    begin
+      fccType := streamtypeVIDEO; // Now prepare the stream
+      fccHandler := 0;
+      dwScale := 1; // dwRate / dwScale = frames/second
+      dwRate := FFPS;
+      dwSuggestedBufferSize := FBitmapSize;
+      rcFrame.Right := FBitmapInfo.biWidth;
+      rcFrame.Bottom := FBitmapInfo.biHeight;
+    end;
+
+    if AVIFileCreateStream(pfile, Stream, asi) <> AVIERR_OK then
+      raise Exception.Create('Cannot create AVI stream.');
+
+    with AVIBitmap do
+      InternalGetDIB(Handle, FBitmapInfo^, FBitmapBits^);
+
+    galpAVIOptions := @gaAVIOptions;
+    FillChar(gaAVIOptions, SizeOf(gaAVIOptions), 0);
+    gaAVIOptions.fccType := streamtypeVIDEO;
+
+    case FCompressor of
+      acShowDialog:
+        begin
+          // call a dialog box for the user to choose the compressor options
+          AVISaveOptions(0, ICMF_CHOOSE_KEYFRAME or ICMF_CHOOSE_DATARATE, 1,
+            Stream, galpAVIOptions);
+        end;
+      acDivX:
+        with gaAVIOptions do
+        begin
+          // ask for generic divx, using current default settings
+          fccHandler := mmioFOURCC('d', 'i', 'v', 'x');
+        end;
+    else
+      with gaAVIOptions do
+      begin // or, you may want to fill the compression options yourself
+        fccHandler := mmioFOURCC('M', 'S', 'V', 'C');
+        // User MS video 1 as default.
+        // I guess it is installed on every Win95 or later.
+        dwQuality := 7500; // compress quality 0-10,000
+        dwFlags := 0;
+        // setting dwFlags to 0 would lead to some default settings
+      end;
+    end;
+
+    AVIResult := AVIMakeCompressedStream(Stream_c, Stream, galpAVIOptions, nil);
+
+    if AVIResult <> AVIERR_OK then
+    begin
+      if AVIResult = AVIERR_NOCOMPRESSOR then
+        ResultString := 'No such compressor found'
+      else
+        ResultString := '';
+      raise Exception.Create('Cannot make compressed stream. ' + ResultString);
+    end;
+
+    if AVIStreamSetFormat(Stream_c, 0, FBitmapInfo, bitmapInfoSize) <> AVIERR_OK
+    then
+      raise Exception.Create('AVIStreamSetFormat Error');
+    // no error description found in MSDN.
+
+    AVI_DPI := DPI;
+
+  except
+    CloseAVIFile(True);
+    raise;
+  end;
+end;
+
+procedure TGLAVIRecorder.CloseAVIFile(UserAbort: boolean = false);
+begin
+  // if UserAbort, CloseAVIFile will also delete the unfinished file.
+  try
+    if RecorderState <> rsRecording then
+      raise Exception.Create('Cannot close AVI file. AVI file not created.');
+
+    AVIBitmap.Free;
+
+    FreeMem(FBitmapInfo);
+    FreeMem(FBitmapBits);
+
+    AVIFileExit; // finalize the AVI lib.
+
+    // release the interfaces explicitly (can't rely on automatic release)
+    Stream := nil;
+    Stream_c := nil;
+    pfile := nil;
+
+    if UserAbort then
+      DeleteFile(FTempName);
+  finally
+    RecorderState := rsNone;
+  end;
+end;
+
+function TGLAVIRecorder.Recording: boolean;
+begin
+  Result := (RecorderState = rsRecording);
+end;
+
+procedure TGLAVIRecorder.SetGLSceneViewer(const Value: TGLSceneViewer);
+begin
+  FGLSceneViewer := Value;
+  if Assigned(FGLSceneViewer) then
+    FBuffer := FGLSceneViewer.Buffer
+  else
+    FBuffer := nil;
+end;
+
+procedure TGLAVIRecorder.SetGLNonVisualViewer(const Value: TGLNonVisualViewer);
+begin
+  FGLNonVisualViewer := Value;
+  if Assigned(FGLNonVisualViewer) then
+    FBuffer := FGLNonVisualViewer.Buffer
+  else
+    FBuffer := nil;
+end;
+
+end.

+ 2 - 4
Source/GLS.ArchiveManager.pas

@@ -14,8 +14,9 @@ uses
   System.Classes,
   System.SysUtils,
 
+  GLApplicationFileIO,
   Scene.PersistentClasses,
-  GLApplicationFileIO;
+  Scene.Strings;
 
 type
 
@@ -187,9 +188,6 @@ function ArcFileStreamExists(const FileName: string): boolean;
 implementation
 // ------------------------------------------------------------------
 
-uses
-  Scene.Strings;
-
 var
   vArchiveFileFormats: TGLArchiveFileFormatsList;
   vArchiveManager: TGLSArchiveManager;

+ 1589 - 1589
Source/GLIsosurface.pas → Source/GLS.Isosurface.pas

@@ -1,1599 +1,1599 @@
 //
-// This unit is part of the GLScene Engine, http://glscene.org
-//
-
-unit GLIsosurface;
-
-(*
-  Polygonising a scalar field by construction of isosurfaces
-  Algorithms
-  ----------
-  Marching Cubes
-  - Exploits a coarser Mesh then Marching Tetrahedra but produces less triangles
-  - based on "Marching Cubes: A High Resolution 3D Surface
-  Construction Algorithm" by W.E.Lorensen and H.E.Cline
-  - patent free since 2005
-
-  Marching Tetrahedra
-  - Finer Mesh, better feature preservation
-  - based on "A new tetrahedral tesselation scheme for isosurface generation"
-  by S.L.Chan and E.O.Purisima
-  - patent free
-
-  Lookuptables
-  - by Paul Bourke (http://paulbourke.net/geometry/polygonise/)
-
-  Overall
-  - Simple Data Structures to store Mesh. Vertices are calculated and stored twice
-  or even more often.
-*)
-
-interface
-
+// This unit is part of the GLScene Engine, http://glscene.org
+//
+
+unit GLS.Isosurface;
+
+(*
+  Polygonising a scalar field by construction of isosurfaces
+  Algorithms
+  ----------
+  Marching Cubes
+  - Exploits a coarser Mesh then Marching Tetrahedra but produces less triangles
+  - based on "Marching Cubes: A High Resolution 3D Surface
+  Construction Algorithm" by W.E.Lorensen and H.E.Cline
+  - patent free since 2005
+
+  Marching Tetrahedra
+  - Finer Mesh, better feature preservation
+  - based on "A new tetrahedral tesselation scheme for isosurface generation"
+  by S.L.Chan and E.O.Purisima
+  - patent free
+
+  Lookuptables
+  - by Paul Bourke (http://paulbourke.net/geometry/polygonise/)
+
+  Overall
+  - Simple Data Structures to store Mesh. Vertices are calculated and stored twice
+  or even more often.
+*)
+
+interface
+
 {$I GLScene.inc}
 
 // uncomment next line to memorize vertex Density value to further use
-// (i.e. mesh color generation)
-{.$Define UseDensity}
+// (i.e. mesh color generation)
+{.$Define UseDensity}
 
-uses
+uses
   Scene.VectorGeometry,
   Scene.VectorLists,
   GLMesh,
   GLVectorFileObjects,
-  Scene.VectorTypes,
-  Scene.VectorRecTypes;
-
-const
-  ALLOC_SIZE = 65536;
-
-type
-  TSingle3DArray = array of array of array of Single;
-  TVertexArray = array of TVector3f;
-  TIntegerArray = array of Integer;
-
-  TGLMarchingCube = class(TObject)
-  private
-    FIsoValue: TxScalarValue;
-    // sliceSize:Longword;
-    PVertsX: PIntegerArray;
-    PVertsY: PIntegerArray;
-    PVertsZ: PIntegerArray;
-    _Nverts: Integer;
-    _Ntrigs: Integer;
-    _Sverts: Integer;
-    _Strigs: Integer;
-    PVertices: PxVertexArray;
-    PTriangles: PxTriangleArray;
-    _i, _j, _k: Longword;
-    _Cube: array [0 .. 7] of TxVoxel;
-    _lut_entry: Byte;
-    // _case:Byte;
-    // _config:Byte;
-    // _subconfig:Byte;
-    procedure Init_temps;
-    procedure Init_all;
-    procedure Init_space;
-    procedure Clean_temps;
-    procedure Clean_all(keepFacets: Boolean = False);
-    procedure Clean_space;
-    procedure Test_vertex_addiction;
-  protected
-    FOriginalMC: Boolean; // now only original MC is implemented
-    FSizeX: Integer;
-    FSizeY: Integer;
-    FSizeZ: Integer;
-    FxMin: Single;
-    FxMax: Single;
-    FyMin: Single;
-    FyMax: Single;
-    FzMin: Single;
-    FzMax: Single;
-    FStepX: Single;
-    FStepY: Single;
-    FStepZ: Single;
-    VoxelData: PxVoxelData;
-    procedure Process_cube;
-    { function test_face(face:byte):Boolean;
-      function test_interior(s:Byte):boolean }
-    procedure Compute_Intersection_Points;
-    procedure Add_Triangle(trig: array of Integer; N: Byte; v12: Integer = -1);
-    function Add_x_vertex: Integer;
-    function Add_y_vertex: Integer;
-    function Add_z_vertex: Integer;
-    function Add_c_vertex: Integer;
-    function Get_x_grad(i, j, k: Integer): Single;
-    function Get_y_grad(i, j, k: Integer): Single;
-    function Get_z_grad(i, j, k: Integer): Single;
-    function Get_x_vert(i, j, k: Integer): Integer;
-    function Get_y_vert(i, j, k: Integer): Integer;
-    function Get_z_vert(i, j, k: Integer): Integer;
-    procedure Set_x_vert(a_val, i, j, k: Integer);
-    procedure Set_y_vert(a_val, i, j, k: Integer);
-    procedure Set_z_vert(a_val, i, j, k: Integer);
-    function GetVoxelValue(i, j, k: Integer): TxScalarValue;
-    procedure SetVoxelValue(i, j, k: Integer; HfValue: TxScalarValue);
-    function GetVoxelData(i, j, k: Integer): TxVoxel;
-    function Voxel(i, j, k: Integer): PxVoxel;
-    function calc_u(v1, v2: Single): Single; virtual;
-  public
-    ScalarField: TxScalarField;
-    constructor Create; overload; virtual;
-    constructor Create(SizeX, SizeY, SizeZ: Integer;
-      AIsoValue: TxScalarValue = 0.0; xMin: Single = -0.5; xMax: Single = 0.5;
-      yMin: Single = -0.5; yMax: Single = 0.5; zMin: Single = -0.5;
-      zMax: Single = 0.5); overload; virtual;
-    procedure ReDim(ASizeX, ASizeY, ASizeZ: Integer;
-      xMin, xMax, yMin, yMax, zMin, zMax: Single); virtual;
-    destructor Destroy; override;
-    procedure Run; overload;
-    procedure Run(IsoValue: TxScalarValue); overload;
-    function Internal(AValue: TxScalarValue): Boolean; virtual;
-    procedure FillVoxelData; overload; virtual;
-    procedure FillVoxelData(AIsoValue: TxScalarValue;
-      AScalarField: TxScalarField = nil); overload; virtual;
-    procedure FillVoxelData(AIsoValue: TxScalarValue;
-      AScalarField: TxScalarFieldInt); overload; virtual;
-    procedure CalcVertices(Vertices: TGLVertexList; Alpha: Single = 1);
-    procedure CalcMeshObject(AMeshObject: TMeshObject; Alpha: Single = 1);
-    property IsoValue: TxScalarValue read FIsoValue write FIsoValue;
-    // TODO SetIsoValue to Run
-  end;
-
-  (* 3D isosurface extractor class. This class allows to calculate and exctract
-    isosurfaces from scalar field voxel models using a given isovalue *)
-  TIsoSurfaceExtractor = class(TObject)
-  private
-    Data: TSingle3DArray;
-    Dimensions: array ['x' .. 'z'] of Integer;
-    // Build Index depending on whether the edges are outside or inside the surface
-    function BuildIndex(var ADatavals: array of Single; Isovalue: Single): word;
-    function Interpolate(const V0, V1: TAffineVector;
-      var Val0, Val1, Isovalue: Single; isPolished: boolean): TVertex;
-  public
-    constructor Create(); overload;
-    constructor Create(Xdim, Ydim, Zdim: Integer;
-      var AData: TSingle3DArray); overload;
-    destructor Destroy(); override;
-    procedure AssignData(Xdim, Ydim, Zdim: Integer; var AData: TSingle3DArray);
-    { Launch Marching Cubes }
-    procedure MarchingCubes(Isovalue: Single; out Vertices: TVertexArray;
-      out Triangles: TIntegerArray; isPolished: boolean);
-    { Launch Marching Tetrahedra }
-    procedure MarchingTetrahedra(Isovalue: Single; out Vertices: TVertexArray;
-      out Triangles: TIntegerArray; isPolished: boolean);
-  end;
-
-// Sphere surface
-function SFSphere(X, Y, Z: Single): TxScalarValue;
-// Minkowski space (http://mathworld.wolfram.com)
-function SFMinkowski(X, Y, Z: Single): TxScalarValue;
-// Klein Bottle (http://mathworld.wolfram.com)
-function SFKleinBottle(X, Y, Z: Single): TxScalarValue;
-// Chmutov-surface-1 (http://mathworld.wolfram.com)
-function SFChmutov1(X, Y, Z: Single): TxScalarValue;
-// Chmutov-surface-2 (http://mathworld.wolfram.com)
-function SFChmutov2(X, Y, Z: Single): TxScalarValue;
-// Toroidal surface (phantasy!)
-function SFToroidal(X, Y, Z: Single): TxScalarValue;
-// Double torus Surface (phantasy!)
-function SFDoubleTorus(X, Y, Z: Single): TxScalarValue;
-
-const
-  DemoScalarField: array [0 .. 6] of
-  record
-    // xMin, xMax, yMin, yMax, zMin, zMax:Single; // default -0.5..0.5
-    ScalarField: TxScalarField;
-    IsoValue: TxScalarValue
-  end = ((ScalarField: SFSphere; IsoValue: 0.3), (ScalarField: SFMinkowski;
-  IsoValue: 0.0), (ScalarField: SFKleinBottle; IsoValue: 0.0),
-  (ScalarField: SFChmutov1; IsoValue: 3.0), (ScalarField: SFChmutov2;
-  IsoValue: 3.0), (ScalarField: SFToroidal; IsoValue: 3.0),
-  (ScalarField: SFDoubleTorus; IsoValue: 0.015));
-
-// -------------------------------------------------------------------------
-implementation
-// -------------------------------------------------------------------------
-
-const
-  // Classic Cases for Marching Cube TriTable
-  //
-  (*
-        4----4------5
-       /|          /|
-      7 |         5 |
-     /  |        /  |
-    7-----6----6    |
-    |   8       |   9
-    |   |       |   |
-    |   0----0--|---1
-    11 /        10 /
-    | 3         | 1
-    |/          |/
-    3-----2-----2
-  *)
-
-  MC_TRITABLE: array [0 .. 255, 0 .. 15] of Integer = (
-(*   0:                          *)  ( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   1: 0,                       *)  (  0,  8,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   2:    1,                    *)  (  0,  1,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   3: 0, 1,                    *)  (  1,  8,  3,  9,  8,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   4:       2,                 *)  (  1,  2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   5: 0,    2,                 *)  (  0,  8,  3,  1,  2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   6:    1, 2,                 *)  (  9,  2, 10,  0,  2,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   7: 0, 1, 2,                 *)  (  2,  8,  3,  2, 10,  8, 10,  9,  8, -1, -1, -1, -1, -1, -1, -1 ),
-(*   8:          3,              *)  (  3, 11,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*   9: 0,       3,              *)  (  0, 11,  2,  8, 11,  0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  10:    1,    3,              *)  (  1,  9,  0,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  11: 0, 1,    3,              *)  (  1, 11,  2,  1,  9, 11,  9,  8, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(*  12:       2, 3,              *)  (  3, 10,  1, 11, 10,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  13: 0,    2, 3,              *)  (  0, 10,  1,  0,  8, 10,  8, 11, 10, -1, -1, -1, -1, -1, -1, -1 ),
-(*  14:    1, 2, 3,              *)  (  3,  9,  0,  3, 11,  9, 11, 10,  9, -1, -1, -1, -1, -1, -1, -1 ),
-(*  15: 0, 1, 2, 3,              *)  (  9,  8, 10, 10,  8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  16:             4,           *)  (  4,  7,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  17: 0,          4,           *)  (  4,  3,  0,  7,  3,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  18:    1,       4,           *)  (  0,  1,  9,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  19: 0, 1,       4,           *)  (  4,  1,  9,  4,  7,  1,  7,  3,  1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  20:       2,    4,           *)  (  1,  2, 10,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  21: 0,    2,    4,           *)  (  3,  4,  7,  3,  0,  4,  1,  2, 10, -1, -1, -1, -1, -1, -1, -1 ),
-(*  22:    1, 2,    4,           *)  (  9,  2, 10,  9,  0,  2,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(*  23: 0, 1, 2,    4,           *)  (  2, 10,  9,  2,  9,  7,  2,  7,  3,  7,  9,  4, -1, -1, -1, -1 ),
-(*  24:          3, 4,           *)  (  8,  4,  7,  3, 11,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  25: 0,       3, 4,           *)  ( 11,  4,  7, 11,  2,  4,  2,  0,  4, -1, -1, -1, -1, -1, -1, -1 ),
-(*  26:    1,    3, 4,           *)  (  9,  0,  1,  8,  4,  7,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(*  27: 0, 1,    3, 4,           *)  (  4,  7, 11,  9,  4, 11,  9, 11,  2,  9,  2,  1, -1, -1, -1, -1 ),
-(*  28:       2, 3, 4,           *)  (  3, 10,  1,  3, 11, 10,  7,  8,  4, -1, -1, -1, -1, -1, -1, -1 ),
-(*  29: 0,    2, 3, 4,           *)  (  1, 11, 10,  1,  4, 11,  1,  0,  4,  7, 11,  4, -1, -1, -1, -1 ),
-(*  30:    1, 2, 3, 4,           *)  (  4,  7,  8,  9,  0, 11,  9, 11, 10, 11,  0,  3, -1, -1, -1, -1 ),
-(*  31: 0, 1, 2, 3, 4,           *)  (  4,  7, 11,  4, 11,  9,  9, 11, 10, -1, -1, -1, -1, -1, -1, -1 ),
-(*  32:                5,        *)  (  9,  5,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  33: 0,             5,        *)  (  9,  5,  4,  0,  8,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  34:    1,          5,        *)  (  0,  5,  4,  1,  5,  0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  35: 0, 1,          5,        *)  (  8,  5,  4,  8,  3,  5,  3,  1,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(*  36:       2,       5,        *)  (  1,  2, 10,  9,  5,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  37: 0,    2,       5,        *)  (  3,  0,  8,  1,  2, 10,  4,  9,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(*  38:    1, 2,       5,        *)  (  5,  2, 10,  5,  4,  2,  4,  0,  2, -1, -1, -1, -1, -1, -1, -1 ),
-(*  39: 0, 1, 2,       5,        *)  (  2, 10,  5,  3,  2,  5,  3,  5,  4,  3,  4,  8, -1, -1, -1, -1 ),
-(*  40:          3,    5,        *)  (  9,  5,  4,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  41: 0,       3,    5,        *)  (  0, 11,  2,  0,  8, 11,  4,  9,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(*  42:    1,    3,    5,        *)  (  0,  5,  4,  0,  1,  5,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(*  43: 0, 1,    3,    5,        *)  (  2,  1,  5,  2,  5,  8,  2,  8, 11,  4,  8,  5, -1, -1, -1, -1 ),
-(*  44:       2, 3,    5,        *)  ( 10,  3, 11, 10,  1,  3,  9,  5,  4, -1, -1, -1, -1, -1, -1, -1 ),
-(*  45: 0,    2, 3,    5,        *)  (  4,  9,  5,  0,  8,  1,  8, 10,  1,  8, 11, 10, -1, -1, -1, -1 ),
-(*  46:    1, 2, 3,    5,        *)  (  5,  4,  0,  5,  0, 11,  5, 11, 10, 11,  0,  3, -1, -1, -1, -1 ),
-(*  47: 0, 1, 2, 3,    5,        *)  (  5,  4,  8,  5,  8, 10, 10,  8, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(*  48:             4, 5,        *)  (  9,  7,  8,  5,  7,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  49: 0,          4, 5,        *)  (  9,  3,  0,  9,  5,  3,  5,  7,  3, -1, -1, -1, -1, -1, -1, -1 ),
-(*  50:    1,       4, 5,        *)  (  0,  7,  8,  0,  1,  7,  1,  5,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(*  51: 0, 1,       4, 5,        *)  (  1,  5,  3,  3,  5,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  52:       2,    4, 5,        *)  (  9,  7,  8,  9,  5,  7, 10,  1,  2, -1, -1, -1, -1, -1, -1, -1 ),
-(*  53: 0,    2,    4, 5,        *)  ( 10,  1,  2,  9,  5,  0,  5,  3,  0,  5,  7,  3, -1, -1, -1, -1 ),
-(*  54:    1, 2,    4, 5,        *)  (  8,  0,  2,  8,  2,  5,  8,  5,  7, 10,  5,  2, -1, -1, -1, -1 ),
-(*  55: 0, 1, 2,    4, 5,        *)  (  2, 10,  5,  2,  5,  3,  3,  5,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(*  56:          3, 4, 5,        *)  (  7,  9,  5,  7,  8,  9,  3, 11,  2, -1, -1, -1, -1, -1, -1, -1 ),
-(*  57: 0,       3, 4, 5,        *)  (  9,  5,  7,  9,  7,  2,  9,  2,  0,  2,  7, 11, -1, -1, -1, -1 ),
-(*  58:    1,    3, 4, 5,        *)  (  2,  3, 11,  0,  1,  8,  1,  7,  8,  1,  5,  7, -1, -1, -1, -1 ),
-(*  59: 0, 1,    3, 4, 5,        *)  ( 11,  2,  1, 11,  1,  7,  7,  1,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(*  60:       2, 3, 4, 5,        *)  (  9,  5,  8,  8,  5,  7, 10,  1,  3, 10,  3, 11, -1, -1, -1, -1 ),
-(*  61: 0,    2, 3, 4, 5,        *)  (  5,  7,  0,  5,  0,  9,  7, 11,  0,  1,  0, 10, 11, 10,  0, -1 ),
-(*  62:    1, 2, 3, 4, 5,        *)  ( 11, 10,  0, 11,  0,  3, 10,  5,  0,  8,  0,  7,  5,  7,  0, -1 ),
-(*  63: 0, 1, 2, 3, 4, 5,        *)  ( 11, 10,  5,  7, 11,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  64:                   6,     *)  ( 10,  6,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  65: 0,                6,     *)  (  0,  8,  3,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  66:    1,             6,     *)  (  9,  0,  1,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  67: 0, 1,             6,     *)  (  1,  8,  3,  1,  9,  8,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(*  68:       2,          6,     *)  (  1,  6,  5,  2,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  69: 0,    2,          6,     *)  (  1,  6,  5,  1,  2,  6,  3,  0,  8, -1, -1, -1, -1, -1, -1, -1 ),
-(*  70:    1, 2,          6,     *)  (  9,  6,  5,  9,  0,  6,  0,  2,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(*  71: 0, 1, 2,          6,     *)  (  5,  9,  8,  5,  8,  2,  5,  2,  6,  3,  2,  8, -1, -1, -1, -1 ),
-(*  72:          3,       6,     *)  (  2,  3, 11, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  73: 0,       3,       6,     *)  ( 11,  0,  8, 11,  2,  0, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(*  74:    1,    3,       6,     *)  (  0,  1,  9,  2,  3, 11,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(*  75: 0, 1,    3,       6,     *)  (  5, 10,  6,  1,  9,  2,  9, 11,  2,  9,  8, 11, -1, -1, -1, -1 ),
-(*  76:       2, 3,       6,     *)  (  6,  3, 11,  6,  5,  3,  5,  1,  3, -1, -1, -1, -1, -1, -1, -1 ),
-(*  77: 0,    2, 3,       6,     *)  (  0,  8, 11,  0, 11,  5,  0,  5,  1,  5, 11,  6, -1, -1, -1, -1 ),
-(*  78:    1, 2, 3,       6,     *)  (  3, 11,  6,  0,  3,  6,  0,  6,  5,  0,  5,  9, -1, -1, -1, -1 ),
-(*  79: 0, 1, 2, 3,       6,     *)  (  6,  5,  9,  6,  9, 11, 11,  9,  8, -1, -1, -1, -1, -1, -1, -1 ),
-(*  80:             4,    6,     *)  (  5, 10,  6,  4,  7,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  81: 0,          4,    6,     *)  (  4,  3,  0,  4,  7,  3,  6,  5, 10, -1, -1, -1, -1, -1, -1, -1 ),
-(*  82:    1,       4,    6,     *)  (  1,  9,  0,  5, 10,  6,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(*  83: 0, 1,       4,    6,     *)  ( 10,  6,  5,  1,  9,  7,  1,  7,  3,  7,  9,  4, -1, -1, -1, -1 ),
-(*  84:       2,    4,    6,     *)  (  6,  1,  2,  6,  5,  1,  4,  7,  8, -1, -1, -1, -1, -1, -1, -1 ),
-(*  85: 0,    2,    4,    6,     *)  (  1,  2,  5,  5,  2,  6,  3,  0,  4,  3,  4,  7, -1, -1, -1, -1 ),
-(*  86:    1, 2,    4,    6,     *)  (  8,  4,  7,  9,  0,  5,  0,  6,  5,  0,  2,  6, -1, -1, -1, -1 ),
-(*  87: 0, 1, 2,    4,    6,     *)  (  7,  3,  9,  7,  9,  4,  3,  2,  9,  5,  9,  6,  2,  6,  9, -1 ),
-(*  88:          3, 4,    6,     *)  (  3, 11,  2,  7,  8,  4, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(*  89: 0,       3, 4,    6,     *)  (  5, 10,  6,  4,  7,  2,  4,  2,  0,  2,  7, 11, -1, -1, -1, -1 ),
-(*  90:    1,    3, 4,    6,     *)  (  0,  1,  9,  4,  7,  8,  2,  3, 11,  5, 10,  6, -1, -1, -1, -1 ),
-(*  91: 0, 1,    3, 4,    6,     *)  (  9,  2,  1,  9, 11,  2,  9,  4, 11,  7, 11,  4,  5, 10,  6, -1 ),
-(*  92:       2, 3, 4,    6,     *)  (  8,  4,  7,  3, 11,  5,  3,  5,  1,  5, 11,  6, -1, -1, -1, -1 ),
-(*  93: 0,    2, 3, 4,    6,     *)  (  5,  1, 11,  5, 11,  6,  1,  0, 11,  7, 11,  4,  0,  4, 11, -1 ),
-(*  94:    1, 2, 3, 4,    6,     *)  (  0,  5,  9,  0,  6,  5,  0,  3,  6, 11,  6,  3,  8,  4,  7, -1 ),
-(*  95: 0, 1, 2, 3, 4,    6,     *)  (  6,  5,  9,  6,  9, 11,  4,  7,  9,  7, 11,  9, -1, -1, -1, -1 ),
-(*  96:                5, 6,     *)  ( 10,  4,  9,  6,  4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(*  97: 0,             5, 6,     *)  (  4, 10,  6,  4,  9, 10,  0,  8,  3, -1, -1, -1, -1, -1, -1, -1 ),
-(*  98:    1,          5, 6,     *)  ( 10,  0,  1, 10,  6,  0,  6,  4,  0, -1, -1, -1, -1, -1, -1, -1 ),
-(*  99: 0, 1,          5, 6,     *)  (  8,  3,  1,  8,  1,  6,  8,  6,  4,  6,  1, 10, -1, -1, -1, -1 ),
-(* 100:       2,       5, 6,     *)  (  1,  4,  9,  1,  2,  4,  2,  6,  4, -1, -1, -1, -1, -1, -1, -1 ),
-(* 101: 0,    2,       5, 6,     *)  (  3,  0,  8,  1,  2,  9,  2,  4,  9,  2,  6,  4, -1, -1, -1, -1 ),
-(* 102:    1, 2,       5, 6,     *)  (  0,  2,  4,  4,  2,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 103: 0, 1, 2,       5, 6,     *)  (  8,  3,  2,  8,  2,  4,  4,  2,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(* 104:          3,    5, 6,     *)  ( 10,  4,  9, 10,  6,  4, 11,  2,  3, -1, -1, -1, -1, -1, -1, -1 ),
-(* 105: 0,       3,    5, 6,     *)  (  0,  8,  2,  2,  8, 11,  4,  9, 10,  4, 10,  6, -1, -1, -1, -1 ),
-(* 106:    1,    3,    5, 6,     *)  (  3, 11,  2,  0,  1,  6,  0,  6,  4,  6,  1, 10, -1, -1, -1, -1 ),
-(* 107: 0, 1,    3,    5, 6,     *)  (  6,  4,  1,  6,  1, 10,  4,  8,  1,  2,  1, 11,  8, 11,  1, -1 ),
-(* 108:       2, 3,    5, 6,     *)  (  9,  6,  4,  9,  3,  6,  9,  1,  3, 11,  6,  3, -1, -1, -1, -1 ),
-(* 109: 0,    2, 3,    5, 6,     *)  (  8, 11,  1,  8,  1,  0, 11,  6,  1,  9,  1,  4,  6,  4,  1, -1 ),
-(* 110:    1, 2, 3,    5, 6,     *)  (  3, 11,  6,  3,  6,  0,  0,  6,  4, -1, -1, -1, -1, -1, -1, -1 ),
-(* 111: 0, 1, 2, 3,    5, 6,     *)  (  6,  4,  8, 11,  6,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 112:             4, 5, 6,     *)  (  7, 10,  6,  7,  8, 10,  8,  9, 10, -1, -1, -1, -1, -1, -1, -1 ),
-(* 113: 0,          4, 5, 6,     *)  (  0,  7,  3,  0, 10,  7,  0,  9, 10,  6,  7, 10, -1, -1, -1, -1 ),
-(* 114:    1,       4, 5, 6,     *)  ( 10,  6,  7,  1, 10,  7,  1,  7,  8,  1,  8,  0, -1, -1, -1, -1 ),
-(* 115: 0, 1,       4, 5, 6,     *)  ( 10,  6,  7, 10,  7,  1,  1,  7,  3, -1, -1, -1, -1, -1, -1, -1 ),
-(* 116:       2,    4, 5, 6,     *)  (  1,  2,  6,  1,  6,  8,  1,  8,  9,  8,  6,  7, -1, -1, -1, -1 ),
-(* 117: 0,    2,    4, 5, 6,     *)  (  2,  6,  9,  2,  9,  1,  6,  7,  9,  0,  9,  3,  7,  3,  9, -1 ),
-(* 118:    1, 2,    4, 5, 6,     *)  (  7,  8,  0,  7,  0,  6,  6,  0,  2, -1, -1, -1, -1, -1, -1, -1 ),
-(* 119: 0, 1, 2,    4, 5, 6,     *)  (  7,  3,  2,  6,  7,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 120:          3, 4, 5, 6,     *)  (  2,  3, 11, 10,  6,  8, 10,  8,  9,  8,  6,  7, -1, -1, -1, -1 ),
-(* 121: 0,       3, 4, 5, 6,     *)  (  2,  0,  7,  2,  7, 11,  0,  9,  7,  6,  7, 10,  9, 10,  7, -1 ),
-(* 122:    1,    3, 4, 5, 6,     *)  (  1,  8,  0,  1,  7,  8,  1, 10,  7,  6,  7, 10,  2,  3, 11, -1 ),
-(* 123: 0, 1,    3, 4, 5, 6,     *)  ( 11,  2,  1, 11,  1,  7, 10,  6,  1,  6,  7,  1, -1, -1, -1, -1 ),
-(* 124:       2, 3, 4, 5, 6,     *)  (  8,  9,  6,  8,  6,  7,  9,  1,  6, 11,  6,  3,  1,  3,  6, -1 ),
-(* 125: 0,    2, 3, 4, 5, 6,     *)  (  0,  9,  1, 11,  6,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 126:    1, 2, 3, 4, 5, 6,     *)  (  7,  8,  0,  7,  0,  6,  3, 11,  0, 11,  6,  0, -1, -1, -1, -1 ),
-(* 127: 0, 1, 2, 3, 4, 5, 6,     *)  (  7, 11,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 128:                      7,  *)  (  7,  6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 129: 0,                   7,  *)  (  3,  0,  8, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 130:    1,                7,  *)  (  0,  1,  9, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 131: 0, 1,                7,  *)  (  8,  1,  9,  8,  3,  1, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(* 132:       2,             7,  *)  ( 10,  1,  2,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 133: 0,    2,             7,  *)  (  1,  2, 10,  3,  0,  8,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(* 134:    1, 2,             7,  *)  (  2,  9,  0,  2, 10,  9,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(* 135: 0, 1, 2,             7,  *)  (  6, 11,  7,  2, 10,  3, 10,  8,  3, 10,  9,  8, -1, -1, -1, -1 ),
-(* 136:          3,          7,  *)  (  7,  2,  3,  6,  2,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 137: 0,       3,          7,  *)  (  7,  0,  8,  7,  6,  0,  6,  2,  0, -1, -1, -1, -1, -1, -1, -1 ),
-(* 138:    1,    3,          7,  *)  (  2,  7,  6,  2,  3,  7,  0,  1,  9, -1, -1, -1, -1, -1, -1, -1 ),
-(* 139: 0, 1,    3,          7,  *)  (  1,  6,  2,  1,  8,  6,  1,  9,  8,  8,  7,  6, -1, -1, -1, -1 ),
-(* 140:       2, 3,          7,  *)  ( 10,  7,  6, 10,  1,  7,  1,  3,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(* 141: 0,    2, 3,          7,  *)  ( 10,  7,  6,  1,  7, 10,  1,  8,  7,  1,  0,  8, -1, -1, -1, -1 ),
-(* 142:    1, 2, 3,          7,  *)  (  0,  3,  7,  0,  7, 10,  0, 10,  9,  6, 10,  7, -1, -1, -1, -1 ),
-(* 143: 0, 1, 2, 3,          7,  *)  (  7,  6, 10,  7, 10,  8,  8, 10,  9, -1, -1, -1, -1, -1, -1, -1 ),
-(* 144:             4,       7,  *)  (  6,  8,  4, 11,  8,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 145: 0,          4,       7,  *)  (  3,  6, 11,  3,  0,  6,  0,  4,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(* 146:    1,       4,       7,  *)  (  8,  6, 11,  8,  4,  6,  9,  0,  1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 147: 0, 1,       4,       7,  *)  (  9,  4,  6,  9,  6,  3,  9,  3,  1, 11,  3,  6, -1, -1, -1, -1 ),
-(* 148:       2,    4,       7,  *)  (  6,  8,  4,  6, 11,  8,  2, 10,  1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 149: 0,    2,    4,       7,  *)  (  1,  2, 10,  3,  0, 11,  0,  6, 11,  0,  4,  6, -1, -1, -1, -1 ),
-(* 150:    1, 2,    4,       7,  *)  (  4, 11,  8,  4,  6, 11,  0,  2,  9,  2, 10,  9, -1, -1, -1, -1 ),
-(* 151: 0, 1, 2,    4,       7,  *)  ( 10,  9,  3, 10,  3,  2,  9,  4,  3, 11,  3,  6,  4,  6,  3, -1 ),
-(* 152:          3, 4,       7,  *)  (  8,  2,  3,  8,  4,  2,  4,  6,  2, -1, -1, -1, -1, -1, -1, -1 ),
-(* 153: 0,       3, 4,       7,  *)  (  0,  4,  2,  4,  6,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 154:    1,    3, 4,       7,  *)  (  1,  9,  0,  2,  3,  4,  2,  4,  6,  4,  3,  8, -1, -1, -1, -1 ),
-(* 155: 0, 1,    3, 4,       7,  *)  (  1,  9,  4,  1,  4,  2,  2,  4,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(* 156:       2, 3, 4,       7,  *)  (  8,  1,  3,  8,  6,  1,  8,  4,  6,  6, 10,  1, -1, -1, -1, -1 ),
-(* 157: 0,    2, 3, 4,       7,  *)  ( 10,  1,  0, 10,  0,  6,  6,  0,  4, -1, -1, -1, -1, -1, -1, -1 ),
-(* 158:    1, 2, 3, 4,       7,  *)  (  4,  6,  3,  4,  3,  8,  6, 10,  3,  0,  3,  9, 10,  9,  3, -1 ),
-(* 159: 0, 1, 2, 3, 4,       7,  *)  ( 10,  9,  4,  6, 10,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 160:                5,    7,  *)  (  4,  9,  5,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 161: 0,             5,    7,  *)  (  0,  8,  3,  4,  9,  5, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1 ),
-(* 162:    1,          5,    7,  *)  (  5,  0,  1,  5,  4,  0,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(* 163: 0, 1,          5,    7,  *)  ( 11,  7,  6,  8,  3,  4,  3,  5,  4,  3,  1,  5, -1, -1, -1, -1 ),
-(* 164:       2,       5,    7,  *)  (  9,  5,  4, 10,  1,  2,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(* 165: 0,    2,       5,    7,  *)  (  6, 11,  7,  1,  2, 10,  0,  8,  3,  4,  9,  5, -1, -1, -1, -1 ),
-(* 166:    1, 2,       5,    7,  *)  (  7,  6, 11,  5,  4, 10,  4,  2, 10,  4,  0,  2, -1, -1, -1, -1 ),
-(* 167: 0, 1, 2,       5,    7,  *)  (  3,  4,  8,  3,  5,  4,  3,  2,  5, 10,  5,  2, 11,  7,  6, -1 ),
-(* 168:          3,    5,    7,  *)  (  7,  2,  3,  7,  6,  2,  5,  4,  9, -1, -1, -1, -1, -1, -1, -1 ),
-(* 169: 0,       3,    5,    7,  *)  (  9,  5,  4,  0,  8,  6,  0,  6,  2,  6,  8,  7, -1, -1, -1, -1 ),
-(* 170:    1,    3,    5,    7,  *)  (  3,  6,  2,  3,  7,  6,  1,  5,  0,  5,  4,  0, -1, -1, -1, -1 ),
-(* 171: 0, 1,    3,    5,    7,  *)  (  6,  2,  8,  6,  8,  7,  2,  1,  8,  4,  8,  5,  1,  5,  8, -1 ),
-(* 172:       2, 3,    5,    7,  *)  (  9,  5,  4, 10,  1,  6,  1,  7,  6,  1,  3,  7, -1, -1, -1, -1 ),
-(* 173: 0,    2, 3,    5,    7,  *)  (  1,  6, 10,  1,  7,  6,  1,  0,  7,  8,  7,  0,  9,  5,  4, -1 ),
-(* 174:    1, 2, 3,    5,    7,  *)  (  4,  0, 10,  4, 10,  5,  0,  3, 10,  6, 10,  7,  3,  7, 10, -1 ),
-(* 175: 0, 1, 2, 3,    5,    7,  *)  (  7,  6, 10,  7, 10,  8,  5,  4, 10,  4,  8, 10, -1, -1, -1, -1 ),
-(* 176:             4, 5,    7,  *)  (  6,  9,  5,  6, 11,  9, 11,  8,  9, -1, -1, -1, -1, -1, -1, -1 ),
-(* 177: 0,          4, 5,    7,  *)  (  3,  6, 11,  0,  6,  3,  0,  5,  6,  0,  9,  5, -1, -1, -1, -1 ),
-(* 178:    1,       4, 5,    7,  *)  (  0, 11,  8,  0,  5, 11,  0,  1,  5,  5,  6, 11, -1, -1, -1, -1 ),
-(* 179: 0, 1,       4, 5,    7,  *)  (  6, 11,  3,  6,  3,  5,  5,  3,  1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 180:       2,    4, 5,    7,  *)  (  1,  2, 10,  9,  5, 11,  9, 11,  8, 11,  5,  6, -1, -1, -1, -1 ),
-(* 181: 0,    2,    4, 5,    7,  *)  (  0, 11,  3,  0,  6, 11,  0,  9,  6,  5,  6,  9,  1,  2, 10, -1 ),
-(* 182:    1, 2,    4, 5,    7,  *)  ( 11,  8,  5, 11,  5,  6,  8,  0,  5, 10,  5,  2,  0,  2,  5, -1 ),
-(* 183: 0, 1, 2,    4, 5,    7,  *)  (  6, 11,  3,  6,  3,  5,  2, 10,  3, 10,  5,  3, -1, -1, -1, -1 ),
-(* 184:          3, 4, 5,    7,  *)  (  5,  8,  9,  5,  2,  8,  5,  6,  2,  3,  8,  2, -1, -1, -1, -1 ),
-(* 185: 0,       3, 4, 5,    7,  *)  (  9,  5,  6,  9,  6,  0,  0,  6,  2, -1, -1, -1, -1, -1, -1, -1 ),
-(* 186:    1,    3, 4, 5,    7,  *)  (  1,  5,  8,  1,  8,  0,  5,  6,  8,  3,  8,  2,  6,  2,  8, -1 ),
-(* 187: 0, 1,    3, 4, 5,    7,  *)  (  1,  5,  6,  2,  1,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 188:       2, 3, 4, 5,    7,  *)  (  1,  3,  6,  1,  6, 10,  3,  8,  6,  5,  6,  9,  8,  9,  6, -1 ),
-(* 189: 0,    2, 3, 4, 5,    7,  *)  ( 10,  1,  0, 10,  0,  6,  9,  5,  0,  5,  6,  0, -1, -1, -1, -1 ),
-(* 190:    1, 2, 3, 4, 5,    7,  *)  (  0,  3,  8,  5,  6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 191: 0, 1, 2, 3, 4, 5,    7,  *)  ( 10,  5,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 192:                   6, 7,  *)  ( 11,  5, 10,  7,  5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 193: 0,                6, 7,  *)  ( 11,  5, 10, 11,  7,  5,  8,  3,  0, -1, -1, -1, -1, -1, -1, -1 ),
-(* 194:    1,             6, 7,  *)  (  5, 11,  7,  5, 10, 11,  1,  9,  0, -1, -1, -1, -1, -1, -1, -1 ),
-(* 195: 0, 1,             6, 7,  *)  ( 10,  7,  5, 10, 11,  7,  9,  8,  1,  8,  3,  1, -1, -1, -1, -1 ),
-(* 196:       2,          6, 7,  *)  ( 11,  1,  2, 11,  7,  1,  7,  5,  1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 197: 0,    2,          6, 7,  *)  (  0,  8,  3,  1,  2,  7,  1,  7,  5,  7,  2, 11, -1, -1, -1, -1 ),
-(* 198:    1, 2,          6, 7,  *)  (  9,  7,  5,  9,  2,  7,  9,  0,  2,  2, 11,  7, -1, -1, -1, -1 ),
-(* 199: 0, 1, 2,          6, 7,  *)  (  7,  5,  2,  7,  2, 11,  5,  9,  2,  3,  2,  8,  9,  8,  2, -1 ),
-(* 200:          3,       6, 7,  *)  (  2,  5, 10,  2,  3,  5,  3,  7,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(* 201: 0,       3,       6, 7,  *)  (  8,  2,  0,  8,  5,  2,  8,  7,  5, 10,  2,  5, -1, -1, -1, -1 ),
-(* 202:    1,    3,       6, 7,  *)  (  9,  0,  1,  5, 10,  3,  5,  3,  7,  3, 10,  2, -1, -1, -1, -1 ),
-(* 203: 0, 1,    3,       6, 7,  *)  (  9,  8,  2,  9,  2,  1,  8,  7,  2, 10,  2,  5,  7,  5,  2, -1 ),
-(* 204:       2, 3,       6, 7,  *)  (  1,  3,  5,  3,  7,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 205: 0,    2, 3,       6, 7,  *)  (  0,  8,  7,  0,  7,  1,  1,  7,  5, -1, -1, -1, -1, -1, -1, -1 ),
-(* 206:    1, 2, 3,       6, 7,  *)  (  9,  0,  3,  9,  3,  5,  5,  3,  7, -1, -1, -1, -1, -1, -1, -1 ),
-(* 207: 0, 1, 2, 3,       6, 7,  *)  (  9,  8,  7,  5,  9,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 208:             4,    6, 7,  *)  (  5,  8,  4,  5, 10,  8, 10, 11,  8, -1, -1, -1, -1, -1, -1, -1 ),
-(* 209: 0,          4,    6, 7,  *)  (  5,  0,  4,  5, 11,  0,  5, 10, 11, 11,  3,  0, -1, -1, -1, -1 ),
-(* 210:    1,       4,    6, 7,  *)  (  0,  1,  9,  8,  4, 10,  8, 10, 11, 10,  4,  5, -1, -1, -1, -1 ),
-(* 211: 0, 1,       4,    6, 7,  *)  ( 10, 11,  4, 10,  4,  5, 11,  3,  4,  9,  4,  1,  3,  1,  4, -1 ),
-(* 212:       2,    4,    6, 7,  *)  (  2,  5,  1,  2,  8,  5,  2, 11,  8,  4,  5,  8, -1, -1, -1, -1 ),
-(* 213: 0,    2,    4,    6, 7,  *)  (  0,  4, 11,  0, 11,  3,  4,  5, 11,  2, 11,  1,  5,  1, 11, -1 ),
-(* 214:    1, 2,    4,    6, 7,  *)  (  0,  2,  5,  0,  5,  9,  2, 11,  5,  4,  5,  8, 11,  8,  5, -1 ),
-(* 215: 0, 1, 2,    4,    6, 7,  *)  (  9,  4,  5,  2, 11,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 216:          3, 4,    6, 7,  *)  (  2,  5, 10,  3,  5,  2,  3,  4,  5,  3,  8,  4, -1, -1, -1, -1 ),
-(* 217: 0,       3, 4,    6, 7,  *)  (  5, 10,  2,  5,  2,  4,  4,  2,  0, -1, -1, -1, -1, -1, -1, -1 ),
-(* 218:    1,    3, 4,    6, 7,  *)  (  3, 10,  2,  3,  5, 10,  3,  8,  5,  4,  5,  8,  0,  1,  9, -1 ),
-(* 219: 0, 1,    3, 4,    6, 7,  *)  (  5, 10,  2,  5,  2,  4,  1,  9,  2,  9,  4,  2, -1, -1, -1, -1 ),
-(* 220:       2, 3, 4,    6, 7,  *)  (  8,  4,  5,  8,  5,  3,  3,  5,  1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 221: 0,    2, 3, 4,    6, 7,  *)  (  0,  4,  5,  1,  0,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 222:    1, 2, 3, 4,    6, 7,  *)  (  8,  4,  5,  8,  5,  3,  9,  0,  5,  0,  3,  5, -1, -1, -1, -1 ),
-(* 223: 0, 1, 2, 3, 4,    6, 7,  *)  (  9,  4,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 224:                5, 6, 7,  *)  (  4, 11,  7,  4,  9, 11,  9, 10, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(* 225: 0,             5, 6, 7,  *)  (  0,  8,  3,  4,  9,  7,  9, 11,  7,  9, 10, 11, -1, -1, -1, -1 ),
-(* 226:    1,          5, 6, 7,  *)  (  1, 10, 11,  1, 11,  4,  1,  4,  0,  7,  4, 11, -1, -1, -1, -1 ),
-(* 227: 0, 1,          5, 6, 7,  *)  (  3,  1,  4,  3,  4,  8,  1, 10,  4,  7,  4, 11, 10, 11,  4, -1 ),
-(* 228:       2,       5, 6, 7,  *)  (  4, 11,  7,  9, 11,  4,  9,  2, 11,  9,  1,  2, -1, -1, -1, -1 ),
-(* 229: 0,    2,       5, 6, 7,  *)  (  9,  7,  4,  9, 11,  7,  9,  1, 11,  2, 11,  1,  0,  8,  3, -1 ),
-(* 230:    1, 2,       5, 6, 7,  *)  ( 11,  7,  4, 11,  4,  2,  2,  4,  0, -1, -1, -1, -1, -1, -1, -1 ),
-(* 231: 0, 1, 2,       5, 6, 7,  *)  ( 11,  7,  4, 11,  4,  2,  8,  3,  4,  3,  2,  4, -1, -1, -1, -1 ),
-(* 232:          3,    5, 6, 7,  *)  (  2,  9, 10,  2,  7,  9,  2,  3,  7,  7,  4,  9, -1, -1, -1, -1 ),
-(* 233: 0,       3,    5, 6, 7,  *)  (  9, 10,  7,  9,  7,  4, 10,  2,  7,  8,  7,  0,  2,  0,  7, -1 ),
-(* 234:    1,    3,    5, 6, 7,  *)  (  3,  7, 10,  3, 10,  2,  7,  4, 10,  1, 10,  0,  4,  0, 10, -1 ),
-(* 235: 0, 1,    3,    5, 6, 7,  *)  (  1, 10,  2,  8,  7,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 236:       2, 3,    5, 6, 7,  *)  (  4,  9,  1,  4,  1,  7,  7,  1,  3, -1, -1, -1, -1, -1, -1, -1 ),
-(* 237: 0,    2, 3,    5, 6, 7,  *)  (  4,  9,  1,  4,  1,  7,  0,  8,  1,  8,  7,  1, -1, -1, -1, -1 ),
-(* 238:    1, 2, 3,    5, 6, 7,  *)  (  4,  0,  3,  7,  4,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 239: 0, 1, 2, 3,    5, 6, 7,  *)  (  4,  8,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 240:             4, 5, 6, 7,  *)  (  9, 10,  8, 10, 11,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 241: 0,          4, 5, 6, 7,  *)  (  3,  0,  9,  3,  9, 11, 11,  9, 10, -1, -1, -1, -1, -1, -1, -1 ),
-(* 242:    1,       4, 5, 6, 7,  *)  (  0,  1, 10,  0, 10,  8,  8, 10, 11, -1, -1, -1, -1, -1, -1, -1 ),
-(* 243: 0, 1,       4, 5, 6, 7,  *)  (  3,  1, 10, 11,  3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 244:       2,    4, 5, 6, 7,  *)  (  1,  2, 11,  1, 11,  9,  9, 11,  8, -1, -1, -1, -1, -1, -1, -1 ),
-(* 245: 0,    2,    4, 5, 6, 7,  *)  (  3,  0,  9,  3,  9, 11,  1,  2,  9,  2, 11,  9, -1, -1, -1, -1 ),
-(* 246:    1, 2,    4, 5, 6, 7,  *)  (  0,  2, 11,  8,  0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 247: 0, 1, 2,    4, 5, 6, 7,  *)  (  3,  2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 248:          3, 4, 5, 6, 7,  *)  (  2,  3,  8,  2,  8, 10, 10,  8,  9, -1, -1, -1, -1, -1, -1, -1 ),
-(* 249: 0,       3, 4, 5, 6, 7,  *)  (  9, 10,  2,  0,  9,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 250:    1,    3, 4, 5, 6, 7,  *)  (  2,  3,  8,  2,  8, 10,  0,  1,  8,  1, 10,  8, -1, -1, -1, -1 ),
-(* 251: 0, 1,    3, 4, 5, 6, 7,  *)  (  1, 10,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 252:       2, 3, 4, 5, 6, 7,  *)  (  1,  3,  8,  9,  1,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 253: 0,    2, 3, 4, 5, 6, 7,  *)  (  0,  9,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 254:    1, 2, 3, 4, 5, 6, 7,  *)  (  0,  3,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
-(* 255: 0, 1, 2, 3, 4, 5, 6, 7,  *)  ( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 )
-);
-
-
-// Marching Cube EdgeTable
-const
-  MC_EDGETABLE: array [0 .. 11, 0 .. 1] of Integer = ((0, 1), (1, 2), (2, 3),
-    (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7));
-
-  // Marching Tetrahedra TriTable
-  (*
-        + 0
-         /|\
-        / | \
-       /  |  0
-      3   |   \
-     /    2    \
-    /     |     \
-   +----4--------+ 1
-  3 \     |     /
-     \    |    /
-      5   |   1
-       \  |  /
-        \ | /
-         \|/
-        + 2
-*)
-  MT_TRITABLE: array [0 .. 15, 0 .. 6] of Integer =
-    ((-1, -1, -1, -1, -1, -1, -1), (2, 3, 0, -1, -1, -1, -1),
-    (4, 1, 0, -1, -1, -1, -1), (2, 4, 1, 3, 4, 2, -1),
-    (5, 2, 1, -1, -1, -1, -1), (5, 3, 0, 1, 5, 0, -1), (5, 2, 0, 4, 5, 0, -1),
-    (3, 4, 5, -1, -1, -1, -1), (5, 4, 3, -1, -1, -1, -1),
-    (0, 5, 4, 0, 2, 5, -1), (0, 5, 1, 0, 3, 5, -1), (1, 2, 5, -1, -1, -1, -1),
-    (2, 4, 3, 1, 4, 2, -1), (0, 1, 4, -1, -1, -1, -1),
-    (0, 3, 2, -1, -1, -1, -1), (-1, -1, -1, -1, -1, -1, -1));
-
-  // Marching Tetrahedra EdgeTable
-  MT_EDGETABLE: array [0 .. 5, 0 .. 1] of Integer = ((0, 1), (1, 2), (2, 0),
-    (0, 3), (1, 3), (2, 3));
-
-  // Marching Tetrahedra CubeSplit
-  MT_CUBESPLIT: array [0 .. 5, 0 .. 3] of Integer = ((0, 5, 1, 6), (0, 1, 2, 6),
-    (0, 2, 3, 6), (0, 3, 7, 6), (0, 7, 4, 6), (0, 4, 5, 6));
-
-// Test surface functions
-function SFSphere(X, Y, Z: Single): TxScalarValue;
-begin
-  Result := sqr(X) + sqr(Y) + sqr(Z)
-end;
-
-function SFToroidal(X, Y, Z: Single): TxScalarValue;
-const
-  FScale = 7;
-  a = 2.5;
-begin
-  X := FScale * X;
-  Y := FScale * Y;
-  Z := FScale * Z;
-  Result := (sqr(sqrt(sqr(X) + sqr(Y)) - a) + sqr(Z)) *
-    (sqr(sqrt(sqr(Y) + sqr(Z)) - a) + sqr(X)) *
-    (sqr(sqrt(sqr(Z) + sqr(X)) - a) + sqr(Y));
-end;
-
-function SFDoubleTorus(X, Y, Z: Single): TxScalarValue;
-const
-  FScale = 2.25;
-begin
-  X := FScale * X;
-  Y := FScale * Y;
-  Z := FScale * Z;
-  Result := PowerInteger(X, 8) + PowerInteger(X, 4) - 2 * PowerInteger(X, 6) - 2
-    * sqr(X) * sqr(Y) + 2 * PowerInteger(X, 4) * sqr(Y) +
-    PowerInteger(Y, 4) + sqr(Z)
-end;
-
-function SFChmutov1(X, Y, Z: Single): TxScalarValue;
-const
-  FScale = 2.5;
-begin
-  X := FScale * X;
-  Y := FScale * Y;
-  Z := FScale * Z;
-  Result := 8 * (sqr(X) + sqr(Y) + sqr(Z)) - 8 *
-    (PowerInteger(X, 4) + PowerInteger(Y, 4) + PowerInteger(Z, 4));
-end;
-
-function SFChmutov2(X, Y, Z: Single): TxScalarValue;
-const
-  FScale = 2.5;
-begin
-  X := FScale * X;
-  Y := FScale * Y;
-  Z := FScale * Z;
-  Result := 2 * (sqr(X) * sqr(3 - 4 * sqr(X)) + sqr(Y) * sqr(3 - 4 * sqr(Y)) +
-    sqr(Z) * sqr(3 - 4 * sqr(Z)));
-end;
-
-function SFKleinBottle(X, Y, Z: Single): TxScalarValue;
-const
-  FScale = 7.5;
-begin
-  X := FScale * X;
-  Y := FScale * Y;
-  Z := FScale * Z;
-  Result := (sqr(X) + sqr(Y) + sqr(Z) + 2 * Y - 1) *
-    (sqr(sqr(X) + sqr(Y) + sqr(Z) - 2 * Y - 1) - 8 * sqr(Z)) + 16 * X * Z *
-    (sqr(X) + sqr(Y) + sqr(Z) - 2 * Y - 1);
-end;
-
-function SFMinkowski(X, Y, Z: Single): TxScalarValue;
-const
-  FScale = 7;
-begin
-  X := FScale * X;
-  Y := FScale * Y;
-  Z := FScale * Z;
-  Result := (sqr(X) - sqr(Y) - sqr(Z) - 2) * (sqr(X) - sqr(Y) - sqr(Z) + 2) *
-    (sqr(X) - sqr(Y) - sqr(Z) - 4) * (sqr(X) - sqr(Y) - sqr(Z) + 4) *
-    (sqr(X) - sqr(Y) - sqr(Z));
-end;
-
-(* -------------------------------------------------------------------------
-   Class IsoSurfaceExtractor
-   Purpose: Extract an Isosurface from volume dataset for given Isovalue
-   ------------------------------------------------------------------------- *)
-
-function TIsoSurfaceExtractor.BuildIndex(var ADatavals: array of Single;
-  Isovalue: Single): word;
-var
-  i: Integer;
-  val: word;
-begin
-  val := 1;
-  Result := 0;
-  for i := 1 to Length(ADatavals) do
-  begin
-    if ADatavals[i - 1] <= Isovalue then // Edge inside surface
-      Result := Result + val;
-    val := val * 2;
-  end;
-end;
-
-// Compute intersection point of edge and surface by linear interpolation
-function InterpolateRugged(V0, V1: TAffineVector;
-  var Val0, Val1, Isovalue: Single): TVertex;
-var
-  Diff: Single;
-  i: Integer;
-begin
-  if Val0 <= Isovalue then
-  begin
-    Diff := Val0 / (Val0 + Val1);
-    for i := 0 to 2 do
-      Result.V[i] := V0.V[i] + Diff * (V1.V[i] - V0.V[i]);
-  end
-  else
-  begin
-    Diff := Val1 / (Val0 + Val1);
-    for i := 0 to 2 do
-      Result.V[i] := V1.V[i] + Diff * (V0.V[i] - V1.V[i]);
-  end;
-end;
-
-function InterpolatePolished(V0, V1: TAffineVector;
-  var Val0, Val1, Isovalue: Single): TVertex;
-var
-  w0, w1: Single;
-begin
-  if (Val0 = Val1) then
-    w1 := 0.5
-  else
-    w1 := (Isovalue - Val0) / (Val1 - Val0);
-  w0 := 1.0 - w1;
-  Result.X := w0 * V0.X + w1 * V1.X;
-  Result.Y := w0 * V0.Y + w1 * V1.Y;
-  Result.Z := w0 * V0.Z + w1 * V1.Z;
-end;
-
-function TIsoSurfaceExtractor.Interpolate(const V0, V1: TAffineVector;
-  var Val0, Val1, Isovalue: Single; isPolished: boolean): TVertex;
-begin
-  if isPolished then
-    Result := InterpolatePolished(V0, V1, Val0, Val1, Isovalue)
-  else
-    Result := InterpolateRugged(V0, V1, Val0, Val1, Isovalue)
-end;
-
-procedure TIsoSurfaceExtractor.MarchingTetrahedra(Isovalue: Single;
-  out Vertices: TVertexArray; out Triangles: TIntegerArray; isPolished: boolean);
-var
-  i, j, k: Integer;
-  index: word;
-  CubeVertices: array of TAffineVector;
-  Tetrahedron: array [0 .. 3] of TAffineVector;
-  DataTetra: array [0 .. 3] of Single;
-
-  // Add Triangle to List
-  procedure AppendTri();
-  var
-    edge: byte;
-    Ver1, Ver2, Ver3: TVertex;
-    VListlength: Integer;
-    TListlength: Integer;
-  begin
-    edge := 0;
-    while MT_TRITABLE[index, edge] <> -1 do
-    begin
-      Ver1 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge], 0]
-        ], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge], 1]],
-        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge], 0]],
-        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge], 1]], Isovalue, isPolished);
-      Ver2 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 1],
-        0]], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 1]],
-        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 0]],
-        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 1]], Isovalue, isPolished);
-      Ver3 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 2],
-        0]], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 1]],
-        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 0]],
-        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 1]], Isovalue, isPolished);
-      VListlength := Length(Vertices) + 3;
-      TListlength := Length(Triangles) + 3;
-      SetLength(Vertices, VListlength);
-      SetLength(Triangles, TListlength);
-      Vertices[VListlength - 3] := Ver1;
-      Vertices[VListlength - 2] := Ver2;
-      Vertices[VListlength - 1] := Ver3;
-      Triangles[TListlength - 3] := VListlength - 3;
-      Triangles[TListlength - 2] := VListlength - 2;
-      Triangles[TListlength - 1] := VListlength - 1;
-      edge := edge + 3;
-    end;
-  end;
-
-// Split Cube in 6 Tetrahedrons and process each tetrahedron
-  procedure SplitCube();
-  var
-    i, j: Integer;
-  begin
-    for i := 0 to 5 do
-    begin
-      for j := 0 to 3 do
-      begin
-        Tetrahedron[j] := CubeVertices[MT_CUBESPLIT[i, j]];
-        DataTetra[j] := Data[Trunc(Tetrahedron[j].X),
-          Trunc(Tetrahedron[j].Y), Trunc(Tetrahedron[j].Z)];
-      end;
-      index := BuildIndex(DataTetra, Isovalue);
-      AppendTri();
-    end;
-  end;
-
-begin
-(*
-      1----2
-     /|   /|
-    0----3 |
-    | 5--|-6
-    |/   |/
-    4----7
-*)
-  SetLength(CubeVertices, 8);
-  for k := 0 to Dimensions['z'] - 2 do
-  begin
-    for j := 0 to Dimensions['y'] - 2 do
-    begin
-      for i := 0 to Dimensions['x'] - 2 do
-      begin
-        CubeVertices[0] := AffineVectorMake(i, j, k);
-        CubeVertices[1] := AffineVectorMake(i, j, k + 1);
-        CubeVertices[2] := AffineVectorMake(i + 1, j, k + 1);
-        CubeVertices[3] := AffineVectorMake(i + 1, j, k);
-        CubeVertices[4] := AffineVectorMake(i, j + 1, k);
-        CubeVertices[5] := AffineVectorMake(i, j + 1, k + 1);
-        CubeVertices[6] := AffineVectorMake(i + 1, j + 1, k + 1);
-        CubeVertices[7] := AffineVectorMake(i + 1, j + 1, k);
-
-        SplitCube();
-      end; // for k
-    end; // for j
-  end; // for i
-end; // ccMT
-
-constructor TIsoSurfaceExtractor.Create;
-begin
-  inherited;
-end;
-
-constructor TIsoSurfaceExtractor.Create(Xdim, Ydim, Zdim: Integer;
-  var AData: TSingle3DArray);
-begin
-  Create();
-  AssignData(Xdim, Ydim, Zdim, AData);
-end;
-
-destructor TIsoSurfaceExtractor.Destroy;
-begin
-  inherited;
-end;
-
-procedure TIsoSurfaceExtractor.AssignData(Xdim, Ydim, Zdim: Integer;
-  var AData: TSingle3DArray);
-begin
-  Dimensions['x'] := Xdim;
-  Dimensions['y'] := Ydim;
-  Dimensions['z'] := Zdim;
-
-  Data := AData;
-end;
-
-//-----------------------------------------------------------------------
-procedure TIsoSurfaceExtractor.MarchingCubes(Isovalue: Single;
-  out Vertices: TVertexArray; out Triangles: TIntegerArray; isPolished: boolean);
-var
-  i, j, k: Integer;
-  index: word;
-  CubeVertices: array [0 .. 7] of TAffineVector;
-  CubeData: array [0 .. 7] of Single;
-
-  procedure AppendTri();
-  var
-    edge: byte;
-    Ver1, Ver2, Ver3: TVertex;
-    VListlength: Integer;
-    TListlength: Integer;
-  begin
-    edge := 0;
-    while MC_TRITABLE[index, edge] <> -1 do
-    begin
-      Ver1 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge], 0]
-        ], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge], 1]],
-        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge], 0]],
-        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge], 1]], Isovalue, isPolished);
-      Ver2 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index,
-        edge + 1], 0]], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge + 1],
-        1]], CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 1], 0]],
-        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 1], 1]], Isovalue, isPolished);
-      Ver3 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index,
-        edge + 2], 0]], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge + 2],
-        1]], CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 2], 0]],
-        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 2], 1]], Isovalue, isPolished);
-      VListlength := Length(Vertices) + 3;
-      TListlength := Length(Triangles) + 3;
-      SetLength(Vertices, VListlength);
-      SetLength(Triangles, TListlength);
-      Vertices[VListlength - 3] := Ver1;
-      Vertices[VListlength - 2] := Ver2;
-      Vertices[VListlength - 1] := Ver3;
-      Triangles[TListlength - 3] := VListlength - 3;
-      Triangles[TListlength - 2] := VListlength - 2;
-      Triangles[TListlength - 1] := VListlength - 1;
-      edge := edge + 3;
-    end;
-  end;
-
-begin
-  (*
-      7----6
-     /|   /|
-    3----2 |
-    | 4--|-5
-    |/   |/
-    0----1
-  *)
-  for i := 0 to Dimensions['x'] - 2 do
-  begin
-    for j := 1 to Dimensions['y'] - 1 do
-    begin
-      for k := 0 to Dimensions['z'] - 2 do
-      begin
-        CubeVertices[0] := AffineVectorMake(i, j, k);
-        CubeVertices[1] := AffineVectorMake(i + 1, j, k);
-        CubeVertices[2] := AffineVectorMake(i + 1, j - 1, k);
-        CubeVertices[3] := AffineVectorMake(i, j - 1, k);
-        CubeVertices[4] := AffineVectorMake(i, j, k + 1);
-        CubeVertices[5] := AffineVectorMake(i + 1, j, k + 1);
-        CubeVertices[6] := AffineVectorMake(i + 1, j - 1, k + 1);
-        CubeVertices[7] := AffineVectorMake(i, j - 1, k + 1);
-        CubeData[0] := Data[i, j, k];
-        CubeData[1] := Data[i + 1, j, k];
-        CubeData[2] := Data[i + 1, j - 1, k];
-        CubeData[3] := Data[i, j - 1, k];
-        CubeData[4] := Data[i, j, k + 1];
-        CubeData[5] := Data[i + 1, j, k + 1];
-        CubeData[6] := Data[i + 1, j - 1, k + 1];
-        CubeData[7] := Data[i, j - 1, k + 1];
-
-        Index := BuildIndex(CubeData, Isovalue);
-        AppendTri();
-      end; // for k
-    end; // for j
-  end; // for i
-end;
-
-
-function TGLMarchingCube.add_c_vertex: Integer;
-var
-  u: Single;
-  vid: Integer;
-  procedure VertexAdd(iv: Integer);
-  begin
-    with PVertices^[_Nverts] do
-    begin
-      u := u + 1;
-      P := VectorAdd(P, PVertices[iv].P);
-      N := VectorAdd(N, PVertices[iv].N);
-{$IFDEF UseDensity}
-      Density := Density + PVertices[iv].Density;
-{$ENDIF}
-    end
-  end;
-
-begin
-  test_vertex_addiction;
-
-  u := 0;
-  with PVertices^[_Nverts] do
-  begin
-    P := NullVector;
-    N := NullVector;
-{$IFDEF UseDensity}
-    Density := 0;
-{$ENDIF}
-  end;
-  Inc(_Nverts);
-
-  // Computes the average of the intersection points of the cube
-  vid := Get_x_vert(_i, _j, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_y_vert(_i + 1, _j, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_x_vert(_i, _j + 1, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_y_vert(_i, _j, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_x_vert(_i, _j, _k + 1);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_y_vert(_i + 1, _j, _k + 1);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_x_vert(_i, _j + 1, _k + 1);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_y_vert(_i, _j, _k + 1);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_z_vert(_i, _j, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_z_vert(_i + 1, _j, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_z_vert(_i + 1, _j + 1, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-  vid := Get_z_vert(_i, _j + 1, _k);
-  if (vid <> -1) then
-    VertexAdd(vid);
-
-  ScaleVector(PVertices^[_Nverts].P, 1 / u);
-  NormalizeVector(PVertices^[_Nverts].N);
-{$IFDEF UseDensity}
-  PVertices^[_Nverts].Density := PVertices^[_Nverts].Density / u;
-{$ENDIF}
-  Result := _Nverts - 1;
-end;
-
-procedure TGLMarchingCube.add_triangle(trig: array of Integer; N: Byte;
-  v12: Integer = -1);
-
-var
-  tv: array [0 .. 2] of Integer;
-  t, tmod3: Integer;
-
-begin
-  for t := 0 to 3 * N - 1 do
-  begin
-    tmod3 := t mod 3;
-    case trig[t] of
-      0: tv[tmod3] := Get_x_vert(_i, _j, _k);
-      1: tv[tmod3] := Get_y_vert(_i + 1, _j, _k);
-      2: tv[tmod3] := Get_x_vert(_i, _j + 1, _k);
-      3: tv[tmod3] := Get_y_vert(_i, _j, _k);
-      4: tv[tmod3] := Get_x_vert(_i, _j, _k + 1);
-      5: tv[tmod3] := Get_y_vert(_i + 1, _j, _k + 1);
-      6: tv[tmod3] := Get_x_vert(_i, _j + 1, _k + 1);
-      7: tv[tmod3] := Get_y_vert(_i, _j, _k + 1);
-      8: tv[tmod3] := Get_z_vert(_i, _j, _k);
-      9: tv[tmod3] := Get_z_vert(_i + 1, _j, _k);
-      10: tv[tmod3] := Get_z_vert(_i + 1, _j + 1, _k);
-      11: tv[tmod3] := Get_z_vert(_i, _j + 1, _k);
-      12: tv[tmod3] := v12
-    end;
-
-    if (tv[tmod3] = -1) then
-      Break;
-
-    if (tmod3 = 2) then
-    begin
-      if (_Ntrigs >= _Strigs) then
-      begin
-        _Strigs := 2 * _Strigs;
-        ReallocMem(PTriangles, _Strigs * SizeOf(TxTriangle));
-      end;
-
-      with PTriangles^[_Ntrigs] do
-      begin
-        v1 := tv[0];
-        v2 := tv[1];
-        v3 := tv[2];
-      end;
-      Inc(_Ntrigs);
-
-    end
-  end
-end;
-
-function TGLMarchingCube.calc_u(v1, v2: Single): Single;
-begin
-  if (abs(FIsoValue - v1) >= 0.00001) then
-    Result := 1
-  else if (abs(FIsoValue - v2) >= 0.00001) then
-    Result := 0
-  else if (abs(v1 - v2) >= 0.00001) then
-    Result := (FIsoValue - v1) / (v2 - v1)
-  else
-    Result := 0.5
-end;
-
-function TGLMarchingCube.add_x_vertex: Integer;
-var
-  u: Single;
-begin
-  test_vertex_addiction;
-  u := calc_u(_Cube[0].Density, _Cube[1].Density);
-
-  with PVertices^[_Nverts] do
-  begin
-    P.X := _Cube[0].P.X + u * FStepX;
-    P.Y := _Cube[0].P.Y;
-    P.Z := _Cube[0].P.Z;
-
-    N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i + 1, _j, _k);
-    N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i + 1, _j, _k);
-    N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i + 1, _j, _k);
-    NormalizeVector(N);
-{$IFDEF UseDensity}
-    Density := _Cube[1].Density
-{$ENDIF}
-  end;
-  Inc(_Nverts);
-  Result := _Nverts - 1;
-end;
-
-function TGLMarchingCube.add_y_vertex: Integer;
-var
-  u: Single;
-begin
-  test_vertex_addiction;
-  u := calc_u(_Cube[0].Density, _Cube[3].Density);
-
-  with PVertices^[_Nverts] do
-  begin
-    P.X := _Cube[0].P.X;
-    P.Y := _Cube[0].P.Y + u * FStepY;
-    P.Z := _Cube[0].P.Z;
-
-    N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i, _j + 1, _k);
-    N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i, _j + 1, _k);
-    N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i, _j + 1, _k);
-    NormalizeVector(N);
-{$IFDEF UseDensity}
-    Density := _Cube[3].Density
-{$ENDIF}
-  end;
-  Inc(_Nverts);
-  Result := _Nverts - 1;
-end;
-
-function TGLMarchingCube.add_z_vertex: Integer;
-var
-  u: Single;
-begin
-  test_vertex_addiction;
-  u := calc_u(_Cube[0].Density, _Cube[4].Density);
-
-  with PVertices^[_Nverts] do
-  begin
-    P.X := _Cube[0].P.X;
-    P.Y := _Cube[0].P.Y;
-    P.Z := _Cube[0].P.Z + u * FStepZ;;
-
-    N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i, _j, _k + 1);
-    N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i, _j, _k + 1);
-    N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i, _j, _k + 1);
-    NormalizeVector(N);
-{$IFDEF UseDensity}
-    Density := _Cube[4].Density
-{$ENDIF}
-  end;
-  Inc(_Nverts);
-  Result := _Nverts - 1;
-end;
-
-procedure TGLMarchingCube.clean_all(keepFacets: Boolean = False);
-begin
-  clean_temps;
-  clean_space;
-  if (not keepFacets) then
-    FreeMem(PVertices);
-  FreeMem(PTriangles);
-  PVertices := nil;
-  PTriangles := nil;
-  _Nverts := 0;
-  _Ntrigs := 0;
-  _Sverts := 0;
-  _Strigs := 0;
-end;
-
-procedure TGLMarchingCube.clean_space;
-begin
-  if (VoxelData <> nil) then
-  begin
-    FreeMem(VoxelData);
-    VoxelData := nil
-  end;
-  FSizeX := 0;
-  FSizeY := 0;
-  FSizeZ := 0
-end;
-
-procedure TGLMarchingCube.clean_temps;
-begin
-  FreeMem(PVertsX);
-  PVertsX := nil;
-  FreeMem(PVertsY);
-  PVertsY := nil;
-  FreeMem(PVertsZ);
-  PVertsZ := nil;
-end;
-
-procedure TGLMarchingCube.compute_intersection_points;
-var
-  k, j, i: Integer;
-begin
-  _Cube[0] := getVoxelData(0, 0, 0);
-  _Cube[1] := getVoxelData(1, 0, 0);
-  _Cube[3] := getVoxelData(0, 1, 0);
-  _Cube[4] := getVoxelData(0, 0, 1);
-  { _step_x:= _Cube[1].P[0] - _Cube[0].P[0] ;
-    _step_y:= _Cube[3].P[1] - _Cube[0].P[1] ;
-    _step_z:= _Cube[4].P[2] - _Cube[0].P[2] ; }
-
-  for k := 0 to FSizeZ - 2 do
-  begin
-    _k := k;
-    for j := 0 to FSizeY - 2 do
-    begin
-      _j := j;
-      for i := 0 to FSizeX - 2 do
-      begin
-        _i := i;
-        _Cube[0] := getVoxelData(_i, _j, _k);
-        _Cube[1] := getVoxelData(_i + 1, _j, _k);
-        _Cube[3] := getVoxelData(_i, _j + 1, _k);
-        _Cube[4] := getVoxelData(_i, _j, _k + 1);
-
-        if (Internal(_Cube[0].Density)) then
-        begin
-          if (not Internal(_Cube[1].Density)) then
-            set_x_vert(add_x_vertex(), _i, _j, _k);
-          if (not Internal(_Cube[3].Density)) then
-            set_y_vert(add_y_vertex(), _i, _j, _k);
-          if (not Internal(_Cube[4].Density)) then
-            set_z_vert(add_z_vertex(), _i, _j, _k);
-        end
-        else
-        begin
-          if (Internal(_Cube[1].Density)) then
-            set_x_vert(add_x_vertex(), _i, _j, _k);
-          if (Internal(_Cube[3].Density)) then
-            set_y_vert(add_y_vertex(), _i, _j, _k);
-          if (Internal(_Cube[4].Density)) then
-            set_z_vert(add_z_vertex(), _i, _j, _k);
-        end
-      end
-    end
-  end
-end;
-
-procedure TGLMarchingCube.ReDim(ASizeX, ASizeY, ASizeZ: Integer;
-  xMin, xMax, yMin, yMax, zMin, zMax: Single);
-begin
-  clean_all;
-  FSizeX := ASizeX;
-  FSizeY := ASizeY;
-  FSizeZ := ASizeZ;
-  FxMin := xMin;
-  FxMax := xMax;
-  FyMin := yMin;
-  FyMax := yMax;
-  FzMin := zMin;
-  FzMax := zMax;
-
-  FStepX := (FxMax - FxMin) / (FSizeX - 1);
-  FStepY := (FyMax - FyMin) / (FSizeY - 1);
-  FStepZ := (FzMax - FzMin) / (FSizeZ - 1);
-
-  VoxelData := nil;
-  PVertsX := nil;
-  PVertsY := nil;
-  PVertsZ := nil;
-  _Nverts := 0;
-  _Ntrigs := 0;
-  _Sverts := 0;
-  _Strigs := 0;
-  PVertices := nil;
-  PTriangles := nil;
-
-  Init_all;
-  // FillVoxelData;
-end;
-
-constructor TGLMarchingCube.Create;
-begin
-  FOriginalMC := True; // now only original MC is implemented
-  FIsoValue := 0;
-  ScalarField := nil;
-  // SFSphere;//SFKleinBottle;//SFMinkowski;// SFChmutov2;// SFChmutov1;//SFDoubleTorus;// SFToroidal;
-
-  VoxelData := nil;
-  PVertsX := nil;
-  PVertsY := nil;
-  PVertsZ := nil;
-  _Nverts := 0;
-  _Ntrigs := 0;
-  _Sverts := 0;
-  _Strigs := 0;
-  PVertices := nil;
-  PTriangles := nil;
-end;
-
-constructor TGLMarchingCube.Create(SizeX, SizeY, SizeZ: Integer;
-  AIsoValue: TxScalarValue = 0.0; xMin: Single = -0.5; xMax: Single = 0.5;
-  yMin: Single = -0.5; yMax: Single = 0.5; zMin: Single = -0.5;
-  zMax: Single = 0.5);
-begin
-  FOriginalMC := True; // now only original MC is implemented
-  FIsoValue := AIsoValue;
-  ScalarField := SFSphere;
-  //SFKleinBottle;
-  //SFMinkowski;
-  //SFChmutov2;
-  //SFChmutov1;
-  //SFDoubleTorus;
-  //SFToroidal;
-  ReDim(SizeX, SizeY, SizeZ, xMin, xMax, yMin, yMax, zMin, zMax);
-  FillVoxelData;
-end;
-
-destructor TGLMarchingCube.Destroy;
-begin
-  clean_all;
-  inherited;
-end;
-
-function TGLMarchingCube.getVoxelValue(i, j, k: Integer): TxScalarValue;
-begin
-  Result := VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY].Density
-end;
-
-function TGLMarchingCube.getVoxelData(i, j, k: Integer): TxVoxel;
-begin
-  Result := VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY]
-end;
-
-function TGLMarchingCube.Get_x_grad(i, j, k: Integer): Single;
-begin
-  if (i > 0) then
-    if (i < FSizeX - 1) then
-      Result := (getVoxelValue(i + 1, j, k) - getVoxelValue(i - 1, j, k)) / 2
-    else
-      Result := getVoxelValue(i, j, k) - getVoxelValue(i - 1, j, k)
-  else
-    Result := getVoxelValue(i + 1, j, k) - getVoxelValue(i, j, k)
-end;
-
-function TGLMarchingCube.Get_x_vert(i, j, k: Integer): Integer;
-begin
-  Result := PVertsX^[i + j * FSizeX + k * FSizeX * FSizeY]
-end;
-
-function TGLMarchingCube.Get_y_grad(i, j, k: Integer): Single;
-begin
-  if (j > 0) then
-    if (j < FSizeY - 1) then
-      Result := (getVoxelValue(i, j + 1, k) - getVoxelValue(i, j - 1, k)) / 2
-    else
-      Result := getVoxelValue(i, j, k) - getVoxelValue(i, j - 1, k)
-  else
-    Result := getVoxelValue(i, j + 1, k) - getVoxelValue(i, j, k)
-end;
-
-function TGLMarchingCube.Get_y_vert(i, j, k: Integer): Integer;
-begin
-  Result := PVertsY^[i + j * FSizeX + k * FSizeX * FSizeY]
-end;
-
-function TGLMarchingCube.Get_z_grad(i, j, k: Integer): Single;
-begin
-  if (k > 0) then
-    if (k < FSizeZ - 1) then
-      Result := (getVoxelValue(i, j, k + 1) - getVoxelValue(i, j, k - 1)) / 2
-    else
-      Result := getVoxelValue(i, j, k) - getVoxelValue(i, j, k - 1)
-  else
-    Result := getVoxelValue(i, j, k + 1) - getVoxelValue(i, j, k)
-end;
-
-function TGLMarchingCube.Get_z_vert(i, j, k: Integer): Integer;
-begin
-  Result := PVertsZ^[i + j * FSizeX + k * FSizeX * FSizeY]
-end;
-
-procedure TGLMarchingCube.Init_all;
-begin
-  Init_temps;
-  Init_space;
-
-  if (PVertices <> nil) then
-    FreeMem(PVertices);
-  if (PTriangles <> nil) then
-    FreeMem(PTriangles);
-  _Nverts := 0;
-  _Ntrigs := 0;
-  _Sverts := ALLOC_SIZE;
-  _Strigs := ALLOC_SIZE;
-
-  GetMem(PVertices, _Sverts * SizeOf(TxVertex));
-  GetMem(PTriangles, _Strigs * SizeOf(TxTriangle));
-end;
-
-procedure TGLMarchingCube.Init_space;
-begin
-  VoxelData := AllocMem(FSizeX * FSizeY * FSizeZ * SizeOf(TxVoxel));
-end;
-
-procedure TGLMarchingCube.Init_temps;
-var
-  spaceSize: Longword;
-begin
-  spaceSize := FSizeX * FSizeY * FSizeZ;
-  GetMem(PVertsX, spaceSize * SizeOf(Integer));
-  GetMem(PVertsY, spaceSize * SizeOf(Integer));
-  GetMem(PVertsZ, spaceSize * SizeOf(Integer));
-
-  FillChar(PVertsX^, spaceSize * SizeOf(Integer), -1);
-  FillChar(PVertsY^, spaceSize * SizeOf(Integer), -1);
-  FillChar(PVertsZ^, spaceSize * SizeOf(Integer), -1);
-end;
-
-function TGLMarchingCube.Internal(AValue: TxScalarValue): Boolean;
-begin
-  Result := AValue <= FIsoValue
-end;
-
-procedure TGLMarchingCube.process_cube;
-var
-  nt: Byte;
-begin
-  if (FOriginalMC) then
-  begin
-    nt := 0;
-    while (MC_TRITABLE[_lut_entry][3 * nt] <> -1) do
-      Inc(nt);
-    add_triangle(MC_TRITABLE[_lut_entry], nt);
-    Exit;
-  end;
-  /// TODO complete algorithm with various tiling...
-end;
-
-procedure TGLMarchingCube.Run;
-var
-  i, j, k, P: Integer;
-begin
-  if (PVertsX = nil) then
-  begin
-    Init_temps;
-    _Nverts := 0;
-    _Ntrigs := 0;
-  end;
-  Compute_Intersection_Points;
-  for k := 0 to FSizeZ - 2 do
-  begin
-    _k := k;
-    for j := 0 to FSizeY - 2 do
-    begin
-      _j := j;
-      for i := 0 to FSizeX - 2 do
-      begin
-        _i := i;
-        _lut_entry := 0;
-        for P := 0 to 7 do
-        begin
-          _Cube[P] := getVoxelData(i + ((P xor (P shr 1)) and 1),
-            j + ((P shr 1) and 1), k + ((P shr 2) and 1));
-          // _Cube[p]:= getVoxelData( i+((p^(p>>1))&1), j+((p>>1)&1), k+((p>>2)&1) ) ;
-          if (Internal(_Cube[P].Density)) then
-            _lut_entry := _lut_entry or (1 shl P);
-        end;
-        process_cube;
-      end
-    end
-  end;
-  clean_temps;
-end;
-
-procedure TGLMarchingCube.Run(IsoValue: TxScalarValue);
-begin
-  FIsoValue := IsoValue;
-  Run
-end;
-
-procedure TGLMarchingCube.setVoxelValue(i, j, k: Integer; HfValue: TxScalarValue);
-begin
-  VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY].Density := HfValue
-end;
-
-procedure TGLMarchingCube.set_x_vert(a_val, i, j, k: Integer);
-begin
-  PVertsX^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
-end;
-
-procedure TGLMarchingCube.set_y_vert(a_val, i, j, k: Integer);
-begin
-  PVertsY^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
-end;
-
-procedure TGLMarchingCube.set_z_vert(a_val, i, j, k: Integer);
-begin
-  PVertsZ^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
-end;
-
-procedure TGLMarchingCube.test_vertex_addiction;
-begin
-  if _Nverts >= _Sverts then
-  begin
-    _Sverts := 2 * _Sverts;
-    ReallocMem(PVertices, _Sverts * SizeOf(TxVertex))
-  end;
-end;
-
-function TGLMarchingCube.voxel(i, j, k: Integer): PxVoxel;
-begin
-  if (k >= FSizeZ) or (j >= FSizeY) or (i >= FSizeX) then
-    Result := nil
-  else
-    Result := @VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY]
-end;
-
-procedure TGLMarchingCube.FillVoxelData;
-var
-  iX, iY, iZ: Integer;
-  X, Y, Z: Single;
-begin
-  for iX := 0 to FSizeX - 1 do
-  begin
-    X := FxMin + iX * FStepX;
-    for iY := 0 to FSizeY - 1 do
-    begin
-      Y := FyMin + iY * FStepY;
-      for iZ := 0 to FSizeZ - 1 do
-        with VoxelData^[iX + iY * FSizeX + iZ * FSizeX * FSizeY] do
-        begin
-          Z := FzMin + iZ * FStepZ;
-          MakeVector(P, X, Y, Z);
-          Density := ScalarField(X, Y, Z);
-          if Internal(Density) then
-            Status := bpInternal
-          else
-            Status := bpExternal
-        end;
-    end;
-  end;
-end;
-
-procedure TGLMarchingCube.FillVoxelData(AIsoValue: TxScalarValue; AScalarField: TxScalarField = nil);
-begin
-  FIsoValue := AIsoValue;
-  if Assigned(AScalarField) then
-    ScalarField := AScalarField;
-  FillVoxelData;
-end;
-
-procedure TGLMarchingCube.FillVoxelData(AIsoValue: TxScalarValue; AScalarField: TxScalarFieldInt);
-var
-  iX, iY, iZ: Integer;
-  X, Y, Z: Single;
-begin
-  FIsoValue := AIsoValue;
-  for iX := 0 to FSizeX - 1 do
-  begin
-    X := FxMin + iX * FStepX;
-    for iY := 0 to FSizeY - 1 do
-    begin
-      Y := FyMin + iY * FStepY;
-      for iZ := 0 to FSizeZ - 1 do
-        with VoxelData^[iX + iY * FSizeX + iZ * FSizeX * FSizeY] do
-        begin
-          Z := FzMin + iZ * FStepZ;
-          MakeVector(P, X, Y, Z);
-          Density := AScalarField(iX, iY, iZ);
-          if Internal(Density) then
-            Status := bpInternal
-          else
-            Status := bpExternal
-        end;
-    end;
-  end;
-end;
-
-procedure TGLMarchingCube.CalcVertices(Vertices: TGLVertexList;
-  Alpha: Single = 1);
-var
-  i: Integer;
-  vx1, vx2, vx3: TGLVertexData;
-
-  function GetNrmColor(Nrm: TAffineVector): TVector;
-  begin
-    Result.V[0] := 0;
-    if Nrm.V[0] > 0.0 then
-      Result.V[0] := Result.V[0] + Nrm.V[0];
-    if Nrm.V[1] < 0.0 then
-      Result.V[0] := Result.V[0] - 0.5 * Nrm.V[1];
-    if Nrm.V[2] < 0.0 then
-      Result.V[0] := Result.V[0] - 0.5 * Nrm.V[2];
-
-    Result.V[1] := 1;
-    if Nrm.V[0] < 0.0 then
-      Result.V[1] := Result.V[1] - 0.5 * Nrm.V[0];
-    if Nrm.V[1] > 0.0 then
-      Result.V[1] := Result.V[1] + Nrm.V[1];
-    if Nrm.V[2] < 0.0 then
-      Result.V[1] := Result.V[1] - 0.5 * Nrm.V[2];
-
-    Result.V[2] := 0;
-    if Nrm.V[0] < 0.0 then
-      Result.V[2] := Result.V[2] - 0.5 * Nrm.V[0];
-    if Nrm.V[1] < 0.0 then
-      Result.V[2] := Result.V[2] - 0.5 * Nrm.V[1];
-    if Nrm.V[2] > 0.0 then
-      Result.V[2] := Result.V[2] + Nrm.V[2];
-    Result.V[3] := 0.3
-  end;
-
-  function GetColor(H: TxScalarValue): TVector;
-  begin
-    Result := VectorMake(0.890, 0.855, 0.788, Alpha)
-    (*
-      if H <= 10 then Result:= VectorMake(0.922, 0.957, 0.980, 1.000)  //<=10
-      else if H <= 50 then Result:= VectorMake(0.541, 0.027, 0.027, 1.000) // 10..50
-      else if H <= 300 then Result:= VectorMake(0.941, 0.910, 0.859, 1.000) //50..300
-      else if H <= 2000 then Result:= VectorMake(0.965, 0.969, 0.973, 1.000) //350.. 2000
-      else if H <= 4000 then Result:= VectorMake(0.890, 0.855, 0.788, 1.000) //2000..4000
-      else Result:= VectorMake(0.9, 0.9, 0.6, 1.0)
-    *)
-  end;
-
-begin
-  Vertices.Clear;
-  Vertices.Capacity := 3 * _Ntrigs;
-
-  for i := 0 to _Ntrigs - 1 do
-    with PTriangles^[i] do
-    begin
-      vx1.coord := PVertices^[v1].P;
-      vx1.normal := PVertices^[v1].N;
-      vx2.coord := PVertices^[v2].P;
-      vx2.normal := PVertices^[v2].N;
-      vx3.coord := PVertices^[v3].P;
-      vx3.normal := PVertices^[v3].N;
-{$IFDEF UseDensity}
-      vx1.Color := GetColor(PVertices^[v1].Density); // GetNrmColor(vx1.normal);
-      vx2.Color := GetColor(PVertices^[v2].Density); // GetNrmColor(vx2.normal);
-      vx3.Color := GetColor(PVertices^[v3].Density); // GetNrmColor(vx3.normal);
-{$ELSE}
-      vx1.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
-      vx2.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
-      vx3.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
-{$ENDIF}
-      // Vertices.AddVertex3(vx1, vx2, vx3); seems to be correct the next line
-      Vertices.AddVertex3(vx3, vx2, vx1);
-    end;
-end;
-
-procedure TGLMarchingCube.CalcMeshObject(AMeshObject: TMeshObject; Alpha: Single);
-var
-  i: Integer;
-begin
-  AMeshObject.Clear;
-  AMeshObject.Vertices.Capacity := _Nverts;
-  AMeshObject.Normals.Capacity := _Nverts;
-  AMeshObject.Colors.Capacity := _Nverts;
-  with TFGVertexIndexList.CreateOwned(AMeshObject.FaceGroups) do
-  begin
-    Mode := fgmmTriangles;
-    for i := 0 to _Nverts - 1 do
-    begin
-      AMeshObject.Vertices.Add(PVertices^[i].P);
-      AMeshObject.Normals.Add(PVertices^[i].N);
-      // AMeshObject.Normals.Add(VectorScale(PVertices^[i].N, -1));
-      // AMeshObject.Colors.Add(VectorMake(0.890, 0.855, 0.788, Alpha));
-    end;
-
-    for i := 0 to _Ntrigs - 1 do
-      // with PTriangles^[i] do VertexIndices.Add(v1, v2, v3);
-      with PTriangles^[i] do
-        VertexIndices.Add(v3, v2, v1);
-  end;
-end;
-
-
-
+  Scene.VectorTypes,
+  Scene.VectorRecTypes;
+
+const
+  ALLOC_SIZE = 65536;
+
+type
+  TSingle3DArray = array of array of array of Single;
+  TVertexArray = array of TVector3f;
+  TIntegerArray = array of Integer;
+
+  TGLMarchingCube = class(TObject)
+  private
+    FIsoValue: TxScalarValue;
+    // sliceSize:Longword;
+    PVertsX: PIntegerArray;
+    PVertsY: PIntegerArray;
+    PVertsZ: PIntegerArray;
+    _Nverts: Integer;
+    _Ntrigs: Integer;
+    _Sverts: Integer;
+    _Strigs: Integer;
+    PVertices: PxVertexArray;
+    PTriangles: PxTriangleArray;
+    _i, _j, _k: Longword;
+    _Cube: array [0 .. 7] of TxVoxel;
+    _lut_entry: Byte;
+    // _case:Byte;
+    // _config:Byte;
+    // _subconfig:Byte;
+    procedure Init_temps;
+    procedure Init_all;
+    procedure Init_space;
+    procedure Clean_temps;
+    procedure Clean_all(keepFacets: Boolean = False);
+    procedure Clean_space;
+    procedure Test_vertex_addiction;
+  protected
+    FOriginalMC: Boolean; // now only original MC is implemented
+    FSizeX: Integer;
+    FSizeY: Integer;
+    FSizeZ: Integer;
+    FxMin: Single;
+    FxMax: Single;
+    FyMin: Single;
+    FyMax: Single;
+    FzMin: Single;
+    FzMax: Single;
+    FStepX: Single;
+    FStepY: Single;
+    FStepZ: Single;
+    VoxelData: PxVoxelData;
+    procedure Process_cube;
+    { function test_face(face:byte):Boolean;
+      function test_interior(s:Byte):boolean }
+    procedure Compute_Intersection_Points;
+    procedure Add_Triangle(trig: array of Integer; N: Byte; v12: Integer = -1);
+    function Add_x_vertex: Integer;
+    function Add_y_vertex: Integer;
+    function Add_z_vertex: Integer;
+    function Add_c_vertex: Integer;
+    function Get_x_grad(i, j, k: Integer): Single;
+    function Get_y_grad(i, j, k: Integer): Single;
+    function Get_z_grad(i, j, k: Integer): Single;
+    function Get_x_vert(i, j, k: Integer): Integer;
+    function Get_y_vert(i, j, k: Integer): Integer;
+    function Get_z_vert(i, j, k: Integer): Integer;
+    procedure Set_x_vert(a_val, i, j, k: Integer);
+    procedure Set_y_vert(a_val, i, j, k: Integer);
+    procedure Set_z_vert(a_val, i, j, k: Integer);
+    function GetVoxelValue(i, j, k: Integer): TxScalarValue;
+    procedure SetVoxelValue(i, j, k: Integer; HfValue: TxScalarValue);
+    function GetVoxelData(i, j, k: Integer): TxVoxel;
+    function Voxel(i, j, k: Integer): PxVoxel;
+    function calc_u(v1, v2: Single): Single; virtual;
+  public
+    ScalarField: TxScalarField;
+    constructor Create; overload; virtual;
+    constructor Create(SizeX, SizeY, SizeZ: Integer;
+      AIsoValue: TxScalarValue = 0.0; xMin: Single = -0.5; xMax: Single = 0.5;
+      yMin: Single = -0.5; yMax: Single = 0.5; zMin: Single = -0.5;
+      zMax: Single = 0.5); overload; virtual;
+    procedure ReDim(ASizeX, ASizeY, ASizeZ: Integer;
+      xMin, xMax, yMin, yMax, zMin, zMax: Single); virtual;
+    destructor Destroy; override;
+    procedure Run; overload;
+    procedure Run(IsoValue: TxScalarValue); overload;
+    function Internal(AValue: TxScalarValue): Boolean; virtual;
+    procedure FillVoxelData; overload; virtual;
+    procedure FillVoxelData(AIsoValue: TxScalarValue;
+      AScalarField: TxScalarField = nil); overload; virtual;
+    procedure FillVoxelData(AIsoValue: TxScalarValue;
+      AScalarField: TxScalarFieldInt); overload; virtual;
+    procedure CalcVertices(Vertices: TGLVertexList; Alpha: Single = 1);
+    procedure CalcMeshObject(AMeshObject: TMeshObject; Alpha: Single = 1);
+    property IsoValue: TxScalarValue read FIsoValue write FIsoValue;
+    // TODO SetIsoValue to Run
+  end;
+
+  (* 3D isosurface extractor class. This class allows to calculate and exctract
+    isosurfaces from scalar field voxel models using a given isovalue *)
+  TIsoSurfaceExtractor = class(TObject)
+  private
+    Data: TSingle3DArray;
+    Dimensions: array ['x' .. 'z'] of Integer;
+    // Build Index depending on whether the edges are outside or inside the surface
+    function BuildIndex(var ADatavals: array of Single; Isovalue: Single): word;
+    function Interpolate(const V0, V1: TAffineVector;
+      var Val0, Val1, Isovalue: Single; isPolished: boolean): TVertex;
+  public
+    constructor Create(); overload;
+    constructor Create(Xdim, Ydim, Zdim: Integer;
+      var AData: TSingle3DArray); overload;
+    destructor Destroy(); override;
+    procedure AssignData(Xdim, Ydim, Zdim: Integer; var AData: TSingle3DArray);
+    { Launch Marching Cubes }
+    procedure MarchingCubes(Isovalue: Single; out Vertices: TVertexArray;
+      out Triangles: TIntegerArray; isPolished: boolean);
+    { Launch Marching Tetrahedra }
+    procedure MarchingTetrahedra(Isovalue: Single; out Vertices: TVertexArray;
+      out Triangles: TIntegerArray; isPolished: boolean);
+  end;
+
+// Sphere surface
+function SFSphere(X, Y, Z: Single): TxScalarValue;
+// Minkowski space (http://mathworld.wolfram.com)
+function SFMinkowski(X, Y, Z: Single): TxScalarValue;
+// Klein Bottle (http://mathworld.wolfram.com)
+function SFKleinBottle(X, Y, Z: Single): TxScalarValue;
+// Chmutov-surface-1 (http://mathworld.wolfram.com)
+function SFChmutov1(X, Y, Z: Single): TxScalarValue;
+// Chmutov-surface-2 (http://mathworld.wolfram.com)
+function SFChmutov2(X, Y, Z: Single): TxScalarValue;
+// Toroidal surface (phantasy!)
+function SFToroidal(X, Y, Z: Single): TxScalarValue;
+// Double torus Surface (phantasy!)
+function SFDoubleTorus(X, Y, Z: Single): TxScalarValue;
+
+const
+  DemoScalarField: array [0 .. 6] of
+  record
+    // xMin, xMax, yMin, yMax, zMin, zMax:Single; // default -0.5..0.5
+    ScalarField: TxScalarField;
+    IsoValue: TxScalarValue
+  end = ((ScalarField: SFSphere; IsoValue: 0.3), (ScalarField: SFMinkowski;
+  IsoValue: 0.0), (ScalarField: SFKleinBottle; IsoValue: 0.0),
+  (ScalarField: SFChmutov1; IsoValue: 3.0), (ScalarField: SFChmutov2;
+  IsoValue: 3.0), (ScalarField: SFToroidal; IsoValue: 3.0),
+  (ScalarField: SFDoubleTorus; IsoValue: 0.015));
+
+// -------------------------------------------------------------------------
+implementation
+// -------------------------------------------------------------------------
+
+const
+  // Classic Cases for Marching Cube TriTable
+  //
+  (*
+        4----4------5
+       /|          /|
+      7 |         5 |
+     /  |        /  |
+    7-----6----6    |
+    |   8       |   9
+    |   |       |   |
+    |   0----0--|---1
+    11 /        10 /
+    | 3         | 1
+    |/          |/
+    3-----2-----2
+  *)
+
+  MC_TRITABLE: array [0 .. 255, 0 .. 15] of Integer = (
+(*   0:                          *)  ( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   1: 0,                       *)  (  0,  8,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   2:    1,                    *)  (  0,  1,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   3: 0, 1,                    *)  (  1,  8,  3,  9,  8,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   4:       2,                 *)  (  1,  2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   5: 0,    2,                 *)  (  0,  8,  3,  1,  2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   6:    1, 2,                 *)  (  9,  2, 10,  0,  2,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   7: 0, 1, 2,                 *)  (  2,  8,  3,  2, 10,  8, 10,  9,  8, -1, -1, -1, -1, -1, -1, -1 ),
+(*   8:          3,              *)  (  3, 11,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*   9: 0,       3,              *)  (  0, 11,  2,  8, 11,  0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  10:    1,    3,              *)  (  1,  9,  0,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  11: 0, 1,    3,              *)  (  1, 11,  2,  1,  9, 11,  9,  8, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(*  12:       2, 3,              *)  (  3, 10,  1, 11, 10,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  13: 0,    2, 3,              *)  (  0, 10,  1,  0,  8, 10,  8, 11, 10, -1, -1, -1, -1, -1, -1, -1 ),
+(*  14:    1, 2, 3,              *)  (  3,  9,  0,  3, 11,  9, 11, 10,  9, -1, -1, -1, -1, -1, -1, -1 ),
+(*  15: 0, 1, 2, 3,              *)  (  9,  8, 10, 10,  8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  16:             4,           *)  (  4,  7,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  17: 0,          4,           *)  (  4,  3,  0,  7,  3,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  18:    1,       4,           *)  (  0,  1,  9,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  19: 0, 1,       4,           *)  (  4,  1,  9,  4,  7,  1,  7,  3,  1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  20:       2,    4,           *)  (  1,  2, 10,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  21: 0,    2,    4,           *)  (  3,  4,  7,  3,  0,  4,  1,  2, 10, -1, -1, -1, -1, -1, -1, -1 ),
+(*  22:    1, 2,    4,           *)  (  9,  2, 10,  9,  0,  2,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(*  23: 0, 1, 2,    4,           *)  (  2, 10,  9,  2,  9,  7,  2,  7,  3,  7,  9,  4, -1, -1, -1, -1 ),
+(*  24:          3, 4,           *)  (  8,  4,  7,  3, 11,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  25: 0,       3, 4,           *)  ( 11,  4,  7, 11,  2,  4,  2,  0,  4, -1, -1, -1, -1, -1, -1, -1 ),
+(*  26:    1,    3, 4,           *)  (  9,  0,  1,  8,  4,  7,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(*  27: 0, 1,    3, 4,           *)  (  4,  7, 11,  9,  4, 11,  9, 11,  2,  9,  2,  1, -1, -1, -1, -1 ),
+(*  28:       2, 3, 4,           *)  (  3, 10,  1,  3, 11, 10,  7,  8,  4, -1, -1, -1, -1, -1, -1, -1 ),
+(*  29: 0,    2, 3, 4,           *)  (  1, 11, 10,  1,  4, 11,  1,  0,  4,  7, 11,  4, -1, -1, -1, -1 ),
+(*  30:    1, 2, 3, 4,           *)  (  4,  7,  8,  9,  0, 11,  9, 11, 10, 11,  0,  3, -1, -1, -1, -1 ),
+(*  31: 0, 1, 2, 3, 4,           *)  (  4,  7, 11,  4, 11,  9,  9, 11, 10, -1, -1, -1, -1, -1, -1, -1 ),
+(*  32:                5,        *)  (  9,  5,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  33: 0,             5,        *)  (  9,  5,  4,  0,  8,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  34:    1,          5,        *)  (  0,  5,  4,  1,  5,  0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  35: 0, 1,          5,        *)  (  8,  5,  4,  8,  3,  5,  3,  1,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(*  36:       2,       5,        *)  (  1,  2, 10,  9,  5,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  37: 0,    2,       5,        *)  (  3,  0,  8,  1,  2, 10,  4,  9,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(*  38:    1, 2,       5,        *)  (  5,  2, 10,  5,  4,  2,  4,  0,  2, -1, -1, -1, -1, -1, -1, -1 ),
+(*  39: 0, 1, 2,       5,        *)  (  2, 10,  5,  3,  2,  5,  3,  5,  4,  3,  4,  8, -1, -1, -1, -1 ),
+(*  40:          3,    5,        *)  (  9,  5,  4,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  41: 0,       3,    5,        *)  (  0, 11,  2,  0,  8, 11,  4,  9,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(*  42:    1,    3,    5,        *)  (  0,  5,  4,  0,  1,  5,  2,  3, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(*  43: 0, 1,    3,    5,        *)  (  2,  1,  5,  2,  5,  8,  2,  8, 11,  4,  8,  5, -1, -1, -1, -1 ),
+(*  44:       2, 3,    5,        *)  ( 10,  3, 11, 10,  1,  3,  9,  5,  4, -1, -1, -1, -1, -1, -1, -1 ),
+(*  45: 0,    2, 3,    5,        *)  (  4,  9,  5,  0,  8,  1,  8, 10,  1,  8, 11, 10, -1, -1, -1, -1 ),
+(*  46:    1, 2, 3,    5,        *)  (  5,  4,  0,  5,  0, 11,  5, 11, 10, 11,  0,  3, -1, -1, -1, -1 ),
+(*  47: 0, 1, 2, 3,    5,        *)  (  5,  4,  8,  5,  8, 10, 10,  8, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(*  48:             4, 5,        *)  (  9,  7,  8,  5,  7,  9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  49: 0,          4, 5,        *)  (  9,  3,  0,  9,  5,  3,  5,  7,  3, -1, -1, -1, -1, -1, -1, -1 ),
+(*  50:    1,       4, 5,        *)  (  0,  7,  8,  0,  1,  7,  1,  5,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(*  51: 0, 1,       4, 5,        *)  (  1,  5,  3,  3,  5,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  52:       2,    4, 5,        *)  (  9,  7,  8,  9,  5,  7, 10,  1,  2, -1, -1, -1, -1, -1, -1, -1 ),
+(*  53: 0,    2,    4, 5,        *)  ( 10,  1,  2,  9,  5,  0,  5,  3,  0,  5,  7,  3, -1, -1, -1, -1 ),
+(*  54:    1, 2,    4, 5,        *)  (  8,  0,  2,  8,  2,  5,  8,  5,  7, 10,  5,  2, -1, -1, -1, -1 ),
+(*  55: 0, 1, 2,    4, 5,        *)  (  2, 10,  5,  2,  5,  3,  3,  5,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(*  56:          3, 4, 5,        *)  (  7,  9,  5,  7,  8,  9,  3, 11,  2, -1, -1, -1, -1, -1, -1, -1 ),
+(*  57: 0,       3, 4, 5,        *)  (  9,  5,  7,  9,  7,  2,  9,  2,  0,  2,  7, 11, -1, -1, -1, -1 ),
+(*  58:    1,    3, 4, 5,        *)  (  2,  3, 11,  0,  1,  8,  1,  7,  8,  1,  5,  7, -1, -1, -1, -1 ),
+(*  59: 0, 1,    3, 4, 5,        *)  ( 11,  2,  1, 11,  1,  7,  7,  1,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(*  60:       2, 3, 4, 5,        *)  (  9,  5,  8,  8,  5,  7, 10,  1,  3, 10,  3, 11, -1, -1, -1, -1 ),
+(*  61: 0,    2, 3, 4, 5,        *)  (  5,  7,  0,  5,  0,  9,  7, 11,  0,  1,  0, 10, 11, 10,  0, -1 ),
+(*  62:    1, 2, 3, 4, 5,        *)  ( 11, 10,  0, 11,  0,  3, 10,  5,  0,  8,  0,  7,  5,  7,  0, -1 ),
+(*  63: 0, 1, 2, 3, 4, 5,        *)  ( 11, 10,  5,  7, 11,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  64:                   6,     *)  ( 10,  6,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  65: 0,                6,     *)  (  0,  8,  3,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  66:    1,             6,     *)  (  9,  0,  1,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  67: 0, 1,             6,     *)  (  1,  8,  3,  1,  9,  8,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(*  68:       2,          6,     *)  (  1,  6,  5,  2,  6,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  69: 0,    2,          6,     *)  (  1,  6,  5,  1,  2,  6,  3,  0,  8, -1, -1, -1, -1, -1, -1, -1 ),
+(*  70:    1, 2,          6,     *)  (  9,  6,  5,  9,  0,  6,  0,  2,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(*  71: 0, 1, 2,          6,     *)  (  5,  9,  8,  5,  8,  2,  5,  2,  6,  3,  2,  8, -1, -1, -1, -1 ),
+(*  72:          3,       6,     *)  (  2,  3, 11, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  73: 0,       3,       6,     *)  ( 11,  0,  8, 11,  2,  0, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(*  74:    1,    3,       6,     *)  (  0,  1,  9,  2,  3, 11,  5, 10,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(*  75: 0, 1,    3,       6,     *)  (  5, 10,  6,  1,  9,  2,  9, 11,  2,  9,  8, 11, -1, -1, -1, -1 ),
+(*  76:       2, 3,       6,     *)  (  6,  3, 11,  6,  5,  3,  5,  1,  3, -1, -1, -1, -1, -1, -1, -1 ),
+(*  77: 0,    2, 3,       6,     *)  (  0,  8, 11,  0, 11,  5,  0,  5,  1,  5, 11,  6, -1, -1, -1, -1 ),
+(*  78:    1, 2, 3,       6,     *)  (  3, 11,  6,  0,  3,  6,  0,  6,  5,  0,  5,  9, -1, -1, -1, -1 ),
+(*  79: 0, 1, 2, 3,       6,     *)  (  6,  5,  9,  6,  9, 11, 11,  9,  8, -1, -1, -1, -1, -1, -1, -1 ),
+(*  80:             4,    6,     *)  (  5, 10,  6,  4,  7,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  81: 0,          4,    6,     *)  (  4,  3,  0,  4,  7,  3,  6,  5, 10, -1, -1, -1, -1, -1, -1, -1 ),
+(*  82:    1,       4,    6,     *)  (  1,  9,  0,  5, 10,  6,  8,  4,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(*  83: 0, 1,       4,    6,     *)  ( 10,  6,  5,  1,  9,  7,  1,  7,  3,  7,  9,  4, -1, -1, -1, -1 ),
+(*  84:       2,    4,    6,     *)  (  6,  1,  2,  6,  5,  1,  4,  7,  8, -1, -1, -1, -1, -1, -1, -1 ),
+(*  85: 0,    2,    4,    6,     *)  (  1,  2,  5,  5,  2,  6,  3,  0,  4,  3,  4,  7, -1, -1, -1, -1 ),
+(*  86:    1, 2,    4,    6,     *)  (  8,  4,  7,  9,  0,  5,  0,  6,  5,  0,  2,  6, -1, -1, -1, -1 ),
+(*  87: 0, 1, 2,    4,    6,     *)  (  7,  3,  9,  7,  9,  4,  3,  2,  9,  5,  9,  6,  2,  6,  9, -1 ),
+(*  88:          3, 4,    6,     *)  (  3, 11,  2,  7,  8,  4, 10,  6,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(*  89: 0,       3, 4,    6,     *)  (  5, 10,  6,  4,  7,  2,  4,  2,  0,  2,  7, 11, -1, -1, -1, -1 ),
+(*  90:    1,    3, 4,    6,     *)  (  0,  1,  9,  4,  7,  8,  2,  3, 11,  5, 10,  6, -1, -1, -1, -1 ),
+(*  91: 0, 1,    3, 4,    6,     *)  (  9,  2,  1,  9, 11,  2,  9,  4, 11,  7, 11,  4,  5, 10,  6, -1 ),
+(*  92:       2, 3, 4,    6,     *)  (  8,  4,  7,  3, 11,  5,  3,  5,  1,  5, 11,  6, -1, -1, -1, -1 ),
+(*  93: 0,    2, 3, 4,    6,     *)  (  5,  1, 11,  5, 11,  6,  1,  0, 11,  7, 11,  4,  0,  4, 11, -1 ),
+(*  94:    1, 2, 3, 4,    6,     *)  (  0,  5,  9,  0,  6,  5,  0,  3,  6, 11,  6,  3,  8,  4,  7, -1 ),
+(*  95: 0, 1, 2, 3, 4,    6,     *)  (  6,  5,  9,  6,  9, 11,  4,  7,  9,  7, 11,  9, -1, -1, -1, -1 ),
+(*  96:                5, 6,     *)  ( 10,  4,  9,  6,  4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(*  97: 0,             5, 6,     *)  (  4, 10,  6,  4,  9, 10,  0,  8,  3, -1, -1, -1, -1, -1, -1, -1 ),
+(*  98:    1,          5, 6,     *)  ( 10,  0,  1, 10,  6,  0,  6,  4,  0, -1, -1, -1, -1, -1, -1, -1 ),
+(*  99: 0, 1,          5, 6,     *)  (  8,  3,  1,  8,  1,  6,  8,  6,  4,  6,  1, 10, -1, -1, -1, -1 ),
+(* 100:       2,       5, 6,     *)  (  1,  4,  9,  1,  2,  4,  2,  6,  4, -1, -1, -1, -1, -1, -1, -1 ),
+(* 101: 0,    2,       5, 6,     *)  (  3,  0,  8,  1,  2,  9,  2,  4,  9,  2,  6,  4, -1, -1, -1, -1 ),
+(* 102:    1, 2,       5, 6,     *)  (  0,  2,  4,  4,  2,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 103: 0, 1, 2,       5, 6,     *)  (  8,  3,  2,  8,  2,  4,  4,  2,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(* 104:          3,    5, 6,     *)  ( 10,  4,  9, 10,  6,  4, 11,  2,  3, -1, -1, -1, -1, -1, -1, -1 ),
+(* 105: 0,       3,    5, 6,     *)  (  0,  8,  2,  2,  8, 11,  4,  9, 10,  4, 10,  6, -1, -1, -1, -1 ),
+(* 106:    1,    3,    5, 6,     *)  (  3, 11,  2,  0,  1,  6,  0,  6,  4,  6,  1, 10, -1, -1, -1, -1 ),
+(* 107: 0, 1,    3,    5, 6,     *)  (  6,  4,  1,  6,  1, 10,  4,  8,  1,  2,  1, 11,  8, 11,  1, -1 ),
+(* 108:       2, 3,    5, 6,     *)  (  9,  6,  4,  9,  3,  6,  9,  1,  3, 11,  6,  3, -1, -1, -1, -1 ),
+(* 109: 0,    2, 3,    5, 6,     *)  (  8, 11,  1,  8,  1,  0, 11,  6,  1,  9,  1,  4,  6,  4,  1, -1 ),
+(* 110:    1, 2, 3,    5, 6,     *)  (  3, 11,  6,  3,  6,  0,  0,  6,  4, -1, -1, -1, -1, -1, -1, -1 ),
+(* 111: 0, 1, 2, 3,    5, 6,     *)  (  6,  4,  8, 11,  6,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 112:             4, 5, 6,     *)  (  7, 10,  6,  7,  8, 10,  8,  9, 10, -1, -1, -1, -1, -1, -1, -1 ),
+(* 113: 0,          4, 5, 6,     *)  (  0,  7,  3,  0, 10,  7,  0,  9, 10,  6,  7, 10, -1, -1, -1, -1 ),
+(* 114:    1,       4, 5, 6,     *)  ( 10,  6,  7,  1, 10,  7,  1,  7,  8,  1,  8,  0, -1, -1, -1, -1 ),
+(* 115: 0, 1,       4, 5, 6,     *)  ( 10,  6,  7, 10,  7,  1,  1,  7,  3, -1, -1, -1, -1, -1, -1, -1 ),
+(* 116:       2,    4, 5, 6,     *)  (  1,  2,  6,  1,  6,  8,  1,  8,  9,  8,  6,  7, -1, -1, -1, -1 ),
+(* 117: 0,    2,    4, 5, 6,     *)  (  2,  6,  9,  2,  9,  1,  6,  7,  9,  0,  9,  3,  7,  3,  9, -1 ),
+(* 118:    1, 2,    4, 5, 6,     *)  (  7,  8,  0,  7,  0,  6,  6,  0,  2, -1, -1, -1, -1, -1, -1, -1 ),
+(* 119: 0, 1, 2,    4, 5, 6,     *)  (  7,  3,  2,  6,  7,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 120:          3, 4, 5, 6,     *)  (  2,  3, 11, 10,  6,  8, 10,  8,  9,  8,  6,  7, -1, -1, -1, -1 ),
+(* 121: 0,       3, 4, 5, 6,     *)  (  2,  0,  7,  2,  7, 11,  0,  9,  7,  6,  7, 10,  9, 10,  7, -1 ),
+(* 122:    1,    3, 4, 5, 6,     *)  (  1,  8,  0,  1,  7,  8,  1, 10,  7,  6,  7, 10,  2,  3, 11, -1 ),
+(* 123: 0, 1,    3, 4, 5, 6,     *)  ( 11,  2,  1, 11,  1,  7, 10,  6,  1,  6,  7,  1, -1, -1, -1, -1 ),
+(* 124:       2, 3, 4, 5, 6,     *)  (  8,  9,  6,  8,  6,  7,  9,  1,  6, 11,  6,  3,  1,  3,  6, -1 ),
+(* 125: 0,    2, 3, 4, 5, 6,     *)  (  0,  9,  1, 11,  6,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 126:    1, 2, 3, 4, 5, 6,     *)  (  7,  8,  0,  7,  0,  6,  3, 11,  0, 11,  6,  0, -1, -1, -1, -1 ),
+(* 127: 0, 1, 2, 3, 4, 5, 6,     *)  (  7, 11,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 128:                      7,  *)  (  7,  6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 129: 0,                   7,  *)  (  3,  0,  8, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 130:    1,                7,  *)  (  0,  1,  9, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 131: 0, 1,                7,  *)  (  8,  1,  9,  8,  3,  1, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(* 132:       2,             7,  *)  ( 10,  1,  2,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 133: 0,    2,             7,  *)  (  1,  2, 10,  3,  0,  8,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(* 134:    1, 2,             7,  *)  (  2,  9,  0,  2, 10,  9,  6, 11,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(* 135: 0, 1, 2,             7,  *)  (  6, 11,  7,  2, 10,  3, 10,  8,  3, 10,  9,  8, -1, -1, -1, -1 ),
+(* 136:          3,          7,  *)  (  7,  2,  3,  6,  2,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 137: 0,       3,          7,  *)  (  7,  0,  8,  7,  6,  0,  6,  2,  0, -1, -1, -1, -1, -1, -1, -1 ),
+(* 138:    1,    3,          7,  *)  (  2,  7,  6,  2,  3,  7,  0,  1,  9, -1, -1, -1, -1, -1, -1, -1 ),
+(* 139: 0, 1,    3,          7,  *)  (  1,  6,  2,  1,  8,  6,  1,  9,  8,  8,  7,  6, -1, -1, -1, -1 ),
+(* 140:       2, 3,          7,  *)  ( 10,  7,  6, 10,  1,  7,  1,  3,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(* 141: 0,    2, 3,          7,  *)  ( 10,  7,  6,  1,  7, 10,  1,  8,  7,  1,  0,  8, -1, -1, -1, -1 ),
+(* 142:    1, 2, 3,          7,  *)  (  0,  3,  7,  0,  7, 10,  0, 10,  9,  6, 10,  7, -1, -1, -1, -1 ),
+(* 143: 0, 1, 2, 3,          7,  *)  (  7,  6, 10,  7, 10,  8,  8, 10,  9, -1, -1, -1, -1, -1, -1, -1 ),
+(* 144:             4,       7,  *)  (  6,  8,  4, 11,  8,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 145: 0,          4,       7,  *)  (  3,  6, 11,  3,  0,  6,  0,  4,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(* 146:    1,       4,       7,  *)  (  8,  6, 11,  8,  4,  6,  9,  0,  1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 147: 0, 1,       4,       7,  *)  (  9,  4,  6,  9,  6,  3,  9,  3,  1, 11,  3,  6, -1, -1, -1, -1 ),
+(* 148:       2,    4,       7,  *)  (  6,  8,  4,  6, 11,  8,  2, 10,  1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 149: 0,    2,    4,       7,  *)  (  1,  2, 10,  3,  0, 11,  0,  6, 11,  0,  4,  6, -1, -1, -1, -1 ),
+(* 150:    1, 2,    4,       7,  *)  (  4, 11,  8,  4,  6, 11,  0,  2,  9,  2, 10,  9, -1, -1, -1, -1 ),
+(* 151: 0, 1, 2,    4,       7,  *)  ( 10,  9,  3, 10,  3,  2,  9,  4,  3, 11,  3,  6,  4,  6,  3, -1 ),
+(* 152:          3, 4,       7,  *)  (  8,  2,  3,  8,  4,  2,  4,  6,  2, -1, -1, -1, -1, -1, -1, -1 ),
+(* 153: 0,       3, 4,       7,  *)  (  0,  4,  2,  4,  6,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 154:    1,    3, 4,       7,  *)  (  1,  9,  0,  2,  3,  4,  2,  4,  6,  4,  3,  8, -1, -1, -1, -1 ),
+(* 155: 0, 1,    3, 4,       7,  *)  (  1,  9,  4,  1,  4,  2,  2,  4,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(* 156:       2, 3, 4,       7,  *)  (  8,  1,  3,  8,  6,  1,  8,  4,  6,  6, 10,  1, -1, -1, -1, -1 ),
+(* 157: 0,    2, 3, 4,       7,  *)  ( 10,  1,  0, 10,  0,  6,  6,  0,  4, -1, -1, -1, -1, -1, -1, -1 ),
+(* 158:    1, 2, 3, 4,       7,  *)  (  4,  6,  3,  4,  3,  8,  6, 10,  3,  0,  3,  9, 10,  9,  3, -1 ),
+(* 159: 0, 1, 2, 3, 4,       7,  *)  ( 10,  9,  4,  6, 10,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 160:                5,    7,  *)  (  4,  9,  5,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 161: 0,             5,    7,  *)  (  0,  8,  3,  4,  9,  5, 11,  7,  6, -1, -1, -1, -1, -1, -1, -1 ),
+(* 162:    1,          5,    7,  *)  (  5,  0,  1,  5,  4,  0,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(* 163: 0, 1,          5,    7,  *)  ( 11,  7,  6,  8,  3,  4,  3,  5,  4,  3,  1,  5, -1, -1, -1, -1 ),
+(* 164:       2,       5,    7,  *)  (  9,  5,  4, 10,  1,  2,  7,  6, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(* 165: 0,    2,       5,    7,  *)  (  6, 11,  7,  1,  2, 10,  0,  8,  3,  4,  9,  5, -1, -1, -1, -1 ),
+(* 166:    1, 2,       5,    7,  *)  (  7,  6, 11,  5,  4, 10,  4,  2, 10,  4,  0,  2, -1, -1, -1, -1 ),
+(* 167: 0, 1, 2,       5,    7,  *)  (  3,  4,  8,  3,  5,  4,  3,  2,  5, 10,  5,  2, 11,  7,  6, -1 ),
+(* 168:          3,    5,    7,  *)  (  7,  2,  3,  7,  6,  2,  5,  4,  9, -1, -1, -1, -1, -1, -1, -1 ),
+(* 169: 0,       3,    5,    7,  *)  (  9,  5,  4,  0,  8,  6,  0,  6,  2,  6,  8,  7, -1, -1, -1, -1 ),
+(* 170:    1,    3,    5,    7,  *)  (  3,  6,  2,  3,  7,  6,  1,  5,  0,  5,  4,  0, -1, -1, -1, -1 ),
+(* 171: 0, 1,    3,    5,    7,  *)  (  6,  2,  8,  6,  8,  7,  2,  1,  8,  4,  8,  5,  1,  5,  8, -1 ),
+(* 172:       2, 3,    5,    7,  *)  (  9,  5,  4, 10,  1,  6,  1,  7,  6,  1,  3,  7, -1, -1, -1, -1 ),
+(* 173: 0,    2, 3,    5,    7,  *)  (  1,  6, 10,  1,  7,  6,  1,  0,  7,  8,  7,  0,  9,  5,  4, -1 ),
+(* 174:    1, 2, 3,    5,    7,  *)  (  4,  0, 10,  4, 10,  5,  0,  3, 10,  6, 10,  7,  3,  7, 10, -1 ),
+(* 175: 0, 1, 2, 3,    5,    7,  *)  (  7,  6, 10,  7, 10,  8,  5,  4, 10,  4,  8, 10, -1, -1, -1, -1 ),
+(* 176:             4, 5,    7,  *)  (  6,  9,  5,  6, 11,  9, 11,  8,  9, -1, -1, -1, -1, -1, -1, -1 ),
+(* 177: 0,          4, 5,    7,  *)  (  3,  6, 11,  0,  6,  3,  0,  5,  6,  0,  9,  5, -1, -1, -1, -1 ),
+(* 178:    1,       4, 5,    7,  *)  (  0, 11,  8,  0,  5, 11,  0,  1,  5,  5,  6, 11, -1, -1, -1, -1 ),
+(* 179: 0, 1,       4, 5,    7,  *)  (  6, 11,  3,  6,  3,  5,  5,  3,  1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 180:       2,    4, 5,    7,  *)  (  1,  2, 10,  9,  5, 11,  9, 11,  8, 11,  5,  6, -1, -1, -1, -1 ),
+(* 181: 0,    2,    4, 5,    7,  *)  (  0, 11,  3,  0,  6, 11,  0,  9,  6,  5,  6,  9,  1,  2, 10, -1 ),
+(* 182:    1, 2,    4, 5,    7,  *)  ( 11,  8,  5, 11,  5,  6,  8,  0,  5, 10,  5,  2,  0,  2,  5, -1 ),
+(* 183: 0, 1, 2,    4, 5,    7,  *)  (  6, 11,  3,  6,  3,  5,  2, 10,  3, 10,  5,  3, -1, -1, -1, -1 ),
+(* 184:          3, 4, 5,    7,  *)  (  5,  8,  9,  5,  2,  8,  5,  6,  2,  3,  8,  2, -1, -1, -1, -1 ),
+(* 185: 0,       3, 4, 5,    7,  *)  (  9,  5,  6,  9,  6,  0,  0,  6,  2, -1, -1, -1, -1, -1, -1, -1 ),
+(* 186:    1,    3, 4, 5,    7,  *)  (  1,  5,  8,  1,  8,  0,  5,  6,  8,  3,  8,  2,  6,  2,  8, -1 ),
+(* 187: 0, 1,    3, 4, 5,    7,  *)  (  1,  5,  6,  2,  1,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 188:       2, 3, 4, 5,    7,  *)  (  1,  3,  6,  1,  6, 10,  3,  8,  6,  5,  6,  9,  8,  9,  6, -1 ),
+(* 189: 0,    2, 3, 4, 5,    7,  *)  ( 10,  1,  0, 10,  0,  6,  9,  5,  0,  5,  6,  0, -1, -1, -1, -1 ),
+(* 190:    1, 2, 3, 4, 5,    7,  *)  (  0,  3,  8,  5,  6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 191: 0, 1, 2, 3, 4, 5,    7,  *)  ( 10,  5,  6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 192:                   6, 7,  *)  ( 11,  5, 10,  7,  5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 193: 0,                6, 7,  *)  ( 11,  5, 10, 11,  7,  5,  8,  3,  0, -1, -1, -1, -1, -1, -1, -1 ),
+(* 194:    1,             6, 7,  *)  (  5, 11,  7,  5, 10, 11,  1,  9,  0, -1, -1, -1, -1, -1, -1, -1 ),
+(* 195: 0, 1,             6, 7,  *)  ( 10,  7,  5, 10, 11,  7,  9,  8,  1,  8,  3,  1, -1, -1, -1, -1 ),
+(* 196:       2,          6, 7,  *)  ( 11,  1,  2, 11,  7,  1,  7,  5,  1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 197: 0,    2,          6, 7,  *)  (  0,  8,  3,  1,  2,  7,  1,  7,  5,  7,  2, 11, -1, -1, -1, -1 ),
+(* 198:    1, 2,          6, 7,  *)  (  9,  7,  5,  9,  2,  7,  9,  0,  2,  2, 11,  7, -1, -1, -1, -1 ),
+(* 199: 0, 1, 2,          6, 7,  *)  (  7,  5,  2,  7,  2, 11,  5,  9,  2,  3,  2,  8,  9,  8,  2, -1 ),
+(* 200:          3,       6, 7,  *)  (  2,  5, 10,  2,  3,  5,  3,  7,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(* 201: 0,       3,       6, 7,  *)  (  8,  2,  0,  8,  5,  2,  8,  7,  5, 10,  2,  5, -1, -1, -1, -1 ),
+(* 202:    1,    3,       6, 7,  *)  (  9,  0,  1,  5, 10,  3,  5,  3,  7,  3, 10,  2, -1, -1, -1, -1 ),
+(* 203: 0, 1,    3,       6, 7,  *)  (  9,  8,  2,  9,  2,  1,  8,  7,  2, 10,  2,  5,  7,  5,  2, -1 ),
+(* 204:       2, 3,       6, 7,  *)  (  1,  3,  5,  3,  7,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 205: 0,    2, 3,       6, 7,  *)  (  0,  8,  7,  0,  7,  1,  1,  7,  5, -1, -1, -1, -1, -1, -1, -1 ),
+(* 206:    1, 2, 3,       6, 7,  *)  (  9,  0,  3,  9,  3,  5,  5,  3,  7, -1, -1, -1, -1, -1, -1, -1 ),
+(* 207: 0, 1, 2, 3,       6, 7,  *)  (  9,  8,  7,  5,  9,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 208:             4,    6, 7,  *)  (  5,  8,  4,  5, 10,  8, 10, 11,  8, -1, -1, -1, -1, -1, -1, -1 ),
+(* 209: 0,          4,    6, 7,  *)  (  5,  0,  4,  5, 11,  0,  5, 10, 11, 11,  3,  0, -1, -1, -1, -1 ),
+(* 210:    1,       4,    6, 7,  *)  (  0,  1,  9,  8,  4, 10,  8, 10, 11, 10,  4,  5, -1, -1, -1, -1 ),
+(* 211: 0, 1,       4,    6, 7,  *)  ( 10, 11,  4, 10,  4,  5, 11,  3,  4,  9,  4,  1,  3,  1,  4, -1 ),
+(* 212:       2,    4,    6, 7,  *)  (  2,  5,  1,  2,  8,  5,  2, 11,  8,  4,  5,  8, -1, -1, -1, -1 ),
+(* 213: 0,    2,    4,    6, 7,  *)  (  0,  4, 11,  0, 11,  3,  4,  5, 11,  2, 11,  1,  5,  1, 11, -1 ),
+(* 214:    1, 2,    4,    6, 7,  *)  (  0,  2,  5,  0,  5,  9,  2, 11,  5,  4,  5,  8, 11,  8,  5, -1 ),
+(* 215: 0, 1, 2,    4,    6, 7,  *)  (  9,  4,  5,  2, 11,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 216:          3, 4,    6, 7,  *)  (  2,  5, 10,  3,  5,  2,  3,  4,  5,  3,  8,  4, -1, -1, -1, -1 ),
+(* 217: 0,       3, 4,    6, 7,  *)  (  5, 10,  2,  5,  2,  4,  4,  2,  0, -1, -1, -1, -1, -1, -1, -1 ),
+(* 218:    1,    3, 4,    6, 7,  *)  (  3, 10,  2,  3,  5, 10,  3,  8,  5,  4,  5,  8,  0,  1,  9, -1 ),
+(* 219: 0, 1,    3, 4,    6, 7,  *)  (  5, 10,  2,  5,  2,  4,  1,  9,  2,  9,  4,  2, -1, -1, -1, -1 ),
+(* 220:       2, 3, 4,    6, 7,  *)  (  8,  4,  5,  8,  5,  3,  3,  5,  1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 221: 0,    2, 3, 4,    6, 7,  *)  (  0,  4,  5,  1,  0,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 222:    1, 2, 3, 4,    6, 7,  *)  (  8,  4,  5,  8,  5,  3,  9,  0,  5,  0,  3,  5, -1, -1, -1, -1 ),
+(* 223: 0, 1, 2, 3, 4,    6, 7,  *)  (  9,  4,  5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 224:                5, 6, 7,  *)  (  4, 11,  7,  4,  9, 11,  9, 10, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(* 225: 0,             5, 6, 7,  *)  (  0,  8,  3,  4,  9,  7,  9, 11,  7,  9, 10, 11, -1, -1, -1, -1 ),
+(* 226:    1,          5, 6, 7,  *)  (  1, 10, 11,  1, 11,  4,  1,  4,  0,  7,  4, 11, -1, -1, -1, -1 ),
+(* 227: 0, 1,          5, 6, 7,  *)  (  3,  1,  4,  3,  4,  8,  1, 10,  4,  7,  4, 11, 10, 11,  4, -1 ),
+(* 228:       2,       5, 6, 7,  *)  (  4, 11,  7,  9, 11,  4,  9,  2, 11,  9,  1,  2, -1, -1, -1, -1 ),
+(* 229: 0,    2,       5, 6, 7,  *)  (  9,  7,  4,  9, 11,  7,  9,  1, 11,  2, 11,  1,  0,  8,  3, -1 ),
+(* 230:    1, 2,       5, 6, 7,  *)  ( 11,  7,  4, 11,  4,  2,  2,  4,  0, -1, -1, -1, -1, -1, -1, -1 ),
+(* 231: 0, 1, 2,       5, 6, 7,  *)  ( 11,  7,  4, 11,  4,  2,  8,  3,  4,  3,  2,  4, -1, -1, -1, -1 ),
+(* 232:          3,    5, 6, 7,  *)  (  2,  9, 10,  2,  7,  9,  2,  3,  7,  7,  4,  9, -1, -1, -1, -1 ),
+(* 233: 0,       3,    5, 6, 7,  *)  (  9, 10,  7,  9,  7,  4, 10,  2,  7,  8,  7,  0,  2,  0,  7, -1 ),
+(* 234:    1,    3,    5, 6, 7,  *)  (  3,  7, 10,  3, 10,  2,  7,  4, 10,  1, 10,  0,  4,  0, 10, -1 ),
+(* 235: 0, 1,    3,    5, 6, 7,  *)  (  1, 10,  2,  8,  7,  4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 236:       2, 3,    5, 6, 7,  *)  (  4,  9,  1,  4,  1,  7,  7,  1,  3, -1, -1, -1, -1, -1, -1, -1 ),
+(* 237: 0,    2, 3,    5, 6, 7,  *)  (  4,  9,  1,  4,  1,  7,  0,  8,  1,  8,  7,  1, -1, -1, -1, -1 ),
+(* 238:    1, 2, 3,    5, 6, 7,  *)  (  4,  0,  3,  7,  4,  3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 239: 0, 1, 2, 3,    5, 6, 7,  *)  (  4,  8,  7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 240:             4, 5, 6, 7,  *)  (  9, 10,  8, 10, 11,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 241: 0,          4, 5, 6, 7,  *)  (  3,  0,  9,  3,  9, 11, 11,  9, 10, -1, -1, -1, -1, -1, -1, -1 ),
+(* 242:    1,       4, 5, 6, 7,  *)  (  0,  1, 10,  0, 10,  8,  8, 10, 11, -1, -1, -1, -1, -1, -1, -1 ),
+(* 243: 0, 1,       4, 5, 6, 7,  *)  (  3,  1, 10, 11,  3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 244:       2,    4, 5, 6, 7,  *)  (  1,  2, 11,  1, 11,  9,  9, 11,  8, -1, -1, -1, -1, -1, -1, -1 ),
+(* 245: 0,    2,    4, 5, 6, 7,  *)  (  3,  0,  9,  3,  9, 11,  1,  2,  9,  2, 11,  9, -1, -1, -1, -1 ),
+(* 246:    1, 2,    4, 5, 6, 7,  *)  (  0,  2, 11,  8,  0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 247: 0, 1, 2,    4, 5, 6, 7,  *)  (  3,  2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 248:          3, 4, 5, 6, 7,  *)  (  2,  3,  8,  2,  8, 10, 10,  8,  9, -1, -1, -1, -1, -1, -1, -1 ),
+(* 249: 0,       3, 4, 5, 6, 7,  *)  (  9, 10,  2,  0,  9,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 250:    1,    3, 4, 5, 6, 7,  *)  (  2,  3,  8,  2,  8, 10,  0,  1,  8,  1, 10,  8, -1, -1, -1, -1 ),
+(* 251: 0, 1,    3, 4, 5, 6, 7,  *)  (  1, 10,  2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 252:       2, 3, 4, 5, 6, 7,  *)  (  1,  3,  8,  9,  1,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 253: 0,    2, 3, 4, 5, 6, 7,  *)  (  0,  9,  1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 254:    1, 2, 3, 4, 5, 6, 7,  *)  (  0,  3,  8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
+(* 255: 0, 1, 2, 3, 4, 5, 6, 7,  *)  ( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 )
+);
+
+
+// Marching Cube EdgeTable
+const
+  MC_EDGETABLE: array [0 .. 11, 0 .. 1] of Integer = ((0, 1), (1, 2), (2, 3),
+    (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7));
+
+  // Marching Tetrahedra TriTable
+  (*
+        + 0
+         /|\
+        / | \
+       /  |  0
+      3   |   \
+     /    2    \
+    /     |     \
+   +----4--------+ 1
+  3 \     |     /
+     \    |    /
+      5   |   1
+       \  |  /
+        \ | /
+         \|/
+        + 2
+*)
+  MT_TRITABLE: array [0 .. 15, 0 .. 6] of Integer =
+    ((-1, -1, -1, -1, -1, -1, -1), (2, 3, 0, -1, -1, -1, -1),
+    (4, 1, 0, -1, -1, -1, -1), (2, 4, 1, 3, 4, 2, -1),
+    (5, 2, 1, -1, -1, -1, -1), (5, 3, 0, 1, 5, 0, -1), (5, 2, 0, 4, 5, 0, -1),
+    (3, 4, 5, -1, -1, -1, -1), (5, 4, 3, -1, -1, -1, -1),
+    (0, 5, 4, 0, 2, 5, -1), (0, 5, 1, 0, 3, 5, -1), (1, 2, 5, -1, -1, -1, -1),
+    (2, 4, 3, 1, 4, 2, -1), (0, 1, 4, -1, -1, -1, -1),
+    (0, 3, 2, -1, -1, -1, -1), (-1, -1, -1, -1, -1, -1, -1));
+
+  // Marching Tetrahedra EdgeTable
+  MT_EDGETABLE: array [0 .. 5, 0 .. 1] of Integer = ((0, 1), (1, 2), (2, 0),
+    (0, 3), (1, 3), (2, 3));
+
+  // Marching Tetrahedra CubeSplit
+  MT_CUBESPLIT: array [0 .. 5, 0 .. 3] of Integer = ((0, 5, 1, 6), (0, 1, 2, 6),
+    (0, 2, 3, 6), (0, 3, 7, 6), (0, 7, 4, 6), (0, 4, 5, 6));
+
+// Test surface functions
+function SFSphere(X, Y, Z: Single): TxScalarValue;
+begin
+  Result := sqr(X) + sqr(Y) + sqr(Z)
+end;
+
+function SFToroidal(X, Y, Z: Single): TxScalarValue;
+const
+  FScale = 7;
+  a = 2.5;
+begin
+  X := FScale * X;
+  Y := FScale * Y;
+  Z := FScale * Z;
+  Result := (sqr(sqrt(sqr(X) + sqr(Y)) - a) + sqr(Z)) *
+    (sqr(sqrt(sqr(Y) + sqr(Z)) - a) + sqr(X)) *
+    (sqr(sqrt(sqr(Z) + sqr(X)) - a) + sqr(Y));
+end;
+
+function SFDoubleTorus(X, Y, Z: Single): TxScalarValue;
+const
+  FScale = 2.25;
+begin
+  X := FScale * X;
+  Y := FScale * Y;
+  Z := FScale * Z;
+  Result := PowerInteger(X, 8) + PowerInteger(X, 4) - 2 * PowerInteger(X, 6) - 2
+    * sqr(X) * sqr(Y) + 2 * PowerInteger(X, 4) * sqr(Y) +
+    PowerInteger(Y, 4) + sqr(Z)
+end;
+
+function SFChmutov1(X, Y, Z: Single): TxScalarValue;
+const
+  FScale = 2.5;
+begin
+  X := FScale * X;
+  Y := FScale * Y;
+  Z := FScale * Z;
+  Result := 8 * (sqr(X) + sqr(Y) + sqr(Z)) - 8 *
+    (PowerInteger(X, 4) + PowerInteger(Y, 4) + PowerInteger(Z, 4));
+end;
+
+function SFChmutov2(X, Y, Z: Single): TxScalarValue;
+const
+  FScale = 2.5;
+begin
+  X := FScale * X;
+  Y := FScale * Y;
+  Z := FScale * Z;
+  Result := 2 * (sqr(X) * sqr(3 - 4 * sqr(X)) + sqr(Y) * sqr(3 - 4 * sqr(Y)) +
+    sqr(Z) * sqr(3 - 4 * sqr(Z)));
+end;
+
+function SFKleinBottle(X, Y, Z: Single): TxScalarValue;
+const
+  FScale = 7.5;
+begin
+  X := FScale * X;
+  Y := FScale * Y;
+  Z := FScale * Z;
+  Result := (sqr(X) + sqr(Y) + sqr(Z) + 2 * Y - 1) *
+    (sqr(sqr(X) + sqr(Y) + sqr(Z) - 2 * Y - 1) - 8 * sqr(Z)) + 16 * X * Z *
+    (sqr(X) + sqr(Y) + sqr(Z) - 2 * Y - 1);
+end;
+
+function SFMinkowski(X, Y, Z: Single): TxScalarValue;
+const
+  FScale = 7;
+begin
+  X := FScale * X;
+  Y := FScale * Y;
+  Z := FScale * Z;
+  Result := (sqr(X) - sqr(Y) - sqr(Z) - 2) * (sqr(X) - sqr(Y) - sqr(Z) + 2) *
+    (sqr(X) - sqr(Y) - sqr(Z) - 4) * (sqr(X) - sqr(Y) - sqr(Z) + 4) *
+    (sqr(X) - sqr(Y) - sqr(Z));
+end;
+
+(* -------------------------------------------------------------------------
+   Class IsoSurfaceExtractor
+   Purpose: Extract an Isosurface from volume dataset for given Isovalue
+   ------------------------------------------------------------------------- *)
+
+function TIsoSurfaceExtractor.BuildIndex(var ADatavals: array of Single;
+  Isovalue: Single): word;
+var
+  i: Integer;
+  val: word;
+begin
+  val := 1;
+  Result := 0;
+  for i := 1 to Length(ADatavals) do
+  begin
+    if ADatavals[i - 1] <= Isovalue then // Edge inside surface
+      Result := Result + val;
+    val := val * 2;
+  end;
+end;
+
+// Compute intersection point of edge and surface by linear interpolation
+function InterpolateRugged(V0, V1: TAffineVector;
+  var Val0, Val1, Isovalue: Single): TVertex;
+var
+  Diff: Single;
+  i: Integer;
+begin
+  if Val0 <= Isovalue then
+  begin
+    Diff := Val0 / (Val0 + Val1);
+    for i := 0 to 2 do
+      Result.V[i] := V0.V[i] + Diff * (V1.V[i] - V0.V[i]);
+  end
+  else
+  begin
+    Diff := Val1 / (Val0 + Val1);
+    for i := 0 to 2 do
+      Result.V[i] := V1.V[i] + Diff * (V0.V[i] - V1.V[i]);
+  end;
+end;
+
+function InterpolatePolished(V0, V1: TAffineVector;
+  var Val0, Val1, Isovalue: Single): TVertex;
+var
+  w0, w1: Single;
+begin
+  if (Val0 = Val1) then
+    w1 := 0.5
+  else
+    w1 := (Isovalue - Val0) / (Val1 - Val0);
+  w0 := 1.0 - w1;
+  Result.X := w0 * V0.X + w1 * V1.X;
+  Result.Y := w0 * V0.Y + w1 * V1.Y;
+  Result.Z := w0 * V0.Z + w1 * V1.Z;
+end;
+
+function TIsoSurfaceExtractor.Interpolate(const V0, V1: TAffineVector;
+  var Val0, Val1, Isovalue: Single; isPolished: boolean): TVertex;
+begin
+  if isPolished then
+    Result := InterpolatePolished(V0, V1, Val0, Val1, Isovalue)
+  else
+    Result := InterpolateRugged(V0, V1, Val0, Val1, Isovalue)
+end;
+
+procedure TIsoSurfaceExtractor.MarchingTetrahedra(Isovalue: Single;
+  out Vertices: TVertexArray; out Triangles: TIntegerArray; isPolished: boolean);
+var
+  i, j, k: Integer;
+  index: word;
+  CubeVertices: array of TAffineVector;
+  Tetrahedron: array [0 .. 3] of TAffineVector;
+  DataTetra: array [0 .. 3] of Single;
+
+  // Add Triangle to List
+  procedure AppendTri();
+  var
+    edge: byte;
+    Ver1, Ver2, Ver3: TVertex;
+    VListlength: Integer;
+    TListlength: Integer;
+  begin
+    edge := 0;
+    while MT_TRITABLE[index, edge] <> -1 do
+    begin
+      Ver1 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge], 0]
+        ], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge], 1]],
+        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge], 0]],
+        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge], 1]], Isovalue, isPolished);
+      Ver2 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 1],
+        0]], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 1]],
+        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 0]],
+        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 1]], Isovalue, isPolished);
+      Ver3 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 2],
+        0]], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 1]],
+        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 0]],
+        DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 1]], Isovalue, isPolished);
+      VListlength := Length(Vertices) + 3;
+      TListlength := Length(Triangles) + 3;
+      SetLength(Vertices, VListlength);
+      SetLength(Triangles, TListlength);
+      Vertices[VListlength - 3] := Ver1;
+      Vertices[VListlength - 2] := Ver2;
+      Vertices[VListlength - 1] := Ver3;
+      Triangles[TListlength - 3] := VListlength - 3;
+      Triangles[TListlength - 2] := VListlength - 2;
+      Triangles[TListlength - 1] := VListlength - 1;
+      edge := edge + 3;
+    end;
+  end;
+
+// Split Cube in 6 Tetrahedrons and process each tetrahedron
+  procedure SplitCube();
+  var
+    i, j: Integer;
+  begin
+    for i := 0 to 5 do
+    begin
+      for j := 0 to 3 do
+      begin
+        Tetrahedron[j] := CubeVertices[MT_CUBESPLIT[i, j]];
+        DataTetra[j] := Data[Trunc(Tetrahedron[j].X),
+          Trunc(Tetrahedron[j].Y), Trunc(Tetrahedron[j].Z)];
+      end;
+      index := BuildIndex(DataTetra, Isovalue);
+      AppendTri();
+    end;
+  end;
+
+begin
+(*
+      1----2
+     /|   /|
+    0----3 |
+    | 5--|-6
+    |/   |/
+    4----7
+*)
+  SetLength(CubeVertices, 8);
+  for k := 0 to Dimensions['z'] - 2 do
+  begin
+    for j := 0 to Dimensions['y'] - 2 do
+    begin
+      for i := 0 to Dimensions['x'] - 2 do
+      begin
+        CubeVertices[0] := AffineVectorMake(i, j, k);
+        CubeVertices[1] := AffineVectorMake(i, j, k + 1);
+        CubeVertices[2] := AffineVectorMake(i + 1, j, k + 1);
+        CubeVertices[3] := AffineVectorMake(i + 1, j, k);
+        CubeVertices[4] := AffineVectorMake(i, j + 1, k);
+        CubeVertices[5] := AffineVectorMake(i, j + 1, k + 1);
+        CubeVertices[6] := AffineVectorMake(i + 1, j + 1, k + 1);
+        CubeVertices[7] := AffineVectorMake(i + 1, j + 1, k);
+
+        SplitCube();
+      end; // for k
+    end; // for j
+  end; // for i
+end; // ccMT
+
+constructor TIsoSurfaceExtractor.Create;
+begin
+  inherited;
+end;
+
+constructor TIsoSurfaceExtractor.Create(Xdim, Ydim, Zdim: Integer;
+  var AData: TSingle3DArray);
+begin
+  Create();
+  AssignData(Xdim, Ydim, Zdim, AData);
+end;
+
+destructor TIsoSurfaceExtractor.Destroy;
+begin
+  inherited;
+end;
+
+procedure TIsoSurfaceExtractor.AssignData(Xdim, Ydim, Zdim: Integer;
+  var AData: TSingle3DArray);
+begin
+  Dimensions['x'] := Xdim;
+  Dimensions['y'] := Ydim;
+  Dimensions['z'] := Zdim;
+
+  Data := AData;
+end;
+
+//-----------------------------------------------------------------------
+procedure TIsoSurfaceExtractor.MarchingCubes(Isovalue: Single;
+  out Vertices: TVertexArray; out Triangles: TIntegerArray; isPolished: boolean);
+var
+  i, j, k: Integer;
+  index: word;
+  CubeVertices: array [0 .. 7] of TAffineVector;
+  CubeData: array [0 .. 7] of Single;
+
+  procedure AppendTri();
+  var
+    edge: byte;
+    Ver1, Ver2, Ver3: TVertex;
+    VListlength: Integer;
+    TListlength: Integer;
+  begin
+    edge := 0;
+    while MC_TRITABLE[index, edge] <> -1 do
+    begin
+      Ver1 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge], 0]
+        ], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge], 1]],
+        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge], 0]],
+        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge], 1]], Isovalue, isPolished);
+      Ver2 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index,
+        edge + 1], 0]], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge + 1],
+        1]], CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 1], 0]],
+        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 1], 1]], Isovalue, isPolished);
+      Ver3 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index,
+        edge + 2], 0]], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge + 2],
+        1]], CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 2], 0]],
+        CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 2], 1]], Isovalue, isPolished);
+      VListlength := Length(Vertices) + 3;
+      TListlength := Length(Triangles) + 3;
+      SetLength(Vertices, VListlength);
+      SetLength(Triangles, TListlength);
+      Vertices[VListlength - 3] := Ver1;
+      Vertices[VListlength - 2] := Ver2;
+      Vertices[VListlength - 1] := Ver3;
+      Triangles[TListlength - 3] := VListlength - 3;
+      Triangles[TListlength - 2] := VListlength - 2;
+      Triangles[TListlength - 1] := VListlength - 1;
+      edge := edge + 3;
+    end;
+  end;
+
+begin
+  (*
+      7----6
+     /|   /|
+    3----2 |
+    | 4--|-5
+    |/   |/
+    0----1
+  *)
+  for i := 0 to Dimensions['x'] - 2 do
+  begin
+    for j := 1 to Dimensions['y'] - 1 do
+    begin
+      for k := 0 to Dimensions['z'] - 2 do
+      begin
+        CubeVertices[0] := AffineVectorMake(i, j, k);
+        CubeVertices[1] := AffineVectorMake(i + 1, j, k);
+        CubeVertices[2] := AffineVectorMake(i + 1, j - 1, k);
+        CubeVertices[3] := AffineVectorMake(i, j - 1, k);
+        CubeVertices[4] := AffineVectorMake(i, j, k + 1);
+        CubeVertices[5] := AffineVectorMake(i + 1, j, k + 1);
+        CubeVertices[6] := AffineVectorMake(i + 1, j - 1, k + 1);
+        CubeVertices[7] := AffineVectorMake(i, j - 1, k + 1);
+        CubeData[0] := Data[i, j, k];
+        CubeData[1] := Data[i + 1, j, k];
+        CubeData[2] := Data[i + 1, j - 1, k];
+        CubeData[3] := Data[i, j - 1, k];
+        CubeData[4] := Data[i, j, k + 1];
+        CubeData[5] := Data[i + 1, j, k + 1];
+        CubeData[6] := Data[i + 1, j - 1, k + 1];
+        CubeData[7] := Data[i, j - 1, k + 1];
+
+        Index := BuildIndex(CubeData, Isovalue);
+        AppendTri();
+      end; // for k
+    end; // for j
+  end; // for i
+end;
+
+
+function TGLMarchingCube.add_c_vertex: Integer;
+var
+  u: Single;
+  vid: Integer;
+  procedure VertexAdd(iv: Integer);
+  begin
+    with PVertices^[_Nverts] do
+    begin
+      u := u + 1;
+      P := VectorAdd(P, PVertices[iv].P);
+      N := VectorAdd(N, PVertices[iv].N);
+{$IFDEF UseDensity}
+      Density := Density + PVertices[iv].Density;
+{$ENDIF}
+    end
+  end;
+
+begin
+  test_vertex_addiction;
+
+  u := 0;
+  with PVertices^[_Nverts] do
+  begin
+    P := NullVector;
+    N := NullVector;
+{$IFDEF UseDensity}
+    Density := 0;
+{$ENDIF}
+  end;
+  Inc(_Nverts);
+
+  // Computes the average of the intersection points of the cube
+  vid := Get_x_vert(_i, _j, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_y_vert(_i + 1, _j, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_x_vert(_i, _j + 1, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_y_vert(_i, _j, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_x_vert(_i, _j, _k + 1);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_y_vert(_i + 1, _j, _k + 1);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_x_vert(_i, _j + 1, _k + 1);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_y_vert(_i, _j, _k + 1);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_z_vert(_i, _j, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_z_vert(_i + 1, _j, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_z_vert(_i + 1, _j + 1, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+  vid := Get_z_vert(_i, _j + 1, _k);
+  if (vid <> -1) then
+    VertexAdd(vid);
+
+  ScaleVector(PVertices^[_Nverts].P, 1 / u);
+  NormalizeVector(PVertices^[_Nverts].N);
+{$IFDEF UseDensity}
+  PVertices^[_Nverts].Density := PVertices^[_Nverts].Density / u;
+{$ENDIF}
+  Result := _Nverts - 1;
+end;
+
+procedure TGLMarchingCube.add_triangle(trig: array of Integer; N: Byte;
+  v12: Integer = -1);
+
+var
+  tv: array [0 .. 2] of Integer;
+  t, tmod3: Integer;
+
+begin
+  for t := 0 to 3 * N - 1 do
+  begin
+    tmod3 := t mod 3;
+    case trig[t] of
+      0: tv[tmod3] := Get_x_vert(_i, _j, _k);
+      1: tv[tmod3] := Get_y_vert(_i + 1, _j, _k);
+      2: tv[tmod3] := Get_x_vert(_i, _j + 1, _k);
+      3: tv[tmod3] := Get_y_vert(_i, _j, _k);
+      4: tv[tmod3] := Get_x_vert(_i, _j, _k + 1);
+      5: tv[tmod3] := Get_y_vert(_i + 1, _j, _k + 1);
+      6: tv[tmod3] := Get_x_vert(_i, _j + 1, _k + 1);
+      7: tv[tmod3] := Get_y_vert(_i, _j, _k + 1);
+      8: tv[tmod3] := Get_z_vert(_i, _j, _k);
+      9: tv[tmod3] := Get_z_vert(_i + 1, _j, _k);
+      10: tv[tmod3] := Get_z_vert(_i + 1, _j + 1, _k);
+      11: tv[tmod3] := Get_z_vert(_i, _j + 1, _k);
+      12: tv[tmod3] := v12
+    end;
+
+    if (tv[tmod3] = -1) then
+      Break;
+
+    if (tmod3 = 2) then
+    begin
+      if (_Ntrigs >= _Strigs) then
+      begin
+        _Strigs := 2 * _Strigs;
+        ReallocMem(PTriangles, _Strigs * SizeOf(TxTriangle));
+      end;
+
+      with PTriangles^[_Ntrigs] do
+      begin
+        v1 := tv[0];
+        v2 := tv[1];
+        v3 := tv[2];
+      end;
+      Inc(_Ntrigs);
+
+    end
+  end
+end;
+
+function TGLMarchingCube.calc_u(v1, v2: Single): Single;
+begin
+  if (abs(FIsoValue - v1) >= 0.00001) then
+    Result := 1
+  else if (abs(FIsoValue - v2) >= 0.00001) then
+    Result := 0
+  else if (abs(v1 - v2) >= 0.00001) then
+    Result := (FIsoValue - v1) / (v2 - v1)
+  else
+    Result := 0.5
+end;
+
+function TGLMarchingCube.add_x_vertex: Integer;
+var
+  u: Single;
+begin
+  test_vertex_addiction;
+  u := calc_u(_Cube[0].Density, _Cube[1].Density);
+
+  with PVertices^[_Nverts] do
+  begin
+    P.X := _Cube[0].P.X + u * FStepX;
+    P.Y := _Cube[0].P.Y;
+    P.Z := _Cube[0].P.Z;
+
+    N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i + 1, _j, _k);
+    N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i + 1, _j, _k);
+    N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i + 1, _j, _k);
+    NormalizeVector(N);
+{$IFDEF UseDensity}
+    Density := _Cube[1].Density
+{$ENDIF}
+  end;
+  Inc(_Nverts);
+  Result := _Nverts - 1;
+end;
+
+function TGLMarchingCube.add_y_vertex: Integer;
+var
+  u: Single;
+begin
+  test_vertex_addiction;
+  u := calc_u(_Cube[0].Density, _Cube[3].Density);
+
+  with PVertices^[_Nverts] do
+  begin
+    P.X := _Cube[0].P.X;
+    P.Y := _Cube[0].P.Y + u * FStepY;
+    P.Z := _Cube[0].P.Z;
+
+    N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i, _j + 1, _k);
+    N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i, _j + 1, _k);
+    N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i, _j + 1, _k);
+    NormalizeVector(N);
+{$IFDEF UseDensity}
+    Density := _Cube[3].Density
+{$ENDIF}
+  end;
+  Inc(_Nverts);
+  Result := _Nverts - 1;
+end;
+
+function TGLMarchingCube.add_z_vertex: Integer;
+var
+  u: Single;
+begin
+  test_vertex_addiction;
+  u := calc_u(_Cube[0].Density, _Cube[4].Density);
+
+  with PVertices^[_Nverts] do
+  begin
+    P.X := _Cube[0].P.X;
+    P.Y := _Cube[0].P.Y;
+    P.Z := _Cube[0].P.Z + u * FStepZ;;
+
+    N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i, _j, _k + 1);
+    N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i, _j, _k + 1);
+    N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i, _j, _k + 1);
+    NormalizeVector(N);
+{$IFDEF UseDensity}
+    Density := _Cube[4].Density
+{$ENDIF}
+  end;
+  Inc(_Nverts);
+  Result := _Nverts - 1;
+end;
+
+procedure TGLMarchingCube.clean_all(keepFacets: Boolean = False);
+begin
+  clean_temps;
+  clean_space;
+  if (not keepFacets) then
+    FreeMem(PVertices);
+  FreeMem(PTriangles);
+  PVertices := nil;
+  PTriangles := nil;
+  _Nverts := 0;
+  _Ntrigs := 0;
+  _Sverts := 0;
+  _Strigs := 0;
+end;
+
+procedure TGLMarchingCube.clean_space;
+begin
+  if (VoxelData <> nil) then
+  begin
+    FreeMem(VoxelData);
+    VoxelData := nil
+  end;
+  FSizeX := 0;
+  FSizeY := 0;
+  FSizeZ := 0
+end;
+
+procedure TGLMarchingCube.clean_temps;
+begin
+  FreeMem(PVertsX);
+  PVertsX := nil;
+  FreeMem(PVertsY);
+  PVertsY := nil;
+  FreeMem(PVertsZ);
+  PVertsZ := nil;
+end;
+
+procedure TGLMarchingCube.compute_intersection_points;
+var
+  k, j, i: Integer;
+begin
+  _Cube[0] := getVoxelData(0, 0, 0);
+  _Cube[1] := getVoxelData(1, 0, 0);
+  _Cube[3] := getVoxelData(0, 1, 0);
+  _Cube[4] := getVoxelData(0, 0, 1);
+  { _step_x:= _Cube[1].P[0] - _Cube[0].P[0] ;
+    _step_y:= _Cube[3].P[1] - _Cube[0].P[1] ;
+    _step_z:= _Cube[4].P[2] - _Cube[0].P[2] ; }
+
+  for k := 0 to FSizeZ - 2 do
+  begin
+    _k := k;
+    for j := 0 to FSizeY - 2 do
+    begin
+      _j := j;
+      for i := 0 to FSizeX - 2 do
+      begin
+        _i := i;
+        _Cube[0] := getVoxelData(_i, _j, _k);
+        _Cube[1] := getVoxelData(_i + 1, _j, _k);
+        _Cube[3] := getVoxelData(_i, _j + 1, _k);
+        _Cube[4] := getVoxelData(_i, _j, _k + 1);
+
+        if (Internal(_Cube[0].Density)) then
+        begin
+          if (not Internal(_Cube[1].Density)) then
+            set_x_vert(add_x_vertex(), _i, _j, _k);
+          if (not Internal(_Cube[3].Density)) then
+            set_y_vert(add_y_vertex(), _i, _j, _k);
+          if (not Internal(_Cube[4].Density)) then
+            set_z_vert(add_z_vertex(), _i, _j, _k);
+        end
+        else
+        begin
+          if (Internal(_Cube[1].Density)) then
+            set_x_vert(add_x_vertex(), _i, _j, _k);
+          if (Internal(_Cube[3].Density)) then
+            set_y_vert(add_y_vertex(), _i, _j, _k);
+          if (Internal(_Cube[4].Density)) then
+            set_z_vert(add_z_vertex(), _i, _j, _k);
+        end
+      end
+    end
+  end
+end;
+
+procedure TGLMarchingCube.ReDim(ASizeX, ASizeY, ASizeZ: Integer;
+  xMin, xMax, yMin, yMax, zMin, zMax: Single);
+begin
+  clean_all;
+  FSizeX := ASizeX;
+  FSizeY := ASizeY;
+  FSizeZ := ASizeZ;
+  FxMin := xMin;
+  FxMax := xMax;
+  FyMin := yMin;
+  FyMax := yMax;
+  FzMin := zMin;
+  FzMax := zMax;
+
+  FStepX := (FxMax - FxMin) / (FSizeX - 1);
+  FStepY := (FyMax - FyMin) / (FSizeY - 1);
+  FStepZ := (FzMax - FzMin) / (FSizeZ - 1);
+
+  VoxelData := nil;
+  PVertsX := nil;
+  PVertsY := nil;
+  PVertsZ := nil;
+  _Nverts := 0;
+  _Ntrigs := 0;
+  _Sverts := 0;
+  _Strigs := 0;
+  PVertices := nil;
+  PTriangles := nil;
+
+  Init_all;
+  // FillVoxelData;
+end;
+
+constructor TGLMarchingCube.Create;
+begin
+  FOriginalMC := True; // now only original MC is implemented
+  FIsoValue := 0;
+  ScalarField := nil;
+  // SFSphere;//SFKleinBottle;//SFMinkowski;// SFChmutov2;// SFChmutov1;//SFDoubleTorus;// SFToroidal;
+
+  VoxelData := nil;
+  PVertsX := nil;
+  PVertsY := nil;
+  PVertsZ := nil;
+  _Nverts := 0;
+  _Ntrigs := 0;
+  _Sverts := 0;
+  _Strigs := 0;
+  PVertices := nil;
+  PTriangles := nil;
+end;
+
+constructor TGLMarchingCube.Create(SizeX, SizeY, SizeZ: Integer;
+  AIsoValue: TxScalarValue = 0.0; xMin: Single = -0.5; xMax: Single = 0.5;
+  yMin: Single = -0.5; yMax: Single = 0.5; zMin: Single = -0.5;
+  zMax: Single = 0.5);
+begin
+  FOriginalMC := True; // now only original MC is implemented
+  FIsoValue := AIsoValue;
+  ScalarField := SFSphere;
+  //SFKleinBottle;
+  //SFMinkowski;
+  //SFChmutov2;
+  //SFChmutov1;
+  //SFDoubleTorus;
+  //SFToroidal;
+  ReDim(SizeX, SizeY, SizeZ, xMin, xMax, yMin, yMax, zMin, zMax);
+  FillVoxelData;
+end;
+
+destructor TGLMarchingCube.Destroy;
+begin
+  clean_all;
+  inherited;
+end;
+
+function TGLMarchingCube.getVoxelValue(i, j, k: Integer): TxScalarValue;
+begin
+  Result := VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY].Density
+end;
+
+function TGLMarchingCube.getVoxelData(i, j, k: Integer): TxVoxel;
+begin
+  Result := VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY]
+end;
+
+function TGLMarchingCube.Get_x_grad(i, j, k: Integer): Single;
+begin
+  if (i > 0) then
+    if (i < FSizeX - 1) then
+      Result := (getVoxelValue(i + 1, j, k) - getVoxelValue(i - 1, j, k)) / 2
+    else
+      Result := getVoxelValue(i, j, k) - getVoxelValue(i - 1, j, k)
+  else
+    Result := getVoxelValue(i + 1, j, k) - getVoxelValue(i, j, k)
+end;
+
+function TGLMarchingCube.Get_x_vert(i, j, k: Integer): Integer;
+begin
+  Result := PVertsX^[i + j * FSizeX + k * FSizeX * FSizeY]
+end;
+
+function TGLMarchingCube.Get_y_grad(i, j, k: Integer): Single;
+begin
+  if (j > 0) then
+    if (j < FSizeY - 1) then
+      Result := (getVoxelValue(i, j + 1, k) - getVoxelValue(i, j - 1, k)) / 2
+    else
+      Result := getVoxelValue(i, j, k) - getVoxelValue(i, j - 1, k)
+  else
+    Result := getVoxelValue(i, j + 1, k) - getVoxelValue(i, j, k)
+end;
+
+function TGLMarchingCube.Get_y_vert(i, j, k: Integer): Integer;
+begin
+  Result := PVertsY^[i + j * FSizeX + k * FSizeX * FSizeY]
+end;
+
+function TGLMarchingCube.Get_z_grad(i, j, k: Integer): Single;
+begin
+  if (k > 0) then
+    if (k < FSizeZ - 1) then
+      Result := (getVoxelValue(i, j, k + 1) - getVoxelValue(i, j, k - 1)) / 2
+    else
+      Result := getVoxelValue(i, j, k) - getVoxelValue(i, j, k - 1)
+  else
+    Result := getVoxelValue(i, j, k + 1) - getVoxelValue(i, j, k)
+end;
+
+function TGLMarchingCube.Get_z_vert(i, j, k: Integer): Integer;
+begin
+  Result := PVertsZ^[i + j * FSizeX + k * FSizeX * FSizeY]
+end;
+
+procedure TGLMarchingCube.Init_all;
+begin
+  Init_temps;
+  Init_space;
+
+  if (PVertices <> nil) then
+    FreeMem(PVertices);
+  if (PTriangles <> nil) then
+    FreeMem(PTriangles);
+  _Nverts := 0;
+  _Ntrigs := 0;
+  _Sverts := ALLOC_SIZE;
+  _Strigs := ALLOC_SIZE;
+
+  GetMem(PVertices, _Sverts * SizeOf(TxVertex));
+  GetMem(PTriangles, _Strigs * SizeOf(TxTriangle));
+end;
+
+procedure TGLMarchingCube.Init_space;
+begin
+  VoxelData := AllocMem(FSizeX * FSizeY * FSizeZ * SizeOf(TxVoxel));
+end;
+
+procedure TGLMarchingCube.Init_temps;
+var
+  spaceSize: Longword;
+begin
+  spaceSize := FSizeX * FSizeY * FSizeZ;
+  GetMem(PVertsX, spaceSize * SizeOf(Integer));
+  GetMem(PVertsY, spaceSize * SizeOf(Integer));
+  GetMem(PVertsZ, spaceSize * SizeOf(Integer));
+
+  FillChar(PVertsX^, spaceSize * SizeOf(Integer), -1);
+  FillChar(PVertsY^, spaceSize * SizeOf(Integer), -1);
+  FillChar(PVertsZ^, spaceSize * SizeOf(Integer), -1);
+end;
+
+function TGLMarchingCube.Internal(AValue: TxScalarValue): Boolean;
+begin
+  Result := AValue <= FIsoValue
+end;
+
+procedure TGLMarchingCube.process_cube;
+var
+  nt: Byte;
+begin
+  if (FOriginalMC) then
+  begin
+    nt := 0;
+    while (MC_TRITABLE[_lut_entry][3 * nt] <> -1) do
+      Inc(nt);
+    add_triangle(MC_TRITABLE[_lut_entry], nt);
+    Exit;
+  end;
+  /// TODO complete algorithm with various tiling...
+end;
+
+procedure TGLMarchingCube.Run;
+var
+  i, j, k, P: Integer;
+begin
+  if (PVertsX = nil) then
+  begin
+    Init_temps;
+    _Nverts := 0;
+    _Ntrigs := 0;
+  end;
+  Compute_Intersection_Points;
+  for k := 0 to FSizeZ - 2 do
+  begin
+    _k := k;
+    for j := 0 to FSizeY - 2 do
+    begin
+      _j := j;
+      for i := 0 to FSizeX - 2 do
+      begin
+        _i := i;
+        _lut_entry := 0;
+        for P := 0 to 7 do
+        begin
+          _Cube[P] := getVoxelData(i + ((P xor (P shr 1)) and 1),
+            j + ((P shr 1) and 1), k + ((P shr 2) and 1));
+          // _Cube[p]:= getVoxelData( i+((p^(p>>1))&1), j+((p>>1)&1), k+((p>>2)&1) ) ;
+          if (Internal(_Cube[P].Density)) then
+            _lut_entry := _lut_entry or (1 shl P);
+        end;
+        process_cube;
+      end
+    end
+  end;
+  clean_temps;
+end;
+
+procedure TGLMarchingCube.Run(IsoValue: TxScalarValue);
+begin
+  FIsoValue := IsoValue;
+  Run
+end;
+
+procedure TGLMarchingCube.setVoxelValue(i, j, k: Integer; HfValue: TxScalarValue);
+begin
+  VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY].Density := HfValue
+end;
+
+procedure TGLMarchingCube.set_x_vert(a_val, i, j, k: Integer);
+begin
+  PVertsX^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
+end;
+
+procedure TGLMarchingCube.set_y_vert(a_val, i, j, k: Integer);
+begin
+  PVertsY^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
+end;
+
+procedure TGLMarchingCube.set_z_vert(a_val, i, j, k: Integer);
+begin
+  PVertsZ^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
+end;
+
+procedure TGLMarchingCube.test_vertex_addiction;
+begin
+  if _Nverts >= _Sverts then
+  begin
+    _Sverts := 2 * _Sverts;
+    ReallocMem(PVertices, _Sverts * SizeOf(TxVertex))
+  end;
+end;
+
+function TGLMarchingCube.voxel(i, j, k: Integer): PxVoxel;
+begin
+  if (k >= FSizeZ) or (j >= FSizeY) or (i >= FSizeX) then
+    Result := nil
+  else
+    Result := @VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY]
+end;
+
+procedure TGLMarchingCube.FillVoxelData;
+var
+  iX, iY, iZ: Integer;
+  X, Y, Z: Single;
+begin
+  for iX := 0 to FSizeX - 1 do
+  begin
+    X := FxMin + iX * FStepX;
+    for iY := 0 to FSizeY - 1 do
+    begin
+      Y := FyMin + iY * FStepY;
+      for iZ := 0 to FSizeZ - 1 do
+        with VoxelData^[iX + iY * FSizeX + iZ * FSizeX * FSizeY] do
+        begin
+          Z := FzMin + iZ * FStepZ;
+          MakeVector(P, X, Y, Z);
+          Density := ScalarField(X, Y, Z);
+          if Internal(Density) then
+            Status := bpInternal
+          else
+            Status := bpExternal
+        end;
+    end;
+  end;
+end;
+
+procedure TGLMarchingCube.FillVoxelData(AIsoValue: TxScalarValue; AScalarField: TxScalarField = nil);
+begin
+  FIsoValue := AIsoValue;
+  if Assigned(AScalarField) then
+    ScalarField := AScalarField;
+  FillVoxelData;
+end;
+
+procedure TGLMarchingCube.FillVoxelData(AIsoValue: TxScalarValue; AScalarField: TxScalarFieldInt);
+var
+  iX, iY, iZ: Integer;
+  X, Y, Z: Single;
+begin
+  FIsoValue := AIsoValue;
+  for iX := 0 to FSizeX - 1 do
+  begin
+    X := FxMin + iX * FStepX;
+    for iY := 0 to FSizeY - 1 do
+    begin
+      Y := FyMin + iY * FStepY;
+      for iZ := 0 to FSizeZ - 1 do
+        with VoxelData^[iX + iY * FSizeX + iZ * FSizeX * FSizeY] do
+        begin
+          Z := FzMin + iZ * FStepZ;
+          MakeVector(P, X, Y, Z);
+          Density := AScalarField(iX, iY, iZ);
+          if Internal(Density) then
+            Status := bpInternal
+          else
+            Status := bpExternal
+        end;
+    end;
+  end;
+end;
+
+procedure TGLMarchingCube.CalcVertices(Vertices: TGLVertexList;
+  Alpha: Single = 1);
+var
+  i: Integer;
+  vx1, vx2, vx3: TGLVertexData;
+
+  function GetNrmColor(Nrm: TAffineVector): TVector;
+  begin
+    Result.V[0] := 0;
+    if Nrm.V[0] > 0.0 then
+      Result.V[0] := Result.V[0] + Nrm.V[0];
+    if Nrm.V[1] < 0.0 then
+      Result.V[0] := Result.V[0] - 0.5 * Nrm.V[1];
+    if Nrm.V[2] < 0.0 then
+      Result.V[0] := Result.V[0] - 0.5 * Nrm.V[2];
+
+    Result.V[1] := 1;
+    if Nrm.V[0] < 0.0 then
+      Result.V[1] := Result.V[1] - 0.5 * Nrm.V[0];
+    if Nrm.V[1] > 0.0 then
+      Result.V[1] := Result.V[1] + Nrm.V[1];
+    if Nrm.V[2] < 0.0 then
+      Result.V[1] := Result.V[1] - 0.5 * Nrm.V[2];
+
+    Result.V[2] := 0;
+    if Nrm.V[0] < 0.0 then
+      Result.V[2] := Result.V[2] - 0.5 * Nrm.V[0];
+    if Nrm.V[1] < 0.0 then
+      Result.V[2] := Result.V[2] - 0.5 * Nrm.V[1];
+    if Nrm.V[2] > 0.0 then
+      Result.V[2] := Result.V[2] + Nrm.V[2];
+    Result.V[3] := 0.3
+  end;
+
+  function GetColor(H: TxScalarValue): TVector;
+  begin
+    Result := VectorMake(0.890, 0.855, 0.788, Alpha)
+    (*
+      if H <= 10 then Result:= VectorMake(0.922, 0.957, 0.980, 1.000)  //<=10
+      else if H <= 50 then Result:= VectorMake(0.541, 0.027, 0.027, 1.000) // 10..50
+      else if H <= 300 then Result:= VectorMake(0.941, 0.910, 0.859, 1.000) //50..300
+      else if H <= 2000 then Result:= VectorMake(0.965, 0.969, 0.973, 1.000) //350.. 2000
+      else if H <= 4000 then Result:= VectorMake(0.890, 0.855, 0.788, 1.000) //2000..4000
+      else Result:= VectorMake(0.9, 0.9, 0.6, 1.0)
+    *)
+  end;
+
+begin
+  Vertices.Clear;
+  Vertices.Capacity := 3 * _Ntrigs;
+
+  for i := 0 to _Ntrigs - 1 do
+    with PTriangles^[i] do
+    begin
+      vx1.coord := PVertices^[v1].P;
+      vx1.normal := PVertices^[v1].N;
+      vx2.coord := PVertices^[v2].P;
+      vx2.normal := PVertices^[v2].N;
+      vx3.coord := PVertices^[v3].P;
+      vx3.normal := PVertices^[v3].N;
+{$IFDEF UseDensity}
+      vx1.Color := GetColor(PVertices^[v1].Density); // GetNrmColor(vx1.normal);
+      vx2.Color := GetColor(PVertices^[v2].Density); // GetNrmColor(vx2.normal);
+      vx3.Color := GetColor(PVertices^[v3].Density); // GetNrmColor(vx3.normal);
+{$ELSE}
+      vx1.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
+      vx2.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
+      vx3.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
+{$ENDIF}
+      // Vertices.AddVertex3(vx1, vx2, vx3); seems to be correct the next line
+      Vertices.AddVertex3(vx3, vx2, vx1);
+    end;
+end;
+
+procedure TGLMarchingCube.CalcMeshObject(AMeshObject: TMeshObject; Alpha: Single);
+var
+  i: Integer;
+begin
+  AMeshObject.Clear;
+  AMeshObject.Vertices.Capacity := _Nverts;
+  AMeshObject.Normals.Capacity := _Nverts;
+  AMeshObject.Colors.Capacity := _Nverts;
+  with TFGVertexIndexList.CreateOwned(AMeshObject.FaceGroups) do
+  begin
+    Mode := fgmmTriangles;
+    for i := 0 to _Nverts - 1 do
+    begin
+      AMeshObject.Vertices.Add(PVertices^[i].P);
+      AMeshObject.Normals.Add(PVertices^[i].N);
+      // AMeshObject.Normals.Add(VectorScale(PVertices^[i].N, -1));
+      // AMeshObject.Colors.Add(VectorMake(0.890, 0.855, 0.788, Alpha));
+    end;
+
+    for i := 0 to _Ntrigs - 1 do
+      // with PTriangles^[i] do VertexIndices.Add(v1, v2, v3);
+      with PTriangles^[i] do
+        VertexIndices.Add(v3, v2, v1);
+  end;
+end;
+
+
+
 end.

+ 15 - 16
Source/GLS.SceneRegister.pas

@@ -293,7 +293,7 @@ uses
   GLAsyncHDS,
   GLAsyncTimer,
   GLAtmosphere,
-  GLAVIRecorder,
+  GLS.AVIRecorder,
   GLBaseClasses,
   GLBitmapFont,
   GLBlur,
@@ -342,37 +342,36 @@ uses
   GLPerlinPFX,
   GLPolyhedron,
   GLPortal,
-  GLPostEffects,
+  GLScreen,
+  GLScriptBase,
+  GLShadowHDS,
+  GLShadowPlane,
+  GLShadowVolume,
+  GLSimpleNavigation,
+  GLSkyBox,
+  GLSkydome,
   GLProjectedTextures,
   GLProxyObjects,
   GLRenderContextInfo,
   GLS.ArchiveManager,
   GLS.Language,
   GLS.Memo,
-  GLS.ShaderAsm,
-  GLS.ShaderBump,
   GLS.ShaderCel,
   GLS.ShaderHiddenLine,
   GLS.ShaderCombiner,
   GLS.ShaderMultiMaterial,
   GLS.ShaderOutline,
-  GLS.ShaderPhong,
   GLS.ShaderTexCombine,
   GLS.ShaderTextureSharing,
   GLS.ShaderUser,
   GLS.Utils,
-  GLScreen,
-  GLScriptBase,
-  GLShadowHDS,
-  GLShadowPlane,
-  GLShadowVolume,
-  GLSimpleNavigation,
-  GLSkyBox,
-  GLSkydome,
+  GLSL.AsmShader,
+  GLSL.PhongShader,
+  GLSL.PostEffects,
   GLSL.ProjectedTextures,
-  GLSL.ShaderBump,
-  GLSL.ShaderDiffuseSpecular,
-  GLSL.ShaderPosts,
+  GLSL.BumpShaders,
+  GLSL.DiffuseSpecularShader,
+  GLSL.PostShaders,
   GLSL.Shader,
   GLSmoothNavigator,
   GLState,

+ 0 - 853
Source/GLS.ShaderBump.pas

@@ -1,853 +0,0 @@
-//
-// This unit is part of the GLScene Engine, http://glscene.org
-//
-
-unit GLS.ShaderBump;
-
-(*
-   A shader that applies bump mapping.
-   Notes:
-   The normal map is expected to be the primary texture.
-
-   The secondary texture is used for the diffuse texture,
-   to enable set boDiffuseTexture2 in the BumpOptions property.
-
-   The tertiary texture is used for the specular texture,
-   to enable set boSpecularTexture3 in the BumpOptions property.
-   The SpecularMode determines the specular highlight calculation
-   (Blinn or Phong), smOff disables specular highlights in the
-   shader.
-
-   External tangent bump space expects tangent data under
-   GL_TEXTURE1_ARB and binormal data under GL_TEXTURE2_ARB.
-
-   The boUseSecondaryTexCoords bump option tells the shader to use
-   the secondary texture coordinates for the diffuse and specular
-   texture lookups.
-
-*)
-
-interface
-
-{$I GLScene.inc}
-
-uses
-  Winapi.OpenGL,
-  Winapi.OpenGLext,
-  System.Classes,
-  System.SysUtils,
-
-  OpenGLTokens,
-  Scene.VectorTypes,
-  Scene.VectorGeometry,
-  GLMaterial,
-  GLGraphics,
-  GLS.Utils,
-  GLContext,
-  Scene.VectorLists,
-  GLColor,
-  GLRenderContextInfo,
-  GLState,
-  GLTextureFormat;
-
-type
-  TBumpMethod = (bmDot3TexCombiner, bmBasicARBFP);
-
-  TBumpSpace = (bsObject, bsTangentExternal, bsTangentQuaternion);
-
-  TBumpOption = (boDiffuseTexture2, // Use secondary texture as diffuse
-    boSpecularTexture3, // Use tertiary texture as specular
-    boUseSecondaryTexCoords, // Pass through secondary texcoords
-    boLightAttenuation, // Use light attenuation
-    boParallaxMapping // Enable parallax offset mapping
-    );
-  TBumpOptions = set of TBumpOption;
-
-  TSpecularMode = (smOff, smBlinn, smPhong);
-
-  // A generic bump shader.
-  TGLBumpShader = class(TGLShader)
-  private
-    FVertexProgramHandle: TGLARBVertexProgramHandle;
-    FFragmentProgramHandle: TGLARBFragmentProgramHandle;
-    FLightIDs: TIntegerList;
-    FLightsEnabled: Integer;
-    FBumpMethod: TBumpMethod;
-    FBumpSpace: TBumpSpace;
-    FBumpOptions: TBumpOptions;
-    FSpecularMode: TSpecularMode;
-    FDesignTimeEnabled: Boolean;
-    FAmbientPass: Boolean;
-    FDiffusePass: Boolean;
-    FVertexProgram: TStringList;
-    FFragmentProgram: TStringList;
-    FParallaxOffset: Single;
-    function GenerateVertexProgram: string;
-    function GenerateFragmentProgram: string;
-    procedure DoLightPass(var rci: TGLRenderContextInfo; lightID: Cardinal);
-  protected
-    procedure SetBumpMethod(const Value: TBumpMethod);
-    procedure SetBumpSpace(const Value: TBumpSpace);
-    procedure SetBumpOptions(const Value: TBumpOptions);
-    procedure SetSpecularMode(const Value: TSpecularMode);
-    procedure SetDesignTimeEnabled(const Value: Boolean);
-    procedure SetParallaxOffset(const Value: Single);
-    procedure Loaded; override;
-    procedure DeleteVertexPrograms;
-    procedure DeleteFragmentPrograms;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
-    function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
-  published
-    property BumpMethod: TBumpMethod read FBumpMethod write SetBumpMethod;
-    property BumpSpace: TBumpSpace read FBumpSpace write SetBumpSpace;
-    property BumpOptions: TBumpOptions read FBumpOptions write SetBumpOptions;
-    property SpecularMode: TSpecularMode read FSpecularMode write
-      SetSpecularMode;
-    property DesignTimeEnabled: Boolean read FDesignTimeEnabled write
-      SetDesignTimeEnabled;
-    property ParallaxOffset: Single read FParallaxOffset write
-      SetParallaxOffset;
-  end;
-
-// ------------------------------------------------------------------
-implementation
-// ------------------------------------------------------------------
-
-// ------------------
-// ------------------ TGLBumpShader ------------------
-// ------------------
-
-constructor TGLBumpShader.Create(AOwner: TComponent);
-begin
-  inherited;
-  FLightIDs := TIntegerList.Create;
-  FBumpMethod := bmDot3TexCombiner;
-  FBumpSpace := bsObject;
-  FBumpOptions := [];
-  FSpecularMode := smOff;
-  ShaderStyle := ssLowLevel;
-  FParallaxOffset := 0.04;
-
-  FVertexProgram := TStringList.Create;
-  FFragmentProgram := TStringList.Create;
-end;
-
-
-destructor TGLBumpShader.Destroy;
-begin
-  DeleteVertexPrograms;
-  DeleteFragmentPrograms;
-  FLightIDs.Free;
-  FVertexProgram.Free;
-  FFragmentProgram.Free;
-  inherited;
-end;
-
-procedure TGLBumpShader.Loaded;
-begin
-  inherited;
-end;
-
-function TGLBumpShader.GenerateVertexProgram: string;
-var
-  VP: TStringList;
-  DoTangent, DoSpecular, DoParallaxOffset: Boolean;
-  texcoord: Integer;
-begin
-  DoSpecular := (BumpMethod = bmBasicARBFP) and not (SpecularMode = smOff);
-  DoTangent := (BumpSpace = bsTangentExternal) or (BumpSpace =
-    bsTangentQuaternion);
-  DoParallaxOffset := (BumpMethod = bmBasicARBFP) and (boParallaxMapping in
-    BumpOptions) and DoTangent;
-
-  VP := TStringList.Create;
-
-  VP.Add('!!ARBvp1.0');
-  VP.Add('OPTION ARB_position_invariant;');
-
-  VP.Add('PARAM mv[4] = { state.matrix.modelview };');
-  VP.Add('PARAM mvinv[4] = { state.matrix.modelview.inverse };');
-  VP.Add('PARAM mvit[4] = { state.matrix.modelview.invtrans };');
-  VP.Add('PARAM tex[4] = { state.matrix.texture[0] };');
-  if boUseSecondaryTexCoords in BumpOptions then
-    VP.Add('PARAM tex2[4] = { state.matrix.texture[1] };');
-  VP.Add('PARAM lightPos = program.local[0];');
-  VP.Add('PARAM lightAtten = program.local[1];');
-  if BumpSpace = bsTangentExternal then
-  begin
-    VP.Add('ATTRIB tangent = vertex.texcoord[1];');
-    VP.Add('ATTRIB binormal = vertex.texcoord[2];');
-    VP.Add('ATTRIB normal = vertex.normal;');
-  end;
-  VP.Add('TEMP temp, temp2, light, eye, atten;');
-
-  if (boLightAttenuation in BumpOptions) then
-  begin
-
-    VP.Add('   DP4 temp.x, mv[0], vertex.position;');
-    VP.Add('   DP4 temp.y, mv[1], vertex.position;');
-    VP.Add('   DP4 temp.z, mv[2], vertex.position;');
-    VP.Add('   ADD light, lightPos, -temp;');
-
-    VP.Add('   DP3 atten.y, light, light;');
-    VP.Add('   RSQ atten.y, atten.y;');
-    if BumpMethod = bmDot3TexCombiner then
-    begin
-      VP.Add('   RCP atten.y, atten.y;');
-      VP.Add('   MUL atten.z, atten.y, atten.y;');
-      VP.Add('   MAD atten.x, lightAtten.y, atten.y, lightAtten.x;');
-      VP.Add('   MAD atten.x, lightAtten.z, atten.z, atten.x;');
-      VP.Add('   RCP atten.x, atten.x;');
-    end
-    else if BumpMethod = bmBasicARBFP then
-    begin
-      // Store the distance in atten.x for ARBFP,
-      // fragment program will calculate attenutation
-      VP.Add('   RCP atten.x, atten.y;');
-    end;
-
-    VP.Add('   DP3 temp.x, mvinv[0], light;');
-    VP.Add('   DP3 temp.y, mvinv[1], light;');
-    VP.Add('   DP3 temp.z, mvinv[2], light;');
-    VP.Add('   MOV light, temp;');
-  end
-  else
-  begin
-    VP.Add('   DP4 light.x, mvinv[0], lightPos;');
-    VP.Add('   DP4 light.y, mvinv[1], lightPos;');
-    VP.Add('   DP4 light.z, mvinv[2], lightPos;');
-    VP.Add('   ADD light, light, -vertex.position;');
-  end;
-
-  if DoSpecular or DoParallaxOffset then
-    VP.Add('   ADD eye, mvit[3], -vertex.position;');
-
-  if DoTangent then
-  begin
-    if BumpSpace = bsTangentExternal then
-    begin
-
-      VP.Add('   DP3 temp.x, light, tangent;');
-      VP.Add('   DP3 temp.y, light, binormal;');
-      VP.Add('   DP3 temp.z, light, normal;');
-      VP.Add('   MOV light, temp;');
-      if DoSpecular or DoParallaxOffset then
-      begin
-        VP.Add('   DP3 temp.x, eye, tangent;');
-        VP.Add('   DP3 temp.y, eye, binormal;');
-        VP.Add('   DP3 temp.z, eye, normal;');
-        VP.Add('   MOV eye, temp;');
-      end;
-
-    end
-    else if BumpSpace = bsTangentQuaternion then
-    begin
-
-      VP.Add('   DP3 temp.x, light, light;');
-      VP.Add('   RSQ temp.x, temp.x;');
-      VP.Add('   MUL light, temp.x, light;');
-
-      VP.Add('   MOV temp2.x, vertex.normal.y;');
-      VP.Add('   ADD temp2.y, 0.0, -vertex.normal.x;');
-      VP.Add('   MOV temp2.z, 0.0;');
-
-      VP.Add('   DP3 temp.x, temp2, light;');
-      VP.Add('   MUL temp.x, temp2.y, light.z;');
-      VP.Add('   MAD temp.y, vertex.normal.z, light.x, temp.x;');
-      VP.Add('   MUL temp.x, vertex.normal.y, light.z;');
-      VP.Add('   MAD temp.z, vertex.normal.z, light.y, -temp.x;');
-      VP.Add('   MUL temp.x, vertex.normal.y, light.y;');
-      VP.Add('   MAD temp.x, vertex.normal.z, light.z, temp.x;');
-      VP.Add('   MAD temp.w, -temp2.y, light.x, temp.x;');
-      VP.Add('   MOV light, temp.yzwy;');
-
-      if DoSpecular or DoParallaxOffset then
-      begin
-        VP.Add('   DP3 temp.x, temp2, eye;');
-        VP.Add('   MUL temp.x, temp2.y, eye.z;');
-        VP.Add('   MAD temp.y, vertex.normal.z, eye.x, temp.x;');
-        VP.Add('   MUL temp.x, vertex.normal.y, eye.z;');
-        VP.Add('   MAD temp.z, vertex.normal.z, eye.y, -temp.x;');
-        VP.Add('   MUL temp.x, vertex.normal.y, eye.y;');
-        VP.Add('   MAD temp.x, vertex.normal.z, eye.z, temp.x;');
-        VP.Add('   MAD temp.w, -temp2.y, eye.x, temp.x;');
-        VP.Add('   MOV eye, temp.yzwy;');
-      end;
-
-    end;
-  end;
-
-  if BumpMethod = bmDot3TexCombiner then
-  begin
-
-    if BumpSpace <> bsTangentQuaternion then
-    begin
-      VP.Add('   DP3 temp.x, light, light;');
-      VP.Add('   RSQ temp, temp.x;');
-      VP.Add('   MUL light, temp.x, light;');
-    end;
-
-    if boLightAttenuation in BumpOptions then
-      VP.Add('   MUL light, atten.x, light;');
-
-    VP.Add('   MAD result.color, light, 0.5, 0.5;');
-    VP.Add('   MOV result.color.w, 1.0;');
-
-  end
-  else if BumpMethod = bmBasicARBFP then
-  begin
-
-    if boLightAttenuation in BumpOptions then
-      VP.Add('   MOV light.w, atten.x;')
-    else
-      VP.Add('   MOV light.w, 0.0;');
-    if DoSpecular or DoParallaxOffset then
-      VP.Add('   MOV eye.w, 0.0;');
-
-  end;
-
-  texcoord := 0;
-
-  VP.Add('   DP4 temp.x, vertex.texcoord[0], tex[0];');
-  VP.Add('   DP4 temp.y, vertex.texcoord[0], tex[1];');
-  VP.Add('   DP4 temp.z, vertex.texcoord[0], tex[2];');
-  VP.Add('   DP4 temp.w, vertex.texcoord[0], tex[3];');
-  VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
-  Inc(texcoord);
-
-  if boUseSecondaryTexCoords in BumpOptions then
-  begin
-    VP.Add('   DP4 temp.x, vertex.texcoord[1], tex2[0];');
-    VP.Add('   DP4 temp.y, vertex.texcoord[1], tex2[1];');
-    VP.Add('   DP4 temp.z, vertex.texcoord[1], tex2[2];');
-    VP.Add('   DP4 temp.w, vertex.texcoord[1], tex2[3];');
-    VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
-    Inc(texcoord);
-  end;
-
-  if BumpMethod = bmDot3TexCombiner then
-  begin
-    if (boDiffuseTexture2 in BumpOptions)
-      and not (boUseSecondaryTexCoords in BumpOptions) then
-      VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
-  end
-  else
-  begin
-    VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], light;');
-    Inc(texcoord);
-    if DoSpecular then
-      VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], eye;');
-  end;
-
-  VP.Add('END');
-
-  FVertexProgram.Assign(VP);
-  Result := VP.Text;
-  VP.Free;
-end;
-
-function TGLBumpShader.GenerateFragmentProgram: string;
-var
-  FP: TStringList;
-  DoSpecular,
-    DoTangent,
-    DoParallaxOffset: Boolean;
-  texcoord,
-    normalTexCoords,
-    diffTexCoords,
-    specTexCoords,
-    lightTexCoords,
-    eyeTexCoords: Integer;
-begin
-  DoSpecular := not (SpecularMode = smOff);
-  DoTangent := (BumpSpace = bsTangentExternal) or (BumpSpace =
-    bsTangentQuaternion);
-  DoParallaxOffset := (boParallaxMapping in BumpOptions) and DoTangent;
-
-  texcoord := 0;
-  normalTexCoords := texcoord;
-  if boUseSecondaryTexCoords in BumpOptions then
-    Inc(texcoord);
-  diffTexCoords := texcoord;
-  specTexCoords := texcoord;
-  Inc(texcoord);
-  lightTexCoords := texcoord;
-  Inc(texcoord);
-  eyeTexCoords := texcoord;
-
-  FP := TStringList.Create;
-
-  FP.Add('!!ARBfp1.0');
-
-  FP.Add('PARAM lightDiffuse = program.local[0];');
-  FP.Add('PARAM lightSpecular = program.local[1];');
-  FP.Add('PARAM lightAtten = program.local[2];');
-  FP.Add('PARAM materialDiffuse = state.material.diffuse;');
-  FP.Add('PARAM materialSpecular = state.material.specular;');
-  FP.Add('PARAM shininess = state.material.shininess;');
-  FP.Add('TEMP temp, tex, light, eye, normal, col, diff, spec;');
-  FP.Add('TEMP textureColor, reflect, atten, offset, texcoord;');
-
-  if DoSpecular or DoParallaxOffset then
-  begin
-    // Get the eye vector
-    FP.Add('   DP3 eye, fragment.texcoord[' + IntToStr(eyeTexCoords) +
-      '], fragment.texcoord[' + IntToStr(eyeTexCoords) + '];');
-    FP.Add('   RSQ eye, eye.x;');
-    FP.Add('   MUL eye, fragment.texcoord[' + IntToStr(eyeTexCoords) +
-      '], eye.x;');
-  end;
-
-  if DoParallaxOffset then
-  begin
-    // Get the parallax offset
-    FP.Add('   TEX textureColor, fragment.texcoord[' + IntToStr(normalTexCoords)
-      + '], texture[0], 2D;');
-    FP.Add(Format('   MAD offset.x, textureColor.a, %f, %f;', [FParallaxOffset,
-      -0.5 * FParallaxOffset]));
-    FP.Add('   MUL offset, eye, offset.x;');
-    FP.Add('   ADD texcoord, fragment.texcoord[' + IntToStr(normalTexCoords) +
-      '], offset;');
-  end
-  else
-    FP.Add('   MOV texcoord, fragment.texcoord[' + IntToStr(normalTexCoords) +
-      '];');
-
-  // Get the normalized normal vector
-  FP.Add('   TEX textureColor, texcoord, texture[0], 2D;');
-  FP.Add('   ADD normal, textureColor, -0.5;');
-  FP.Add('   DP3 temp, normal, normal;');
-  FP.Add('   RSQ temp, temp.x;');
-  FP.Add('   MUL normal, normal, temp.x;');
-
-  // Get the normalized light vector
-  FP.Add('   MOV light, fragment.texcoord[' + IntToStr(lightTexCoords) + '];');
-  if boLightAttenuation in BumpOptions then
-    FP.Add('   MOV atten.x, light.w;');
-  FP.Add('   DP3 light, light, light;');
-  FP.Add('   RSQ light, light.x;');
-  FP.Add('   MUL light, fragment.texcoord[' + IntToStr(lightTexCoords) +
-    '], light.x;');
-
-  // Calculate the diffuse color
-  FP.Add('   DP3 diff, normal, light;');
-  FP.Add('   MUL diff, diff, lightDiffuse;');
-  FP.Add('   MUL diff, diff, materialDiffuse;');
-  if boDiffuseTexture2 in BumpOptions then
-  begin
-    if DoParallaxOffset then
-    begin
-      FP.Add('   ADD temp, fragment.texcoord[' + IntToStr(diffTexCoords) +
-        '], offset;');
-      FP.Add('   TEX textureColor, temp, texture[1], 2D;');
-    end
-    else
-      FP.Add('   TEX textureColor, fragment.texcoord[' + IntToStr(diffTexCoords)
-        + '], texture[1], 2D;');
-    FP.Add('   MUL diff, diff, textureColor;');
-  end;
-
-  if DoSpecular then
-  begin
-    case SpecularMode of
-      smBlinn:
-        begin
-          FP.Add('   ADD eye, eye, light;');
-          FP.Add('   DP3 temp, eye, eye;');
-          FP.Add('   RSQ temp, temp.x;');
-          FP.Add('   MUL eye, eye, temp.x;');
-          FP.Add('   DP3_SAT spec, normal, eye;');
-        end;
-      smPhong:
-        begin
-          FP.Add('   DP3 reflect, normal, light;');
-          FP.Add('   MUL reflect, reflect.x, normal;');
-          FP.Add('   MUL reflect, 2.0, reflect;');
-          FP.Add('   ADD reflect, reflect, -light;');
-          FP.Add('   DP3_SAT spec, reflect, eye;');
-        end;
-    else
-      Assert(False, 'Invalid specular mode!');
-    end;
-
-    FP.Add('   POW spec, spec.x, shininess.x;');
-    FP.Add('   MUL spec, spec, materialSpecular;');
-    FP.Add('   MUL spec, spec, lightSpecular;');
-    if boSpecularTexture3 in BumpOptions then
-    begin
-      if DoParallaxOffset then
-      begin
-        FP.Add('   ADD temp, fragment.texcoord[' + IntToStr(specTexCoords) +
-          '], offset;');
-        FP.Add('   TEX textureColor, temp, texture[2], 2D;');
-      end
-      else
-        FP.Add('   TEX textureColor, fragment.texcoord[' +
-          IntToStr(specTexCoords) + '], texture[2], 2D;');
-      FP.Add('   MUL spec, spec, textureColor;');
-    end;
-  end;
-
-  // Output
-  if DoSpecular then
-    FP.Add('   ADD temp, diff, spec;')
-  else
-    FP.Add('   MOV temp, diff;');
-
-  if boLightAttenuation in BumpOptions then
-  begin
-    FP.Add('   MUL atten.y, atten.x, atten.x;');
-    FP.Add('   MAD atten.x, lightAtten.y, atten.x, lightAtten.x;');
-    FP.Add('   MAD atten.x, lightAtten.z, atten.y, atten.x;');
-    FP.Add('   RCP atten.x, atten.x;');
-    FP.Add('   MUL temp, temp, atten.x;');
-  end;
-
-  FP.Add('   MOV_SAT result.color, temp;');
-  FP.Add('   MOV result.color.w, 1.0;');
-
-  FP.Add('END');
-
-  FFragmentProgram.Assign(FP);
-  Result := FP.Text;
-  FP.Free;
-end;
-
-// DoLightPass
-//
-
-procedure TGLBumpShader.DoLightPass(var rci: TGLRenderContextInfo;
-  lightID: Cardinal);
-var
-  dummyHandle, tempHandle: Integer;
-  lightPos, lightAtten,
-    materialDiffuse, lightDiffuse, lightSpecular: TVector;
-begin
-  FVertexProgramHandle.Enable;
-  FVertexProgramHandle.Bind;
-
-  // Set the light position to program.local[0]
-  gl.GetLightfv(GL_LIGHT0 + FLightIDs[0], GL_POSITION, @lightPos.X);
-  gl.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, 0, @lightPos.X);
-
-  // Set the light attenutation to program.local[1]
-  lightAtten.X := rci.GLStates.LightConstantAtten[FLightIDs[0]];
-  lightAtten.Y := rci.GLStates.LightLinearAtten[FLightIDs[0]];
-  lightAtten.Z := rci.GLStates.LightQuadraticAtten[FLightIDs[0]];
-  gl.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, 1, @lightAtten.X);
-
-  case FBumpMethod of
-    bmDot3TexCombiner:
-      begin
-        rci.GLStates.ActiveTexture := 0;
-        dummyHandle := rci.GLStates.TextureBinding[0, ttTexture2D];
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE0_ARB);
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
-
-        rci.GLStates.ActiveTexture := 1;
-        rci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
-        tempHandle := rci.GLStates.TextureBinding[1, ttTexture2D];
-        if tempHandle = 0 then
-          rci.GLStates.TextureBinding[1, ttTexture2D] := dummyHandle;
-        lightDiffuse := rci.GLStates.LightDiffuse[FLightIDs[0]];
-        gl.GetMaterialfv(GL_FRONT, GL_DIFFUSE, @materialDiffuse);
-        lightDiffuse.X := lightDiffuse.X * materialDiffuse.X;
-        lightDiffuse.Y := lightDiffuse.Y * materialDiffuse.Y;
-        lightDiffuse.Z := lightDiffuse.Z * materialDiffuse.Z;
-        lightDiffuse.W := lightDiffuse.W * materialDiffuse.W;
-        gl.TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, @lightDiffuse);
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
-        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_COLOR_EXT);
-
-        with rci.GLStates do
-        begin
-          ActiveTexture := 2;
-          ActiveTextureEnabled[ttTexture2D] := False;
-          ActiveTexture := 0;
-        end;
-      end;
-
-    bmBasicARBFP:
-      begin
-        FFragmentProgramHandle.Enable;
-        FFragmentProgramHandle.Bind;
-        lightDiffuse := rci.GLStates.LightDiffuse[FLightIDs[0]];
-        lightSpecular := rci.GLStates.LightSpecular[FLightIDs[0]];
-        lightAtten.X := rci.GLStates.LightConstantAtten[FLightIDs[0]];
-
-        gl.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 0,
-          @lightDiffuse.X);
-        gl.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 1,
-          @lightSpecular.X);
-        gl.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 2,
-          @lightAtten.X);
-      end;
-
-  else
-    Assert(False, 'Invalid bump method!');
-  end;
-end;
-
-procedure TGLBumpShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
-var
-  maxTextures, i: Integer;
-  ambient, LMaterialAmbient: TColorVector;
-  success: Boolean;
-begin
-  if (csDesigning in ComponentState) and not DesignTimeEnabled then
-    exit;
-  if not Enabled then
-    exit;
-
-  gl.GetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, @maxTextures);
-
-  success := False;
-  try
-    if not gl.ARB_multitexture then
-      raise Exception.Create('This shader requires GL_ARB_multitexture.');
-    if (maxTextures < 3)
-      and ((BumpMethod <> bmDot3TexCombiner) or (BumpSpace = bsTangentExternal)) then
-      raise
-        Exception.Create('The current shader settings require 3 or more texture units.');
-    if (maxTextures < 4)
-      and (BumpMethod <> bmDot3TexCombiner)
-      and (boUseSecondaryTexCoords in BumpOptions)
-      and (SpecularMode <> smOff) then
-      raise
-        Exception.Create('The current shader settings require 4 or more texture units.');
-
-    if not Assigned(FVertexProgramHandle) then
-    begin
-      FVertexProgramHandle := TGLARBVertexProgramHandle.CreateAndAllocate;
-      FVertexProgramHandle.LoadARBProgram(GenerateVertexProgram);
-    end;
-
-    if not Assigned(FFragmentProgramHandle) then
-      if FBumpMethod = bmBasicARBFP then
-      begin
-        FFragmentProgramHandle := TGLARBFragmentProgramHandle.CreateAndAllocate;
-        FFragmentProgramHandle.LoadARBProgram(GenerateFragmentProgram);
-      end;
-
-    success := True;
-
-  finally
-    if not success then
-    begin
-      Enabled := False;
-      DesignTimeEnabled := False;
-    end;
-  end;
-
-  FLightIDs.Clear;
-  rci.GLStates.ActiveTexture := 0;
-  if rci.GLStates.ActiveTextureEnabled[ttTexture2D] then
-    for i := 0 to rci.GLStates.MaxLights - 1 do
-    begin
-      if rci.GLStates.LightEnabling[i] then
-        FLightIDs.Add(i);
-    end;
-  FLightsEnabled := FLightIDs.Count;
-
-  FAmbientPass := False;
-  FDiffusePass := False;
-
-  if FLightIDs.Count > 0 then
-  begin
-
-    rci.GLStates.DepthFunc := cfLEqual;
-    rci.GLStates.Disable(stBlend);
-    DoLightPass(rci, FLightIDs[0]);
-    FLightIDs.Delete(0);
-
-  end
-  else
-    with rci.GLStates do
-    begin
-      Disable(stLighting);
-      ActiveTexture := 0;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 1;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 2;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 0;
-
-      gl.GetFloatv(GL_LIGHT_MODEL_AMBIENT, @ambient);
-      gl.GetMaterialfv(GL_FRONT, GL_AMBIENT, @LMaterialAmbient);
-      ambient.X := ambient.X * LMaterialAmbient.X;
-      ambient.Y := ambient.Y * LMaterialAmbient.Y;
-      ambient.Z := ambient.Z * LMaterialAmbient.Z;
-      gl.Color3fv(@ambient);
-
-      FAmbientPass := True;
-
-    end;
-end;
-
-function TGLBumpShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
-var
-  ambient, LMaterialAmbient: TVector;
-begin
-  Result := False;
-  if (csDesigning in ComponentState) and not DesignTimeEnabled then
-    exit;
-  if not Enabled then
-    exit;
-
-  if FLightIDs.Count > 0 then
-    with rci.GLStates do
-    begin
-
-      DepthFunc := cfLEqual;
-      Enable(stBlend);
-      SetBlendFunc(bfOne, bfOne);
-
-      DoLightPass(rci, FLightIDs[0]);
-      FLightIDs.Delete(0);
-      Result := True;
-      Exit;
-
-    end
-  else if not FDiffusePass and (FLightsEnabled <> 0)
-    and (boDiffuseTexture2 in BumpOptions)
-    and (BumpMethod = bmDot3TexCombiner) then
-    with rci.GLStates do
-    begin
-      Enable(stBlend);
-      SetBlendFunc(bfDstColor, bfZero);
-      ActiveTexture := 0;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 1;
-      ActiveTextureEnabled[ttTexture2D] := True;
-      gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-      ActiveTexture := 2;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 0;
-      FDiffusePass := True;
-      Result := True;
-      Exit;
-    end
-  else if not FAmbientPass then
-    with rci.GLStates do
-    begin
-      FVertexProgramHandle.Disable;
-      if BumpMethod = bmBasicARBFP then
-        FFragmentProgramHandle.Disable;
-      Disable(stLighting);
-      ActiveTexture := 0;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 1;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 2;
-      ActiveTextureEnabled[ttTexture2D] := False;
-      ActiveTexture := 0;
-
-      DepthFunc := cfLEqual;
-      Enable(stBlend);
-      SetBlendFunc(bfOne, bfOne);
-
-      gl.GetFloatv(GL_LIGHT_MODEL_AMBIENT, @ambient);
-      gl.GetMaterialfv(GL_FRONT, GL_AMBIENT, @LMaterialAmbient);
-      ambient.X := ambient.X * LMaterialAmbient.X;
-      ambient.Y := ambient.Y * LMaterialAmbient.Y;
-      ambient.Z := ambient.Z * LMaterialAmbient.Z;
-      gl.Color3fv(@ambient);
-
-      FAmbientPass := True;
-      Result := True;
-      Exit;
-    end;
-
-  FVertexProgramHandle.Disable;
-  if BumpMethod = bmBasicARBFP then
-    FFragmentProgramHandle.Disable;
-end;
-
-procedure TGLBumpShader.DeleteVertexPrograms;
-begin
-  FVertexProgramHandle.Free;
-  FVertexProgramHandle := nil;
-  FVertexProgram.Clear;
-end;
-
-procedure TGLBumpShader.DeleteFragmentPrograms;
-begin
-  FFragmentProgramHandle.Free;
-  FFragmentProgramHandle := nil;
-  FFragmentProgram.Clear;
-end;
-
-procedure TGLBumpShader.SetBumpMethod(const Value: TBumpMethod);
-begin
-  if Value <> FBumpMethod then
-  begin
-    FBumpMethod := Value;
-    DeleteVertexPrograms;
-    DeleteFragmentPrograms;
-    NotifyChange(Self);
-  end;
-end;
-
-procedure TGLBumpShader.SetBumpSpace(const Value: TBumpSpace);
-begin
-  if Value <> FBumpSpace then
-  begin
-    FBumpSpace := Value;
-    DeleteVertexPrograms;
-    DeleteFragmentPrograms;
-    NotifyChange(Self);
-  end;
-end;
-
-procedure TGLBumpShader.SetBumpOptions(const Value: TBumpOptions);
-begin
-  if Value <> FBumpOptions then
-  begin
-    FBumpOptions := Value;
-    DeleteVertexPrograms;
-    DeleteFragmentPrograms;
-    NotifyChange(Self);
-  end;
-end;
-
-procedure TGLBumpShader.SetSpecularMode(const Value: TSpecularMode);
-begin
-  if Value <> FSpecularMode then
-  begin
-    FSpecularMode := Value;
-    DeleteVertexPrograms;
-    DeleteFragmentPrograms;
-    NotifyChange(Self);
-  end;
-end;
-
-procedure TGLBumpShader.SetDesignTimeEnabled(const Value: Boolean);
-begin
-  if Value <> FDesignTimeEnabled then
-  begin
-    FDesignTimeEnabled := Value;
-    NotifyChange(Self);
-  end;
-end;
-
-procedure TGLBumpShader.SetParallaxOffset(const Value: Single);
-begin
-  if Value <> FParallaxOffset then
-  begin
-    FParallaxOffset := Value;
-    DeleteVertexPrograms;
-    DeleteFragmentPrograms;
-    NotifyChange(Self);
-  end;
-end;
-
-end.
-

+ 0 - 3
Source/GLS.ShaderCombiner.pas

@@ -38,9 +38,6 @@ type
 
      TODO: Add more modes here, including sctOneAPTwoAP, which should be the
            default one.
-
-     By the way, I admit - the names do look stupid, and if someone gives them
-     proper names, I will be only glad.
   *)
   TGLShaderCombinerType = (sctOneSPTwoAP, sctTwoSPOneAP,
                            sctOneMPTwoSP, sctTwoMPOneSP);

+ 1 - 2
Source/GLS.Triangulation.pas

@@ -12,8 +12,7 @@ uses
   System.Classes,
   System.Types,
   Vcl.Dialogs,
-  Vcl.Graphics,
-  
+
   Scene.VectorGeometry;
 
 // Set these as applicable

+ 3 - 3
Source/GLS.ShaderAsm.pas → Source/GLSL.AsmShader.pas

@@ -2,12 +2,12 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.ShaderAsm;
+unit GLSL.AsmShader;
 
 (*
     TGLAsmShader is a wrapper for all ARB shaders 
     This component is only a template and has to be replaced with a
-    proper version by someone who uses ARB shaders more then me.
+    proper version by someone who uses ARB shaders.
 *)
 
 interface
@@ -23,7 +23,7 @@ uses
   Scene.VectorTypes,
   GLTexture,
   GLContext,
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLRenderContextInfo;
 
 type

+ 846 - 13
Source/GLSL.ShaderBump.pas → Source/GLSL.BumpShaders.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLSL.ShaderBump;
+unit GLSL.BumpShaders;
 
 (*
    A GLSL shader that applies bump mapping.
@@ -31,22 +31,46 @@ interface
 {$I GLScene.inc}
 
 uses
+  Winapi.OpenGL,
+  Winapi.OpenGLext,
+
   System.Classes,
   System.SysUtils,
+
+  OpenGLTokens,
+
+  Scene.VectorTypes,
+  Scene.VectorGeometry,
+  GLMaterial,
+  GLGraphics,
+  Scene.VectorLists,
+  GLColor,
+  GLRenderContextInfo,
+  GLState,
+  GLTextureFormat,
+
   GLTexture,
   GLScene,
-  Scene.VectorGeometry,
-  Scene.VectorTypes,
+  GLContext,
   GLCadencer,
   Scene.Strings,
-  OpenGLTokens,
   GLSL.Shader,
-  GLS.ShaderCustom,
-  GLColor,
-  GLRenderContextInfo,
-  GLMaterial;
+  GLSL.CustomShader,
+  GLS.Utils;
 
 type
+  TBumpMethod = (bmDot3TexCombiner, bmBasicARBFP);
+  TBumpSpace = (bsObject, bsTangentExternal, bsTangentQuaternion);
+
+  TBumpOption = (boDiffuseTexture2, // Use secondary texture as diffuse
+    boSpecularTexture3, // Use tertiary texture as specular
+    boUseSecondaryTexCoords, // Pass through secondary texcoords
+    boLightAttenuation, // Use light attenuation
+    boParallaxMapping // Enable parallax offset mapping
+    );
+  TBumpOptions = set of TBumpOption;
+  TSpecularMode = (smOff, smBlinn, smPhong);
+
   EGLSLBumpShaderException = class(EGLSLShaderException);
 
   // An abstract class.
@@ -187,14 +211,13 @@ type
   public
     constructor Create(AOwner : TComponent); override;
     property LightSources: TGLLightSourceSet read FLightSources write SetLightSources default [1];
-    {Setting LightCompensation to a value less than 1 decreeses individual
-       light intensity when using multiple lights }
+    (* Setting LightCompensation to a value less than 1 decreeses individual
+       light intensity when using multiple lights *)
     property LightCompensation: Single read FLightCompensation write SetLightCompensation;
   end;
 
-                {************** Published **************}
-
-  // One light shaders.
+ {************** Published **************}
+   // One light shaders.
   TGLSLBumpShaderMT = class(TGLCustomGLSLBumpShaderMT)
   published
     property MainTextureName;
@@ -267,6 +290,78 @@ type
     property LightCompensation;
   end;
 
+
+(*
+   A shader that applies bump mapping.
+   Notes:
+   The normal map is expected to be the primary texture.
+
+   The secondary texture is used for the diffuse texture,
+   to enable set boDiffuseTexture2 in the BumpOptions property.
+
+   The tertiary texture is used for the specular texture,
+   to enable set boSpecularTexture3 in the BumpOptions property.
+   The SpecularMode determines the specular highlight calculation
+   (Blinn or Phong), smOff disables specular highlights in the
+   shader.
+
+   External tangent bump space expects tangent data under
+   GL_TEXTURE1_ARB and binormal data under GL_TEXTURE2_ARB.
+
+   The boUseSecondaryTexCoords bump option tells the shader to use
+   the secondary texture coordinates for the diffuse and specular
+   texture lookups.
+
+*)
+
+  // A generic bump shader.
+  TGLBumpShader = class(TGLShader)
+  private
+    FVertexProgramHandle: TGLARBVertexProgramHandle;
+    FFragmentProgramHandle: TGLARBFragmentProgramHandle;
+    FLightIDs: TIntegerList;
+    FLightsEnabled: Integer;
+    FBumpMethod: TBumpMethod;
+    FBumpSpace: TBumpSpace;
+    FBumpOptions: TBumpOptions;
+    FSpecularMode: TSpecularMode;
+    FDesignTimeEnabled: Boolean;
+    FAmbientPass: Boolean;
+    FDiffusePass: Boolean;
+    FVertexProgram: TStringList;
+    FFragmentProgram: TStringList;
+    FParallaxOffset: Single;
+    function GenerateVertexProgram: string;
+    function GenerateFragmentProgram: string;
+    procedure DoLightPass(var rci: TGLRenderContextInfo; lightID: Cardinal);
+  protected
+    procedure SetBumpMethod(const Value: TBumpMethod);
+    procedure SetBumpSpace(const Value: TBumpSpace);
+    procedure SetBumpOptions(const Value: TBumpOptions);
+    procedure SetSpecularMode(const Value: TSpecularMode);
+    procedure SetDesignTimeEnabled(const Value: Boolean);
+    procedure SetParallaxOffset(const Value: Single);
+    procedure Loaded; override;
+    procedure DeleteVertexPrograms;
+    procedure DeleteFragmentPrograms;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
+    function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
+  published
+    property BumpMethod: TBumpMethod read FBumpMethod write SetBumpMethod;
+    property BumpSpace: TBumpSpace read FBumpSpace write SetBumpSpace;
+    property BumpOptions: TBumpOptions read FBumpOptions write SetBumpOptions;
+    property SpecularMode: TSpecularMode read FSpecularMode write
+      SetSpecularMode;
+    property DesignTimeEnabled: Boolean read FDesignTimeEnabled write
+      SetDesignTimeEnabled;
+    property ParallaxOffset: Single read FParallaxOffset write
+      SetParallaxOffset;
+  end;
+
+
 //--------------------------------------------------------------
 implementation
 //--------------------------------------------------------------
@@ -1090,9 +1185,747 @@ begin
   SetSpecularTexture(Textures[1]);
 end;
 
+// ------------------
+// ------------------ TGLBumpShader ------------------
+// ------------------
+
+constructor TGLBumpShader.Create(AOwner: TComponent);
+begin
+  inherited;
+  FLightIDs := TIntegerList.Create;
+  FBumpMethod := bmDot3TexCombiner;
+  FBumpSpace := bsObject;
+  FBumpOptions := [];
+  FSpecularMode := smOff;
+  ShaderStyle := ssLowLevel;
+  FParallaxOffset := 0.04;
+
+  FVertexProgram := TStringList.Create;
+  FFragmentProgram := TStringList.Create;
+end;
+
+
+destructor TGLBumpShader.Destroy;
+begin
+  DeleteVertexPrograms;
+  DeleteFragmentPrograms;
+  FLightIDs.Free;
+  FVertexProgram.Free;
+  FFragmentProgram.Free;
+  inherited;
+end;
+
+procedure TGLBumpShader.Loaded;
+begin
+  inherited;
+end;
+
+function TGLBumpShader.GenerateVertexProgram: string;
+var
+  VP: TStringList;
+  DoTangent, DoSpecular, DoParallaxOffset: Boolean;
+  texcoord: Integer;
+begin
+  DoSpecular := (BumpMethod = bmBasicARBFP) and not (SpecularMode = smOff);
+  DoTangent := (BumpSpace = bsTangentExternal) or (BumpSpace =
+    bsTangentQuaternion);
+  DoParallaxOffset := (BumpMethod = bmBasicARBFP) and (boParallaxMapping in
+    BumpOptions) and DoTangent;
+
+  VP := TStringList.Create;
+
+  VP.Add('!!ARBvp1.0');
+  VP.Add('OPTION ARB_position_invariant;');
+
+  VP.Add('PARAM mv[4] = { state.matrix.modelview };');
+  VP.Add('PARAM mvinv[4] = { state.matrix.modelview.inverse };');
+  VP.Add('PARAM mvit[4] = { state.matrix.modelview.invtrans };');
+  VP.Add('PARAM tex[4] = { state.matrix.texture[0] };');
+  if boUseSecondaryTexCoords in BumpOptions then
+    VP.Add('PARAM tex2[4] = { state.matrix.texture[1] };');
+  VP.Add('PARAM lightPos = program.local[0];');
+  VP.Add('PARAM lightAtten = program.local[1];');
+  if BumpSpace = bsTangentExternal then
+  begin
+    VP.Add('ATTRIB tangent = vertex.texcoord[1];');
+    VP.Add('ATTRIB binormal = vertex.texcoord[2];');
+    VP.Add('ATTRIB normal = vertex.normal;');
+  end;
+  VP.Add('TEMP temp, temp2, light, eye, atten;');
+
+  if (boLightAttenuation in BumpOptions) then
+  begin
+
+    VP.Add('   DP4 temp.x, mv[0], vertex.position;');
+    VP.Add('   DP4 temp.y, mv[1], vertex.position;');
+    VP.Add('   DP4 temp.z, mv[2], vertex.position;');
+    VP.Add('   ADD light, lightPos, -temp;');
+
+    VP.Add('   DP3 atten.y, light, light;');
+    VP.Add('   RSQ atten.y, atten.y;');
+    if BumpMethod = bmDot3TexCombiner then
+    begin
+      VP.Add('   RCP atten.y, atten.y;');
+      VP.Add('   MUL atten.z, atten.y, atten.y;');
+      VP.Add('   MAD atten.x, lightAtten.y, atten.y, lightAtten.x;');
+      VP.Add('   MAD atten.x, lightAtten.z, atten.z, atten.x;');
+      VP.Add('   RCP atten.x, atten.x;');
+    end
+    else if BumpMethod = bmBasicARBFP then
+    begin
+      // Store the distance in atten.x for ARBFP,
+      // fragment program will calculate attenutation
+      VP.Add('   RCP atten.x, atten.y;');
+    end;
+
+    VP.Add('   DP3 temp.x, mvinv[0], light;');
+    VP.Add('   DP3 temp.y, mvinv[1], light;');
+    VP.Add('   DP3 temp.z, mvinv[2], light;');
+    VP.Add('   MOV light, temp;');
+  end
+  else
+  begin
+    VP.Add('   DP4 light.x, mvinv[0], lightPos;');
+    VP.Add('   DP4 light.y, mvinv[1], lightPos;');
+    VP.Add('   DP4 light.z, mvinv[2], lightPos;');
+    VP.Add('   ADD light, light, -vertex.position;');
+  end;
+
+  if DoSpecular or DoParallaxOffset then
+    VP.Add('   ADD eye, mvit[3], -vertex.position;');
+
+  if DoTangent then
+  begin
+    if BumpSpace = bsTangentExternal then
+    begin
+
+      VP.Add('   DP3 temp.x, light, tangent;');
+      VP.Add('   DP3 temp.y, light, binormal;');
+      VP.Add('   DP3 temp.z, light, normal;');
+      VP.Add('   MOV light, temp;');
+      if DoSpecular or DoParallaxOffset then
+      begin
+        VP.Add('   DP3 temp.x, eye, tangent;');
+        VP.Add('   DP3 temp.y, eye, binormal;');
+        VP.Add('   DP3 temp.z, eye, normal;');
+        VP.Add('   MOV eye, temp;');
+      end;
+
+    end
+    else if BumpSpace = bsTangentQuaternion then
+    begin
+
+      VP.Add('   DP3 temp.x, light, light;');
+      VP.Add('   RSQ temp.x, temp.x;');
+      VP.Add('   MUL light, temp.x, light;');
+
+      VP.Add('   MOV temp2.x, vertex.normal.y;');
+      VP.Add('   ADD temp2.y, 0.0, -vertex.normal.x;');
+      VP.Add('   MOV temp2.z, 0.0;');
+
+      VP.Add('   DP3 temp.x, temp2, light;');
+      VP.Add('   MUL temp.x, temp2.y, light.z;');
+      VP.Add('   MAD temp.y, vertex.normal.z, light.x, temp.x;');
+      VP.Add('   MUL temp.x, vertex.normal.y, light.z;');
+      VP.Add('   MAD temp.z, vertex.normal.z, light.y, -temp.x;');
+      VP.Add('   MUL temp.x, vertex.normal.y, light.y;');
+      VP.Add('   MAD temp.x, vertex.normal.z, light.z, temp.x;');
+      VP.Add('   MAD temp.w, -temp2.y, light.x, temp.x;');
+      VP.Add('   MOV light, temp.yzwy;');
+
+      if DoSpecular or DoParallaxOffset then
+      begin
+        VP.Add('   DP3 temp.x, temp2, eye;');
+        VP.Add('   MUL temp.x, temp2.y, eye.z;');
+        VP.Add('   MAD temp.y, vertex.normal.z, eye.x, temp.x;');
+        VP.Add('   MUL temp.x, vertex.normal.y, eye.z;');
+        VP.Add('   MAD temp.z, vertex.normal.z, eye.y, -temp.x;');
+        VP.Add('   MUL temp.x, vertex.normal.y, eye.y;');
+        VP.Add('   MAD temp.x, vertex.normal.z, eye.z, temp.x;');
+        VP.Add('   MAD temp.w, -temp2.y, eye.x, temp.x;');
+        VP.Add('   MOV eye, temp.yzwy;');
+      end;
+
+    end;
+  end;
+
+  if BumpMethod = bmDot3TexCombiner then
+  begin
+
+    if BumpSpace <> bsTangentQuaternion then
+    begin
+      VP.Add('   DP3 temp.x, light, light;');
+      VP.Add('   RSQ temp, temp.x;');
+      VP.Add('   MUL light, temp.x, light;');
+    end;
+
+    if boLightAttenuation in BumpOptions then
+      VP.Add('   MUL light, atten.x, light;');
+
+    VP.Add('   MAD result.color, light, 0.5, 0.5;');
+    VP.Add('   MOV result.color.w, 1.0;');
+
+  end
+  else if BumpMethod = bmBasicARBFP then
+  begin
+
+    if boLightAttenuation in BumpOptions then
+      VP.Add('   MOV light.w, atten.x;')
+    else
+      VP.Add('   MOV light.w, 0.0;');
+    if DoSpecular or DoParallaxOffset then
+      VP.Add('   MOV eye.w, 0.0;');
+
+  end;
+
+  texcoord := 0;
+
+  VP.Add('   DP4 temp.x, vertex.texcoord[0], tex[0];');
+  VP.Add('   DP4 temp.y, vertex.texcoord[0], tex[1];');
+  VP.Add('   DP4 temp.z, vertex.texcoord[0], tex[2];');
+  VP.Add('   DP4 temp.w, vertex.texcoord[0], tex[3];');
+  VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
+  Inc(texcoord);
+
+  if boUseSecondaryTexCoords in BumpOptions then
+  begin
+    VP.Add('   DP4 temp.x, vertex.texcoord[1], tex2[0];');
+    VP.Add('   DP4 temp.y, vertex.texcoord[1], tex2[1];');
+    VP.Add('   DP4 temp.z, vertex.texcoord[1], tex2[2];');
+    VP.Add('   DP4 temp.w, vertex.texcoord[1], tex2[3];');
+    VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
+    Inc(texcoord);
+  end;
+
+  if BumpMethod = bmDot3TexCombiner then
+  begin
+    if (boDiffuseTexture2 in BumpOptions)
+      and not (boUseSecondaryTexCoords in BumpOptions) then
+      VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], temp;');
+  end
+  else
+  begin
+    VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], light;');
+    Inc(texcoord);
+    if DoSpecular then
+      VP.Add('   MOV result.texcoord[' + IntToStr(texcoord) + '], eye;');
+  end;
+
+  VP.Add('END');
+
+  FVertexProgram.Assign(VP);
+  Result := VP.Text;
+  VP.Free;
+end;
+
+function TGLBumpShader.GenerateFragmentProgram: string;
+var
+  FP: TStringList;
+  DoSpecular,
+    DoTangent,
+    DoParallaxOffset: Boolean;
+  texcoord,
+    normalTexCoords,
+    diffTexCoords,
+    specTexCoords,
+    lightTexCoords,
+    eyeTexCoords: Integer;
+begin
+  DoSpecular := not (SpecularMode = smOff);
+  DoTangent := (BumpSpace = bsTangentExternal) or (BumpSpace =
+    bsTangentQuaternion);
+  DoParallaxOffset := (boParallaxMapping in BumpOptions) and DoTangent;
+
+  texcoord := 0;
+  normalTexCoords := texcoord;
+  if boUseSecondaryTexCoords in BumpOptions then
+    Inc(texcoord);
+  diffTexCoords := texcoord;
+  specTexCoords := texcoord;
+  Inc(texcoord);
+  lightTexCoords := texcoord;
+  Inc(texcoord);
+  eyeTexCoords := texcoord;
+
+  FP := TStringList.Create;
+
+  FP.Add('!!ARBfp1.0');
+
+  FP.Add('PARAM lightDiffuse = program.local[0];');
+  FP.Add('PARAM lightSpecular = program.local[1];');
+  FP.Add('PARAM lightAtten = program.local[2];');
+  FP.Add('PARAM materialDiffuse = state.material.diffuse;');
+  FP.Add('PARAM materialSpecular = state.material.specular;');
+  FP.Add('PARAM shininess = state.material.shininess;');
+  FP.Add('TEMP temp, tex, light, eye, normal, col, diff, spec;');
+  FP.Add('TEMP textureColor, reflect, atten, offset, texcoord;');
+
+  if DoSpecular or DoParallaxOffset then
+  begin
+    // Get the eye vector
+    FP.Add('   DP3 eye, fragment.texcoord[' + IntToStr(eyeTexCoords) +
+      '], fragment.texcoord[' + IntToStr(eyeTexCoords) + '];');
+    FP.Add('   RSQ eye, eye.x;');
+    FP.Add('   MUL eye, fragment.texcoord[' + IntToStr(eyeTexCoords) +
+      '], eye.x;');
+  end;
+
+  if DoParallaxOffset then
+  begin
+    // Get the parallax offset
+    FP.Add('   TEX textureColor, fragment.texcoord[' + IntToStr(normalTexCoords)
+      + '], texture[0], 2D;');
+    FP.Add(Format('   MAD offset.x, textureColor.a, %f, %f;', [FParallaxOffset,
+      -0.5 * FParallaxOffset]));
+    FP.Add('   MUL offset, eye, offset.x;');
+    FP.Add('   ADD texcoord, fragment.texcoord[' + IntToStr(normalTexCoords) +
+      '], offset;');
+  end
+  else
+    FP.Add('   MOV texcoord, fragment.texcoord[' + IntToStr(normalTexCoords) +
+      '];');
+
+  // Get the normalized normal vector
+  FP.Add('   TEX textureColor, texcoord, texture[0], 2D;');
+  FP.Add('   ADD normal, textureColor, -0.5;');
+  FP.Add('   DP3 temp, normal, normal;');
+  FP.Add('   RSQ temp, temp.x;');
+  FP.Add('   MUL normal, normal, temp.x;');
+
+  // Get the normalized light vector
+  FP.Add('   MOV light, fragment.texcoord[' + IntToStr(lightTexCoords) + '];');
+  if boLightAttenuation in BumpOptions then
+    FP.Add('   MOV atten.x, light.w;');
+  FP.Add('   DP3 light, light, light;');
+  FP.Add('   RSQ light, light.x;');
+  FP.Add('   MUL light, fragment.texcoord[' + IntToStr(lightTexCoords) +
+    '], light.x;');
+
+  // Calculate the diffuse color
+  FP.Add('   DP3 diff, normal, light;');
+  FP.Add('   MUL diff, diff, lightDiffuse;');
+  FP.Add('   MUL diff, diff, materialDiffuse;');
+  if boDiffuseTexture2 in BumpOptions then
+  begin
+    if DoParallaxOffset then
+    begin
+      FP.Add('   ADD temp, fragment.texcoord[' + IntToStr(diffTexCoords) +
+        '], offset;');
+      FP.Add('   TEX textureColor, temp, texture[1], 2D;');
+    end
+    else
+      FP.Add('   TEX textureColor, fragment.texcoord[' + IntToStr(diffTexCoords)
+        + '], texture[1], 2D;');
+    FP.Add('   MUL diff, diff, textureColor;');
+  end;
+
+  if DoSpecular then
+  begin
+    case SpecularMode of
+      smBlinn:
+        begin
+          FP.Add('   ADD eye, eye, light;');
+          FP.Add('   DP3 temp, eye, eye;');
+          FP.Add('   RSQ temp, temp.x;');
+          FP.Add('   MUL eye, eye, temp.x;');
+          FP.Add('   DP3_SAT spec, normal, eye;');
+        end;
+      smPhong:
+        begin
+          FP.Add('   DP3 reflect, normal, light;');
+          FP.Add('   MUL reflect, reflect.x, normal;');
+          FP.Add('   MUL reflect, 2.0, reflect;');
+          FP.Add('   ADD reflect, reflect, -light;');
+          FP.Add('   DP3_SAT spec, reflect, eye;');
+        end;
+    else
+      Assert(False, 'Invalid specular mode!');
+    end;
+
+    FP.Add('   POW spec, spec.x, shininess.x;');
+    FP.Add('   MUL spec, spec, materialSpecular;');
+    FP.Add('   MUL spec, spec, lightSpecular;');
+    if boSpecularTexture3 in BumpOptions then
+    begin
+      if DoParallaxOffset then
+      begin
+        FP.Add('   ADD temp, fragment.texcoord[' + IntToStr(specTexCoords) +
+          '], offset;');
+        FP.Add('   TEX textureColor, temp, texture[2], 2D;');
+      end
+      else
+        FP.Add('   TEX textureColor, fragment.texcoord[' +
+          IntToStr(specTexCoords) + '], texture[2], 2D;');
+      FP.Add('   MUL spec, spec, textureColor;');
+    end;
+  end;
+
+  // Output
+  if DoSpecular then
+    FP.Add('   ADD temp, diff, spec;')
+  else
+    FP.Add('   MOV temp, diff;');
+
+  if boLightAttenuation in BumpOptions then
+  begin
+    FP.Add('   MUL atten.y, atten.x, atten.x;');
+    FP.Add('   MAD atten.x, lightAtten.y, atten.x, lightAtten.x;');
+    FP.Add('   MAD atten.x, lightAtten.z, atten.y, atten.x;');
+    FP.Add('   RCP atten.x, atten.x;');
+    FP.Add('   MUL temp, temp, atten.x;');
+  end;
+
+  FP.Add('   MOV_SAT result.color, temp;');
+  FP.Add('   MOV result.color.w, 1.0;');
+
+  FP.Add('END');
+
+  FFragmentProgram.Assign(FP);
+  Result := FP.Text;
+  FP.Free;
+end;
+
+// DoLightPass
+//
+
+procedure TGLBumpShader.DoLightPass(var rci: TGLRenderContextInfo;
+  lightID: Cardinal);
+var
+  dummyHandle, tempHandle: Integer;
+  lightPos, lightAtten,
+    materialDiffuse, lightDiffuse, lightSpecular: TVector;
+begin
+  FVertexProgramHandle.Enable;
+  FVertexProgramHandle.Bind;
+
+  // Set the light position to program.local[0]
+  gl.GetLightfv(GL_LIGHT0 + FLightIDs[0], GL_POSITION, @lightPos.X);
+  gl.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, 0, @lightPos.X);
+
+  // Set the light attenutation to program.local[1]
+  lightAtten.X := rci.GLStates.LightConstantAtten[FLightIDs[0]];
+  lightAtten.Y := rci.GLStates.LightLinearAtten[FLightIDs[0]];
+  lightAtten.Z := rci.GLStates.LightQuadraticAtten[FLightIDs[0]];
+  gl.ProgramLocalParameter4fv(GL_VERTEX_PROGRAM_ARB, 1, @lightAtten.X);
+
+  case FBumpMethod of
+    bmDot3TexCombiner:
+      begin
+        rci.GLStates.ActiveTexture := 0;
+        dummyHandle := rci.GLStates.TextureBinding[0, ttTexture2D];
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE0_ARB);
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
+
+        rci.GLStates.ActiveTexture := 1;
+        rci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
+        tempHandle := rci.GLStates.TextureBinding[1, ttTexture2D];
+        if tempHandle = 0 then
+          rci.GLStates.TextureBinding[1, ttTexture2D] := dummyHandle;
+        lightDiffuse := rci.GLStates.LightDiffuse[FLightIDs[0]];
+        gl.GetMaterialfv(GL_FRONT, GL_DIFFUSE, @materialDiffuse);
+        lightDiffuse.X := lightDiffuse.X * materialDiffuse.X;
+        lightDiffuse.Y := lightDiffuse.Y * materialDiffuse.Y;
+        lightDiffuse.Z := lightDiffuse.Z * materialDiffuse.Z;
+        lightDiffuse.W := lightDiffuse.W * materialDiffuse.W;
+        gl.TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, @lightDiffuse);
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
+        gl.TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_COLOR_EXT);
+
+        with rci.GLStates do
+        begin
+          ActiveTexture := 2;
+          ActiveTextureEnabled[ttTexture2D] := False;
+          ActiveTexture := 0;
+        end;
+      end;
+
+    bmBasicARBFP:
+      begin
+        FFragmentProgramHandle.Enable;
+        FFragmentProgramHandle.Bind;
+        lightDiffuse := rci.GLStates.LightDiffuse[FLightIDs[0]];
+        lightSpecular := rci.GLStates.LightSpecular[FLightIDs[0]];
+        lightAtten.X := rci.GLStates.LightConstantAtten[FLightIDs[0]];
+
+        gl.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 0,
+          @lightDiffuse.X);
+        gl.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 1,
+          @lightSpecular.X);
+        gl.ProgramLocalParameter4fv(GL_FRAGMENT_PROGRAM_ARB, 2,
+          @lightAtten.X);
+      end;
+
+  else
+    Assert(False, 'Invalid bump method!');
+  end;
+end;
+
+procedure TGLBumpShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
+var
+  maxTextures, i: Integer;
+  ambient, LMaterialAmbient: TColorVector;
+  success: Boolean;
+begin
+  if (csDesigning in ComponentState) and not DesignTimeEnabled then
+    exit;
+  if not Enabled then
+    exit;
+
+  gl.GetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, @maxTextures);
+
+  success := False;
+  try
+    if not gl.ARB_multitexture then
+      raise Exception.Create('This shader requires GL_ARB_multitexture.');
+    if (maxTextures < 3)
+      and ((BumpMethod <> bmDot3TexCombiner) or (BumpSpace = bsTangentExternal)) then
+      raise
+        Exception.Create('The current shader settings require 3 or more texture units.');
+    if (maxTextures < 4)
+      and (BumpMethod <> bmDot3TexCombiner)
+      and (boUseSecondaryTexCoords in BumpOptions)
+      and (SpecularMode <> smOff) then
+      raise
+        Exception.Create('The current shader settings require 4 or more texture units.');
+
+    if not Assigned(FVertexProgramHandle) then
+    begin
+      FVertexProgramHandle := TGLARBVertexProgramHandle.CreateAndAllocate;
+      FVertexProgramHandle.LoadARBProgram(GenerateVertexProgram);
+    end;
+
+    if not Assigned(FFragmentProgramHandle) then
+      if FBumpMethod = bmBasicARBFP then
+      begin
+        FFragmentProgramHandle := TGLARBFragmentProgramHandle.CreateAndAllocate;
+        FFragmentProgramHandle.LoadARBProgram(GenerateFragmentProgram);
+      end;
+
+    success := True;
+
+  finally
+    if not success then
+    begin
+      Enabled := False;
+      DesignTimeEnabled := False;
+    end;
+  end;
+
+  FLightIDs.Clear;
+  rci.GLStates.ActiveTexture := 0;
+  if rci.GLStates.ActiveTextureEnabled[ttTexture2D] then
+    for i := 0 to rci.GLStates.MaxLights - 1 do
+    begin
+      if rci.GLStates.LightEnabling[i] then
+        FLightIDs.Add(i);
+    end;
+  FLightsEnabled := FLightIDs.Count;
+
+  FAmbientPass := False;
+  FDiffusePass := False;
+
+  if FLightIDs.Count > 0 then
+  begin
+
+    rci.GLStates.DepthFunc := cfLEqual;
+    rci.GLStates.Disable(stBlend);
+    DoLightPass(rci, FLightIDs[0]);
+    FLightIDs.Delete(0);
+
+  end
+  else
+    with rci.GLStates do
+    begin
+      Disable(stLighting);
+      ActiveTexture := 0;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 1;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 2;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 0;
+
+      gl.GetFloatv(GL_LIGHT_MODEL_AMBIENT, @ambient);
+      gl.GetMaterialfv(GL_FRONT, GL_AMBIENT, @LMaterialAmbient);
+      ambient.X := ambient.X * LMaterialAmbient.X;
+      ambient.Y := ambient.Y * LMaterialAmbient.Y;
+      ambient.Z := ambient.Z * LMaterialAmbient.Z;
+      gl.Color3fv(@ambient);
+
+      FAmbientPass := True;
+
+    end;
+end;
+
+function TGLBumpShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
+var
+  ambient, LMaterialAmbient: TVector;
+begin
+  Result := False;
+  if (csDesigning in ComponentState) and not DesignTimeEnabled then
+    exit;
+  if not Enabled then
+    exit;
+
+  if FLightIDs.Count > 0 then
+    with rci.GLStates do
+    begin
+
+      DepthFunc := cfLEqual;
+      Enable(stBlend);
+      SetBlendFunc(bfOne, bfOne);
+
+      DoLightPass(rci, FLightIDs[0]);
+      FLightIDs.Delete(0);
+      Result := True;
+      Exit;
+
+    end
+  else if not FDiffusePass and (FLightsEnabled <> 0)
+    and (boDiffuseTexture2 in BumpOptions)
+    and (BumpMethod = bmDot3TexCombiner) then
+    with rci.GLStates do
+    begin
+      Enable(stBlend);
+      SetBlendFunc(bfDstColor, bfZero);
+      ActiveTexture := 0;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 1;
+      ActiveTextureEnabled[ttTexture2D] := True;
+      gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+      ActiveTexture := 2;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 0;
+      FDiffusePass := True;
+      Result := True;
+      Exit;
+    end
+  else if not FAmbientPass then
+    with rci.GLStates do
+    begin
+      FVertexProgramHandle.Disable;
+      if BumpMethod = bmBasicARBFP then
+        FFragmentProgramHandle.Disable;
+      Disable(stLighting);
+      ActiveTexture := 0;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 1;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 2;
+      ActiveTextureEnabled[ttTexture2D] := False;
+      ActiveTexture := 0;
+
+      DepthFunc := cfLEqual;
+      Enable(stBlend);
+      SetBlendFunc(bfOne, bfOne);
+
+      gl.GetFloatv(GL_LIGHT_MODEL_AMBIENT, @ambient);
+      gl.GetMaterialfv(GL_FRONT, GL_AMBIENT, @LMaterialAmbient);
+      ambient.X := ambient.X * LMaterialAmbient.X;
+      ambient.Y := ambient.Y * LMaterialAmbient.Y;
+      ambient.Z := ambient.Z * LMaterialAmbient.Z;
+      gl.Color3fv(@ambient);
+
+      FAmbientPass := True;
+      Result := True;
+      Exit;
+    end;
+
+  FVertexProgramHandle.Disable;
+  if BumpMethod = bmBasicARBFP then
+    FFragmentProgramHandle.Disable;
+end;
+
+procedure TGLBumpShader.DeleteVertexPrograms;
+begin
+  FVertexProgramHandle.Free;
+  FVertexProgramHandle := nil;
+  FVertexProgram.Clear;
+end;
+
+procedure TGLBumpShader.DeleteFragmentPrograms;
+begin
+  FFragmentProgramHandle.Free;
+  FFragmentProgramHandle := nil;
+  FFragmentProgram.Clear;
+end;
+
+procedure TGLBumpShader.SetBumpMethod(const Value: TBumpMethod);
+begin
+  if Value <> FBumpMethod then
+  begin
+    FBumpMethod := Value;
+    DeleteVertexPrograms;
+    DeleteFragmentPrograms;
+    NotifyChange(Self);
+  end;
+end;
+
+procedure TGLBumpShader.SetBumpSpace(const Value: TBumpSpace);
+begin
+  if Value <> FBumpSpace then
+  begin
+    FBumpSpace := Value;
+    DeleteVertexPrograms;
+    DeleteFragmentPrograms;
+    NotifyChange(Self);
+  end;
+end;
+
+procedure TGLBumpShader.SetBumpOptions(const Value: TBumpOptions);
+begin
+  if Value <> FBumpOptions then
+  begin
+    FBumpOptions := Value;
+    DeleteVertexPrograms;
+    DeleteFragmentPrograms;
+    NotifyChange(Self);
+  end;
+end;
+
+procedure TGLBumpShader.SetSpecularMode(const Value: TSpecularMode);
+begin
+  if Value <> FSpecularMode then
+  begin
+    FSpecularMode := Value;
+    DeleteVertexPrograms;
+    DeleteFragmentPrograms;
+    NotifyChange(Self);
+  end;
+end;
+
+procedure TGLBumpShader.SetDesignTimeEnabled(const Value: Boolean);
+begin
+  if Value <> FDesignTimeEnabled then
+  begin
+    FDesignTimeEnabled := Value;
+    NotifyChange(Self);
+  end;
+end;
+
+procedure TGLBumpShader.SetParallaxOffset(const Value: Single);
+begin
+  if Value <> FParallaxOffset then
+  begin
+    FParallaxOffset := Value;
+    DeleteVertexPrograms;
+    DeleteFragmentPrograms;
+    NotifyChange(Self);
+  end;
+end;
+
+
+//-----------------------------------------------
 initialization
+//-----------------------------------------------
+
   RegisterClasses([TGLSLBumpShaderMT, TGLSLBumpShader, TGLSLBumpShaderAM,
                    TGLSLMLBumpShader, TGLSLMLBumpShaderMT]);
 
 end.
 
+

+ 2 - 2
Source/GLS.cgShaderBomb.pas → Source/GLSL.CgBombShader.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.cgShaderBomb;
+unit GLSL.CgBombShader;
 
 (*  Just a good looking shader *)
 
@@ -23,7 +23,7 @@ uses
   GLTextureFormat,
 
   Import.cgGL,
-  GLS.cgShader;
+  GLSL.CgShader;
 
 type
   ECgBombShaderException = class(ECgShaderException);

+ 4 - 4
Source/GLS.cgShaderPostTransformation.pas → Source/GLSL.CgPostTransformationShader.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.cgShaderPostTransformation;
+unit GLSL.CgPostTransformationShader;
 
 (*
    A shader that uses a texture to distort the view by adjusting texture
@@ -22,13 +22,13 @@ uses
   GLCadencer, 
   GLContext, 
   GLScene, 
-  GLS.ShaderCustom,
-  GLRenderContextInfo, 
+  GLRenderContextInfo,
   GLTextureFormat,
 
   Import.Cg,
   Import.CgGL,
-  GLS.cgShader;
+  GLSL.CustomShader,
+  GLSL.CgShader;
 
 type
 

+ 5 - 5
Source/GLS.cgRegister.pas → Source/GLSL.CgRegister.pas

@@ -2,9 +2,9 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.cgRegister;
+unit GLSL.CgRegister;
 
-(*  Registration unit for CG shader package *)
+(*  Registration unit for Cg shader package *)
 
 interface
 
@@ -20,9 +20,9 @@ uses
 
   Import.Cg,
   Import.CgGL,
-  GLS.SceneRegister,
-  GLS.cgShader,
-  GLS.cgShaderBomb;
+  GLS.SceneRegister,  //?
+  GLSL.CgShader,
+  GLSL.CgBombShader;
 
 procedure Register;
 

+ 3 - 2
Source/GLS.cgShader.pas → Source/GLSL.CgShader.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.cgShader;
+unit GLSL.CgShader;
 
 (* Base Cg shader classes *)
 
@@ -284,7 +284,8 @@ type
       write SetOnUnApplyVertexProgram;
     property OnUnApplyFP: TCgUnApplyEvent read GetOnUnApplyFragmentProgram
       write SetOnUnApplyFragmentProgram;
-    { OnInitialize can be use to set parameters that need to be set once only. See demo "Cg Texture" for example. }
+    (* OnInitialize can be use to set parameters that need to be set once only.
+      See demo "Cg Texture" for example. *)
     property OnInitialize: TCgShaderEvent read GetOnInitialize
       write SetOnInitialize;
     property DesignEnable: boolean read FDesignEnable write FDesignEnable

+ 1 - 1
Source/GLS.ShaderCustom.pas → Source/GLSL.CustomShader.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.ShaderCustom;
+unit GLSL.CustomShader;
 
 (*
     A collection of pure abstract classes - descendants of TGLShader, which are

+ 827 - 0
Source/GLSL.DiffuseSpecularShader.pas

@@ -0,0 +1,827 @@
+//
+// This unit is part of the GLScene Engine, http://glscene.org
+//
+
+unit GLSL.DiffuseSpecularShader;
+
+(*
+   This is a collection of GLSL diffuse-specular shaders
+   (to know what these suffixes and prefixes mean see GLCustomShader.pas):
+      - TGLSLDiffuseSpecularShader
+      - TGLSLDiffuseSpecularShaderMT
+
+      - TGLSLMLDiffuseSpecularShader
+      - TGLSLMLDiffuseSpecularShaderMT
+
+    Notes:
+     1) TGLSLDiffuseSpecularShader takes all Material parameters directly
+      from OpenGL (that includes TGLMaterial's)
+     2) TGLSLDiffuseSpecularShader takes all Light parameters directly
+      from OpenGL (that includes TGLLightSource's)
+
+*)
+
+interface
+
+{$I GLScene.inc}
+
+uses
+  System.Classes,
+  System.SysUtils,
+  
+  OpenGLTokens,
+  GLTexture,
+  GLScene,
+  Scene.PersistentClasses,
+  Scene.VectorGeometry,
+  Scene.Strings,
+  GLSL.Shader,
+  GLSL.CustomShader,
+  GLColor,
+  GLRenderContextInfo,
+  GLMaterial;
+
+type
+  EGLSLDiffuseSpecularShaderException = class(EGLSLShaderException);
+
+  // Abstract class.
+  TGLBaseCustomGLSLDiffuseSpecular = class(TGLCustomGLSLShader)
+  private
+    FLightPower: Single;
+    FRealisticSpecular: Boolean;
+    FFogSupport: TGLShaderFogSupport;
+    procedure SetRealisticSpecular(const Value: Boolean);
+    procedure SetFogSupport(const Value: TGLShaderFogSupport);
+  protected
+    procedure DoApply(var rci : TGLRenderContextInfo; Sender : TObject); override;
+    function DoUnApply(var rci: TGLRenderContextInfo): Boolean; override;
+  public
+    constructor Create(AOwner : TComponent); override;
+    property LightPower: Single read FLightPower write FLightPower;
+    property RealisticSpecular: Boolean read FRealisticSpecular write SetRealisticSpecular;
+
+    // User can disable fog support and save some FPS if he doesn't need it.
+    property FogSupport: TGLShaderFogSupport read FFogSupport write SetFogSupport default sfsAuto;
+  end;
+
+  // Abstract class.
+  TGLBaseGLSLDiffuseSpecularShaderMT = class(TGLBaseCustomGLSLDiffuseSpecular, IGLMaterialLibrarySupported)
+  private
+    FMaterialLibrary: TGLMaterialLibrary;
+    FMainTexture: TGLTexture;
+    FMainTextureName: TGLLibMaterialName;
+    function GetMainTextureName: TGLLibMaterialName;
+    procedure SetMainTextureName(const Value: TGLLibMaterialName);
+    // Implementing IGLMaterialLibrarySupported.
+    function GetMaterialLibrary: TGLAbstractMaterialLibrary;
+  protected
+    procedure SetMaterialLibrary(const Value: TGLMaterialLibrary); virtual;
+    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
+    procedure DoApply(var rci : TGLRenderContextInfo; Sender : TObject); override;
+  public
+    property MainTexture: TGLTexture read FMainTexture write FMainTexture;
+    property MainTextureName: TGLLibMaterialName read GetMainTextureName write SetMainTextureName;
+    property MaterialLibrary: TGLMaterialLibrary read FMaterialLibrary write SetMaterialLibrary;
+  end;
+
+                     {********  Single Light  ************}
+
+  TGLCustomGLSLDiffuseSpecularShader = class(TGLBaseCustomGLSLDiffuseSpecular)
+  protected
+    procedure DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject); override;
+    procedure DoApply(var rci : TGLRenderContextInfo; Sender : TObject); override;
+  end;
+
+
+  TGLCustomGLSLDiffuseSpecularShaderMT = class(TGLBaseGLSLDiffuseSpecularShaderMT)
+  protected
+    procedure DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject); override;
+  end;
+
+  // ********  Multi Light  ************
+
+  (* Note: probably LightCount should be replaced by LightSources, like in
+     GLSLBumpShader.pas *)
+
+  TLightRecord = record
+    Enabled: Boolean;
+    Style: TGLLightStyle;
+  end;
+
+  TGLCustomGLSLMLDiffuseSpecularShader = class(TGLBaseCustomGLSLDiffuseSpecular)
+  private
+    FLightTrace: array[0..7] of TLightRecord;
+  protected
+    procedure DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject); override;
+    procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
+  public
+    constructor Create(AOwner : TComponent); override;
+  end;
+
+  TGLCustomGLSLMLDiffuseSpecularShaderMT = class(TGLBaseGLSLDiffuseSpecularShaderMT)
+  private
+    FLightTrace: array[0..7] of TLightRecord;
+  protected
+    procedure DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject); override;
+    procedure DoApply(var rci: TGLRenderContextInfo; Sender: TObject); override;
+  public
+    constructor Create(AOwner : TComponent); override;
+  end;
+
+  // ********  Published Stuff  ************
+
+  TGLSLDiffuseSpecularShaderMT = class(TGLCustomGLSLDiffuseSpecularShaderMT)
+  published
+    property MainTextureName;
+
+    property LightPower;
+    property FogSupport;
+  end;
+
+  TGLSLDiffuseSpecularShader = class(TGLCustomGLSLDiffuseSpecularShader)
+  published
+    property LightPower;
+    property FogSupport;
+  end;
+
+
+  TGLSLMLDiffuseSpecularShaderMT = class(TGLCustomGLSLMLDiffuseSpecularShaderMT)
+  published
+    property MainTextureName;
+
+    property LightPower;
+    property FogSupport;
+  end;
+
+  TGLSLMLDiffuseSpecularShader = class(TGLCustomGLSLMLDiffuseSpecularShader)
+  published
+    property LightPower;
+    property FogSupport;
+  end;
+
+implementation
+
+procedure GetVertexProgramCode(const Code: TStrings;
+  AFogSupport: Boolean; var rci: TGLRenderContextInfo);
+begin
+  with Code do
+  begin
+    Clear;
+    Add('varying vec3 Normal; ');
+    Add('varying vec4 Position; ');
+    if AFogSupport then
+    begin
+      Add('varying float fogFactor; ');
+    end;
+    Add(' ');
+    Add(' ');
+    Add('void main(void) ');
+    Add('{ ');
+    Add('  gl_Position = ftransform(); ');
+    Add('  gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; ');
+    Add('  Normal = normalize(gl_NormalMatrix * gl_Normal); ');
+    Add('  Position = gl_ModelViewMatrix * gl_Vertex; ');
+
+    if AFogSupport then
+    begin
+    Add('  const float LOG2 = 1.442695; ');
+    Add('  gl_FogFragCoord = length(Position.xyz); ');
+
+    case TGLSceneBuffer(rci.buffer).FogEnvironment.FogMode of
+      fmLinear:
+        Add('  fogFactor = (gl_Fog.end - gl_FogFragCoord) * gl_Fog.scale; ');
+      fmExp, // Yep, I don't know about this type, so I use fmExp2.
+      fmExp2:
+      begin
+        Add('  fogFactor = exp2( -gl_Fog.density * ');
+        Add('  				   gl_Fog.density * ');
+        Add('  				   gl_FogFragCoord * ');
+        Add('  				   gl_FogFragCoord * ');
+        Add('  				   LOG2 ); ');
+      end;
+    else
+      Assert(False, strUnknownType);
+    end;
+
+      Add('  fogFactor = clamp(fogFactor, 0.0, 1.0); ');
+    end;
+
+    Add('} ');
+  end;
+end;
+
+procedure AddLightSub(const Code: TStrings);
+begin
+  with Code do
+  begin
+    Add('void pointLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3)');
+    Add('{');
+    Add('   float nDotVP;       // normal . light direction');
+    Add('   float nDotHV;       // normal . light half vector');
+    Add('   float pf;           // power factor');
+    Add('   float attenuation;  // computed attenuation factor');
+    Add('   float d;            // distance from surface to light source');
+    Add('   vec3  VP;           // direction from surface to light position');
+    Add('   vec3  halfVector;   // direction of maximum highlights');
+    Add(' ');
+    Add('   // Compute vector from surface to light position');
+    Add('   VP = vec3 (gl_LightSource[i].position) - ecPosition3;');
+    Add(' ');
+    Add('   // Compute distance between surface and light position');
+    Add('   d = length(VP);');
+    Add(' ');
+    Add('   // Normalize the vector from surface to light position');
+    Add('   VP = normalize(VP);');
+    Add(' ');
+    Add('   // Compute attenuation');
+    Add('   attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +');
+    Add('       gl_LightSource[i].linearAttenuation * d +');
+    Add('       gl_LightSource[i].quadraticAttenuation * d * d);');
+    Add(' ');
+    Add('   halfVector = normalize(VP + eye);');
+    Add(' ');
+    Add('   nDotVP = max(0.0, dot(normal, VP));');
+    Add('   nDotHV = max(0.0, dot(normal, halfVector));');
+    Add(' ');
+    Add('   if (nDotVP == 0.0)');
+    Add('   {');
+    Add('       pf = 0.0;');
+    Add('   }');
+    Add('   else');
+    Add('   {');
+    Add('       pf = pow(nDotHV, gl_FrontMaterial.shininess);');
+    Add(' ');
+    Add('   }');
+    Add('   Ambient  += gl_LightSource[i].ambient * attenuation;');
+    Add('   Diffuse  += gl_LightSource[i].diffuse * nDotVP * attenuation;');
+    Add('   Specular += gl_LightSource[i].specular * pf * attenuation;');
+    Add('}');
+    Add(' ');
+    Add('void directionalLight(in int i, in vec3 normal)');
+    Add('{');
+    Add('   float nDotVP;         // normal . light direction');
+    Add('   float nDotHV;         // normal . light half vector');
+    Add('   float pf;             // power factor');
+    Add(' ');
+    Add('   nDotVP = max(0.0, dot(normal, normalize(vec3 (gl_LightSource[i].position))));');
+    Add('   nDotHV = max(0.0, dot(normal, vec3 (gl_LightSource[i].halfVector)));');
+    Add(' ');
+    Add('   if (nDotVP == 0.0)');
+    Add('   {');
+    Add('       pf = 0.0;');
+    Add('   }');
+    Add('   else');
+    Add('   {');
+    Add('       pf = pow(nDotHV, gl_FrontMaterial.shininess);');
+    Add(' ');
+    Add('   }');
+    Add('   Ambient  += gl_LightSource[i].ambient;');
+    Add('   Diffuse  += gl_LightSource[i].diffuse * nDotVP;');
+    Add('   Specular += gl_LightSource[i].specular * pf;');
+    Add('}');
+    Add('void spotLight(in int i, in vec3 normal, in vec3 eye, in vec3 ecPosition3)');
+    Add('{');
+    Add('   float nDotVP;            // normal . light direction');
+    Add('   float nDotHV;            // normal . light half vector');
+    Add('   float pf;                // power factor');
+    Add('   float spotDot;           // cosine of angle between spotlight');
+    Add('   float spotAttenuation;   // spotlight attenuation factor');
+    Add('   float attenuation;       // computed attenuation factor');
+    Add('   float d;                 // distance from surface to light source');
+    Add('   vec3  VP;                // direction from surface to light position');
+    Add('   vec3  halfVector;        // direction of maximum highlights');
+    Add(' ');
+    Add('   // Compute vector from surface to light position');
+    Add('   VP = vec3 (gl_LightSource[i].position) - ecPosition3;');
+    Add(' ');
+    Add('   // Compute distance between surface and light position');
+    Add('   d = length(VP);');
+    Add(' ');
+    Add('   // Normalize the vector from surface to light position');
+    Add('   VP = normalize(VP);');
+    Add(' ');
+    Add('   // Compute attenuation');
+    Add('   attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +');
+    Add('       gl_LightSource[i].linearAttenuation * d +');
+    Add('       gl_LightSource[i].quadraticAttenuation * d * d);');
+    Add(' ');
+    Add('   // See if point on surface is inside cone of illumination');
+    Add('   spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection));');
+    Add(' ');
+    Add('   if (spotDot < gl_LightSource[i].spotCosCutoff)');
+    Add('   {');
+    Add('       spotAttenuation = 0.0; // light adds no contribution');
+    Add('   }');
+    Add('   else');
+    Add('   {');
+    Add('       spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);');
+    Add(' ');
+    Add('   }');
+    Add('   // Combine the spotlight and distance attenuation.');
+    Add('   attenuation *= spotAttenuation;');
+    Add(' ');
+    Add('   halfVector = normalize(VP + eye);');
+    Add(' ');
+    Add('   nDotVP = max(0.0, dot(normal, VP));');
+    Add('   nDotHV = max(0.0, dot(normal, halfVector));');
+    Add(' ');
+    Add('   if (nDotVP == 0.0)');
+    Add('   {');
+    Add('       pf = 0.0;');
+    Add('   }');
+    Add('   else');
+    Add('   {');
+    Add('       pf = pow(nDotHV, gl_FrontMaterial.shininess);');
+    Add(' ');
+    Add('   }');
+    Add('   Ambient  += gl_LightSource[i].ambient * attenuation;');
+    Add('   Diffuse  += gl_LightSource[i].diffuse * nDotVP * attenuation;');
+    Add('   Specular += gl_LightSource[i].specular * pf * attenuation;');
+    Add(' ');
+    Add('}');
+    Add('void infiniteSpotLight(in int i, in vec3 normal)');
+    Add('{');
+    Add('   float nDotVP;         // normal . light direction');
+    Add('   float nDotHV;         // normal . light half vector');
+    Add('   float pf;             // power factor');
+    Add('   float spotAttenuation;');
+    Add('   vec3  Ppli;');
+    Add('   vec3  Sdli;');
+    Add(' ');
+    Add('   nDotVP = max(0.0, dot(normal, normalize(vec3 (gl_LightSource[i].position))));');
+    Add('   nDotHV = max(0.0, dot(normal, vec3 (gl_LightSource[i].halfVector)));');
+    Add(' ');
+    Add('   Ppli = -normalize(vec3(gl_LightSource[i].position));');
+    Add('   Sdli = normalize(vec3(gl_LightSource[i].spotDirection));');
+    Add(' ');
+    Add('   spotAttenuation = pow(dot(Ppli, Sdli), gl_LightSource[i].spotExponent);');
+    Add('   if (nDotVP == 0.0)');
+    Add('   {');
+    Add('       pf = 0.0;');
+    Add('   }');
+    Add('   else');
+    Add('   {');
+    Add('       pf = pow(nDotHV, gl_FrontMaterial.shininess);');
+    Add(' ');
+    Add('   }');
+    Add('   Ambient  += gl_LightSource[i].ambient * spotAttenuation;');
+    Add('   Diffuse  += gl_LightSource[i].diffuse * nDotVP * spotAttenuation;');
+    Add('   Specular += gl_LightSource[i].specular * pf * spotAttenuation;');
+    Add('}');
+  end;
+end;
+
+procedure GetMLFragmentProgramCodeMid(const Code: TStrings;
+  const CurrentLight: Integer; AStyle: TGLLightStyle);
+begin
+  with Code do
+  begin
+    case AStyle of
+      lsOmni: Add(Format('  pointLight(%d, N, eye, Pos); ', [CurrentLight]));
+      lsSpot: Add(Format('  spotLight(%d, N, eye, Pos); ', [CurrentLight]));
+      lsParallel: Add(Format('  directionalLight(%d, N); ', [CurrentLight]));
+      lsParallelSpot: Add(Format('  infiniteSpotLight(%d, N); ', [CurrentLight]));
+    end;
+  end;
+end;
+
+procedure GetFragmentProgramCode(const Code: TStrings;
+  const ARealisticSpecular: Boolean; const AFogSupport: Boolean;
+  const aRci: TGLRenderContextInfo);
+var
+  scene: TGLScene;
+begin
+  with Code do
+  begin
+    Clear;
+    Add('uniform float LightIntensity; ');
+    Add('uniform sampler2D MainTexture; ');
+    Add(' ');
+    Add('varying vec3 Normal; ');
+    Add('varying vec4 Position; ');
+
+    if AFogSupport then
+    begin
+      Add('varying float fogFactor; ');
+    end;
+
+    Add('vec4 Ambient;');
+    Add('vec4 Diffuse;');
+    Add('vec4 Specular;');
+
+    AddLightSub(Code);
+
+    Add('void main(void) ');
+    Add('{ ');
+    Add('  vec4 TextureContrib = texture2D(MainTexture, gl_TexCoord[0].xy); ');
+    Add('  vec3 eye = vec3(0.0, 0.0, 1.0); ');
+    Add('  Diffuse = vec4(0.0); ');
+    Add('  Specular = vec4(0.0); ');
+    Add('  Ambient = vec4(0.0); ');
+    Add('  vec3 Pos = Position.xyz; ');
+    Add('  vec3 N = normalize(Normal); ');
+    scene := TGLScene(ARci.scene);
+    if (scene.Lights.Count > 0) then
+      GetMLFragmentProgramCodeMid(Code, 0,
+      TGLLightSource(scene.Lights[0]).LightStyle);
+
+    if ARealisticSpecular then
+      Add('  gl_FragColor = LightIntensity * (TextureContrib * (gl_FrontLightModelProduct.sceneColor + Ambient * gl_FrontMaterial.ambient + Diffuse * gl_FrontMaterial.diffuse) + Specular * gl_FrontMaterial.specular); ')
+    else
+      Add('  gl_FragColor = LightIntensity * TextureContrib * (gl_FrontLightModelProduct.sceneColor + Ambient * gl_FrontMaterial.ambient + Diffuse * gl_FrontMaterial.diffuse + Specular * gl_FrontMaterial.specular); ');
+
+    if AFogSupport then
+      Add('  gl_FragColor = mix(gl_Fog.color, gl_FragColor, fogFactor);');
+
+    Add('  gl_FragColor.a = TextureContrib.a; ');
+    Add('} ');
+  end;
+end;
+
+procedure GetMLFragmentProgramCodeBeg(const Code: TStrings;
+  const AFogSupport: Boolean);
+begin
+  with Code do
+  begin
+    Clear;
+    Add('uniform sampler2D MainTexture;');
+    Add('uniform float LightIntensity; ');
+    Add('uniform float SpecPower; ');
+    Add('varying vec3 Normal;');
+    Add('varying vec4 Position;');
+    if AFogSupport then
+    begin
+      Add('varying float fogFactor;');
+    end;
+    Add('vec4 Ambient;');
+    Add('vec4 Diffuse;');
+    Add('vec4 Specular;');
+    AddLightSub(Code);
+
+    Add('void main(void) ');
+    Add('{ ');
+    Add('  vec4 TextureContrib = texture2D(MainTexture, gl_TexCoord[0].st); ');
+    Add('  vec3 eye = vec3(0.0, 0.0, 1.0); ');
+    Add('  Diffuse = vec4(0.0); ');
+    Add('  Specular = vec4(0.0); ');
+    Add('  Ambient = vec4(0.0); ');
+    Add('  vec3 Pos = Position.xyz; ');
+    Add('  vec3 N = normalize(Normal); ');
+  end;
+end;
+
+procedure GetMLFragmentProgramCodeEnd(const Code: TStrings;
+  const ARealisticSpecular: Boolean;
+  AFogSupport: Boolean);
+begin
+  with Code do
+  begin
+    if ARealisticSpecular then
+      Add('  gl_FragColor = LightIntensity * (TextureContrib * (gl_FrontLightModelProduct.sceneColor + Ambient * gl_FrontMaterial.ambient + Diffuse * gl_FrontMaterial.diffuse) + Specular * gl_FrontMaterial.specular); ')
+    else
+      Add('  gl_FragColor = LightIntensity * TextureContrib * (gl_FrontLightModelProduct.sceneColor + Ambient * gl_FrontMaterial.ambient + Diffuse * gl_FrontMaterial.diffuse + Specular * gl_FrontMaterial.specular); ');
+
+    if AFogSupport then
+      Add('  gl_FragColor = mix(gl_Fog.color, gl_FragColor, fogFactor);');
+
+    Add('  gl_FragColor.a = TextureContrib.a; ');
+    Add('} ');
+  end;
+end;
+
+//-----------------------------------
+// TGLBaseCustomGLSLDiffuseSpecular
+//-----------------------------------
+
+constructor TGLBaseCustomGLSLDiffuseSpecular.Create(
+  AOwner: TComponent);
+begin
+  inherited;
+
+  FLightPower     := 1;
+  FFogSupport := sfsAuto;
+  TStringList(VertexProgram.Code).OnChange := nil;
+  TStringList(FragmentProgram.Code).OnChange := nil;
+  VertexProgram.Enabled := true;
+  FragmentProgram.Enabled := true;
+end;
+
+procedure TGLBaseCustomGLSLDiffuseSpecular.DoApply(
+  var rci: TGLRenderContextInfo; Sender: TObject);
+begin
+  GetGLSLProg.UseProgramObject;
+  Param['LightIntensity'].AsVector1f := FLightPower;
+end;
+
+function TGLBaseCustomGLSLDiffuseSpecular.DoUnApply(
+  var rci: TGLRenderContextInfo): Boolean;
+begin
+  Result := False;
+  GetGLSLProg.EndUseProgramObject;
+end;
+
+procedure TGLBaseCustomGLSLDiffuseSpecular.SetFogSupport(
+  const Value: TGLShaderFogSupport);
+begin
+  if FFogSupport <> Value then
+  begin
+    FFogSupport := Value;
+    Self.FinalizeShader;
+  end;
+end;
+
+procedure TGLBaseCustomGLSLDiffuseSpecular.SetRealisticSpecular(
+  const Value: Boolean);
+begin
+  if FRealisticSpecular <> Value then
+  begin
+    FRealisticSpecular := Value;
+    Self.FinalizeShader;
+  end;
+end;
+
+//-----------------------------------
+// TGLBaseGLSLDiffuseSpecularShaderMT
+//-----------------------------------
+
+procedure TGLBaseGLSLDiffuseSpecularShaderMT.DoApply(
+  var rci: TGLRenderContextInfo; Sender: TObject);
+begin
+  inherited;
+  Param['MainTexture'].AsTexture2D[0] := FMainTexture;
+end;
+
+function TGLBaseGLSLDiffuseSpecularShaderMT.GetMainTextureName: TGLLibMaterialName;
+begin
+  Result := FMaterialLibrary.GetNameOfTexture(FMainTexture);
+end;
+
+function TGLBaseGLSLDiffuseSpecularShaderMT.GetMaterialLibrary: TGLAbstractMaterialLibrary;
+begin
+  Result := FMaterialLibrary;
+end;
+
+procedure TGLBaseGLSLDiffuseSpecularShaderMT.Notification(
+  AComponent: TComponent; Operation: TOperation);
+var
+  Index: Integer;
+begin
+  inherited;
+  if Operation = opRemove then
+    if AComponent = FMaterialLibrary then
+      if FMaterialLibrary <> nil then
+      begin
+        //need to nil the textures that were ownned by it
+        if FMainTexture <> nil then
+        begin
+          Index := FMaterialLibrary.Materials.GetTextureIndex(FMainTexture);
+          if Index <> -1 then
+            FMainTexture := nil;
+        end;
+        FMaterialLibrary := nil;
+      end;
+end;
+
+procedure TGLBaseGLSLDiffuseSpecularShaderMT.SetMainTextureName(
+  const Value: TGLLibMaterialName);
+begin
+  if FMaterialLibrary = nil then
+  begin
+    FMainTextureName := Value;
+    if not (csLoading in ComponentState) then
+      raise EGLSLDiffuseSpecularShaderException.Create(strErrorEx + strMatLibNotDefined);
+  end
+  else
+  begin
+    FMainTexture := FMaterialLibrary.TextureByName(Value);
+    FMainTextureName := '';
+  end;
+end;
+
+procedure TGLBaseGLSLDiffuseSpecularShaderMT.SetMaterialLibrary(
+  const Value: TGLMaterialLibrary);
+begin
+  if FMaterialLibrary <> nil then
+    FMaterialLibrary.RemoveFreeNotification(Self);
+  FMaterialLibrary := Value;
+
+  if FMaterialLibrary <> nil then
+  begin
+    FMaterialLibrary.FreeNotification(Self);
+
+    if FMainTextureName <> '' then
+      SetMainTextureName(FMainTextureName);
+  end
+  else
+    FMainTextureName := '';
+end;
+
+{ TGLCustomGLSLDiffuseSpecularShaderMT }
+
+procedure TGLCustomGLSLDiffuseSpecularShaderMT.DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject);
+begin
+  GetVertexProgramCode(VertexProgram.Code, IsFogEnabled(FFogSupport, rci), rci);
+  GetFragmentProgramCode(FragmentProgram.Code, FRealisticSpecular, IsFogEnabled(FFogSupport, rci), rci);
+  VertexProgram.Enabled := True;
+  FragmentProgram.Enabled := True;
+  inherited;
+end;
+
+{ TGLCustomGLSLDiffuseSpecularShader }
+
+procedure TGLCustomGLSLDiffuseSpecularShader.DoApply(
+  var rci: TGLRenderContextInfo; Sender: TObject);
+begin
+  inherited;
+  Param['MainTexture'].AsVector1i := 0;  // Use the current texture.
+end;
+
+procedure TGLCustomGLSLDiffuseSpecularShader.DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject);
+begin
+  GetVertexProgramCode(VertexProgram.Code, IsFogEnabled(FFogSupport, rci), rci);
+  GetFragmentProgramCode(FragmentProgram.Code, FRealisticSpecular, IsFogEnabled(FFogSupport, rci), rci);
+  VertexProgram.Enabled := True;
+  FragmentProgram.Enabled := True;
+  inherited;
+end;
+
+//-----------------------------------
+// TGLCustomGLSLMLDiffuseSpecularShader
+//-----------------------------------
+
+constructor TGLCustomGLSLMLDiffuseSpecularShader.Create(
+  AOwner: TComponent);
+begin
+  inherited;
+end;
+
+procedure TGLCustomGLSLMLDiffuseSpecularShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
+var
+  I: Integer;
+  scene: TGLScene;
+  needRecompile: Boolean;
+begin
+  scene := TGLScene(rci.scene);
+  needRecompile := False;
+  for I := 0 to scene.Lights.Count - 1 do
+  begin
+    if Assigned(scene.Lights[I]) then
+    begin
+      if FLightTrace[I].Enabled <> TGLLightSource(scene.Lights[I]).Shining then
+      begin
+        needRecompile := True;
+        break;
+      end;
+      if FLightTrace[I].Style <> TGLLightSource(scene.Lights[I]).LightStyle then
+      begin
+        needRecompile := True;
+        break;
+      end;
+    end
+    else
+      if FLightTrace[I].Enabled then
+      begin
+        needRecompile := True;
+        break;
+      end;
+  end;
+  if needRecompile then
+  begin
+    FinalizeShader;
+    InitializeShader(rci, Sender);
+  end;
+
+  inherited;
+  Param['MainTexture'].AsVector1i := 0;  // Use the current texture.
+end;
+
+procedure TGLCustomGLSLMLDiffuseSpecularShader.DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject);
+var
+  I: Integer;
+  scene: TGLScene;
+begin
+  GetVertexProgramCode(VertexProgram.Code, IsFogEnabled(FFogSupport, rci), rci);
+  with FragmentProgram.Code do
+  begin
+    GetMLFragmentProgramCodeBeg(FragmentProgram.Code, IsFogEnabled(FFogSupport, rci));
+
+    // Repeat for all lights.
+    scene := TGLScene(rci.scene);
+    for I := 0 to scene.Lights.Count - 1 do
+    begin
+      if Assigned(scene.Lights[I]) then
+      begin
+        FLightTrace[I].Enabled := TGLLightSource(scene.Lights[I]).Shining;
+        FLightTrace[I].Style := TGLLightSource(scene.Lights[I]).LightStyle;
+        if FLightTrace[I].Enabled then
+          GetMLFragmentProgramCodeMid(FragmentProgram.Code, I, FLightTrace[I].Style);
+      end
+      else
+        FLightTrace[I].Enabled := False;
+    end;
+
+    GetMLFragmentProgramCodeEnd(FragmentProgram.Code,
+      FRealisticSpecular, IsFogEnabled(FFogSupport, rci));
+  end;
+  VertexProgram.Enabled := True;
+  FragmentProgram.Enabled := True;
+  inherited DoInitialize(rci, Sender);
+end;
+
+//------------------------------------------
+// TGLCustomGLSLMLDiffuseSpecularShaderMT
+//------------------------------------------
+constructor TGLCustomGLSLMLDiffuseSpecularShaderMT.Create(
+  AOwner: TComponent);
+begin
+  inherited;
+end;
+
+procedure TGLCustomGLSLMLDiffuseSpecularShaderMT.DoApply(
+  var rci: TGLRenderContextInfo; Sender: TObject);
+var
+  I: Integer;
+  scene: TGLScene;
+  needRecompile: Boolean;
+begin
+  scene := TGLScene(rci.scene);
+  needRecompile := False;
+  for I := 0 to scene.Lights.Count - 1 do
+  begin
+    if Assigned(scene.Lights[I]) then
+    begin
+      if FLightTrace[I].Enabled <> TGLLightSource(scene.Lights[I]).Shining then
+      begin
+        needRecompile := True;
+        break;
+      end;
+      if FLightTrace[I].Style <> TGLLightSource(scene.Lights[I]).LightStyle then
+      begin
+        needRecompile := True;
+        break;
+      end;
+    end
+    else
+      if FLightTrace[I].Enabled then
+      begin
+        needRecompile := True;
+        break;
+      end;
+  end;
+  if needRecompile then
+  begin
+    FinalizeShader;
+    InitializeShader(rci, Sender);
+  end;
+
+  inherited;
+end;
+
+procedure TGLCustomGLSLMLDiffuseSpecularShaderMT.DoInitialize(var rci: TGLRenderContextInfo; Sender: TObject);
+var
+  I: Integer;
+  scene: TGLScene;
+begin
+  GetVertexProgramCode(VertexProgram.Code, IsFogEnabled(FFogSupport, rci), rci);
+  with FragmentProgram.Code do
+  begin
+    GetMLFragmentProgramCodeBeg(FragmentProgram.Code, IsFogEnabled(FFogSupport, rci));
+
+    // Repeat for all lights.
+    scene := TGLScene(rci.scene);
+    for I := 0 to scene.Lights.Count - 1 do
+    begin
+      if Assigned(scene.Lights[I]) then
+      begin
+        FLightTrace[I].Enabled := TGLLightSource(scene.Lights[I]).Shining;
+        FLightTrace[I].Style := TGLLightSource(scene.Lights[I]).LightStyle;
+        if FLightTrace[I].Enabled then
+          GetMLFragmentProgramCodeMid(FragmentProgram.Code, I, FLightTrace[I].Style);
+      end
+      else
+        FLightTrace[I].Enabled := False;
+    end;
+
+    GetMLFragmentProgramCodeEnd(FragmentProgram.Code,
+      FRealisticSpecular, IsFogEnabled(FFogSupport, rci));
+  end;
+  VertexProgram.Enabled := True;
+  FragmentProgram.Enabled := True;
+  inherited;
+end;
+
+initialization
+  RegisterClasses([
+                  TGLCustomGLSLDiffuseSpecularShader,
+                  TGLCustomGLSLDiffuseSpecularShaderMT,
+                  TGLCustomGLSLMLDiffuseSpecularShader,
+                  TGLCustomGLSLMLDiffuseSpecularShaderMT,
+
+                  TGLSLDiffuseSpecularShader,
+                  TGLSLDiffuseSpecularShaderMT,
+                  TGLSLMLDiffuseSpecularShader,
+                  TGLSLMLDiffuseSpecularShaderMT
+                  ]);
+
+end.
+

+ 3 - 3
Source/GLS.ShaderPhong.pas → Source/GLSL.PhongShader.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.ShaderPhong;
+unit GLSL.PhongShader;
 
 (*  An ARBvp1.0 + ARBfp1.0 shader that implements phong shading. *)
 
@@ -22,9 +22,9 @@ uses
   Scene.VectorLists,
   OpenGLTokens,
   GLContext,
-  GLS.ShaderAsm,
+  GLSL.AsmShader,
   GLRenderContextInfo,
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLState;
 
 type

+ 492 - 0
Source/GLSL.PostEffects.pas

@@ -0,0 +1,492 @@
+//
+// This unit is part of the GLScene Engine, http://glscene.org
+//
+
+unit GLSL.PostEffects;
+
+(* A collection of components that generate post effects *)
+
+interface
+
+{$I GLScene.inc}
+
+uses
+  Winapi.OpenGL,
+  System.Classes,
+  System.SysUtils,
+
+  OpenGLTokens,
+  GLScene,
+  GLState,
+  GLContext,
+  Scene.PersistentClasses,
+  GLTexture,
+  GLGraphics,
+  Scene.Strings,
+  GLSL.CustomShader,
+  Scene.VectorGeometry,
+  GLRenderContextInfo,
+  GLMaterial,
+  GLTextureFormat;
+
+type
+  EGLPostShaderHolderException = class(Exception);
+  TGLPostShaderHolder = class;
+
+  TGLPostShaderCollectionItem = class(TCollectionItem)
+  private
+    FShader: TGLShader;
+    FPostShaderInterface: IGLPostShader;
+    procedure SetShader(const Value: TGLShader);
+  protected
+    function GetRealOwner: TGLPostShaderHolder;
+    function GetDisplayName: string; override;
+  public
+    procedure Assign(Source: TPersistent); override;
+  published
+    property Shader: TGLShader read FShader write SetShader;
+  end;
+
+  TGLPostShaderCollection = class(TOwnedCollection)
+  private
+    function GetItems(const Index: Integer): TGLPostShaderCollectionItem;
+    procedure SetItems(const Index: Integer;
+      const Value: TGLPostShaderCollectionItem);
+  public
+    procedure Remove(const Item: TGLShader);
+    function Add: TGLPostShaderCollectionItem;
+
+    property Items[const Index: Integer]: TGLPostShaderCollectionItem
+      read GetItems write SetItems; default;
+  end;
+
+  (* A class that allows several post-shaders to be applied to the scene,
+    one after another. It does not provide any optimizations related to
+    multi-shader rendering, just a convenient interface. *)
+  TGLPostShaderHolder = class(TGLBaseSCeneObject)
+  private
+    FShaders: TGLPostShaderCollection;
+    FTempTexture: TGLTextureHandle;
+    FPreviousViewportSize: TGLSize;
+    FTempTextureTarget: TGLTextureTarget;
+    procedure SetShaders(const Value: TGLPostShaderCollection);
+  protected
+    procedure Notification(AComponent: TComponent;
+      Operation: TOperation); override;
+  public
+    constructor Create(Owner: TComponent); override;
+    destructor Destroy; override;
+    procedure Assign(Source: TPersistent); override;
+    procedure DoRender(var rci: TGLRenderContextInfo;
+      renderSelf, renderChildren: Boolean); override;
+  published
+    property TempTextureTarget: TGLTextureTarget read FTempTextureTarget
+      write FTempTextureTarget default ttTexture2d;
+    property Shaders: TGLPostShaderCollection read FShaders write SetShaders;
+    // Publish some stuff from TGLBaseSceneObject.
+    property Visible;
+    property OnProgress;
+  end;
+
+  TGLPostEffectColor = record
+    R, G, B, A: Byte;
+  end;
+
+  TGLPostEffectBuffer = array of TGLPostEffectColor;
+
+  TGLOnCustomPostEffectEvent = procedure(Sender: TObject;
+    var rci: TGLRenderContextInfo; var Buffer: TGLPostEffectBuffer) of object;
+
+  (* Some presets for TGLPostEffect:
+    pepNone - does nothing.
+    pepGray - makes picture gray.
+    pepNegative - inverts all colors.
+    pepDistort - simulates shaky TV image.
+    pepNoise - just adds random niose.
+    pepNightVision - simulates nightvision goggles.
+    pepBlur - blurs the scene.
+    pepCustom - calls the OnCustomEffect event. *)
+  TGLPostEffectPreset = (pepNone, pepGray, pepNegative, pepDistort, pepNoise,
+    pepNightVision, pepBlur, pepCustom);
+
+  (* Provides a simple way to producing post-effects without shaders.
+    It is slow as hell, but it's worth it in some cases. *)
+  TGLPostEffect = class(TGLBaseSCeneObject)
+  private
+    FOnCustomEffect: TGLOnCustomPostEffectEvent;
+    FPreset: TGLPostEffectPreset;
+    FRenderBuffer: TGLPostEffectBuffer;
+  protected
+    // May be should be private...
+    procedure MakeGrayEffect; virtual;
+    procedure MakeNegativeEffect; virtual;
+    procedure MakeDistortEffect; virtual;
+    procedure MakeNoiseEffect; virtual;
+    procedure MakeNightVisionEffect; virtual;
+    procedure MakeBlurEffect(var rci: TGLRenderContextInfo); virtual;
+    procedure DoOnCustomEffect(var rci: TGLRenderContextInfo;
+      var Buffer: TGLPostEffectBuffer); virtual;
+  public
+    procedure DoRender(var rci: TGLRenderContextInfo;
+      renderSelf, renderChildren: Boolean); override;
+    procedure Assign(Source: TPersistent); override;
+  published
+    property Preset: TGLPostEffectPreset read FPreset write FPreset
+      default pepNone;
+    // User creates this effect.
+    property OnCustomEffect: TGLOnCustomPostEffectEvent read FOnCustomEffect
+      write FOnCustomEffect;
+    // Publish some stuff from TGLBaseSCeneObject.
+    property Visible;
+    property OnProgress;
+  end;
+
+  // -------------------------------------------------------------------------
+implementation
+
+// -------------------------------------------------------------------------
+
+{ TGLPostEffect }
+
+procedure TGLPostEffect.Assign(Source: TPersistent);
+begin
+  inherited;
+  if Source is TGLPostEffect then
+  begin
+    FPreset := TGLPostEffect(Source).FPreset;
+  end;
+end;
+
+procedure TGLPostEffect.DoOnCustomEffect(var rci: TGLRenderContextInfo;
+  var Buffer: TGLPostEffectBuffer);
+begin
+  if Assigned(FOnCustomEffect) then
+    FOnCustomEffect(Self, rci, Buffer);
+end;
+
+procedure TGLPostEffect.DoRender(var rci: TGLRenderContextInfo;
+  renderSelf, renderChildren: Boolean);
+var
+  NewScreenSize: Integer;
+begin
+  if (not rci.ignoreMaterials) and (FPreset <> pepNone) and
+    (rci.drawState <> dsPicking) then
+  begin
+    NewScreenSize := rci.viewPortSize.cx * rci.viewPortSize.cy;
+    if NewScreenSize <> Length(FRenderBuffer) then
+      SetLength(FRenderBuffer, NewScreenSize);
+
+    gl.ReadPixels(0, 0, rci.viewPortSize.cx, rci.viewPortSize.cy, GL_RGBA,
+      GL_UNSIGNED_BYTE, FRenderBuffer);
+    case FPreset of
+      // pepNone is handled in the first line.
+      pepGray: MakeGrayEffect;
+      pepNegative: MakeNegativeEffect;
+      pepDistort: MakeDistortEffect;
+      pepNoise: MakeNoiseEffect;
+      pepNightVision: MakeNightVisionEffect;
+      pepBlur: MakeBlurEffect(rci);
+      pepCustom: DoOnCustomEffect(rci, FRenderBuffer);
+    else
+      Assert(False, strErrorEx + strUnknownType);
+    end;
+    gl.DrawPixels(rci.viewPortSize.cx, rci.viewPortSize.cy, GL_RGBA,
+      GL_UNSIGNED_BYTE, FRenderBuffer);
+  end;
+
+  // Start rendering children (if any).
+  if renderChildren then
+    Self.renderChildren(0, Count - 1, rci);
+end;
+
+procedure TGLPostEffect.MakeGrayEffect;
+var
+  I: Longword;
+  gray: Byte;
+begin
+  for I := 0 to High(FRenderBuffer) do
+  begin
+    gray := Round((0.30 * FRenderBuffer[I].R) + (0.59 * FRenderBuffer[I].G) +
+      (0.11 * FRenderBuffer[I].B));
+    FRenderBuffer[I].R := gray;
+    FRenderBuffer[I].G := gray;
+    FRenderBuffer[I].B := gray;
+  end;
+end;
+
+procedure TGLPostEffect.MakeNegativeEffect;
+var
+  I: Longword;
+begin
+  for I := 0 to High(FRenderBuffer) do
+  begin
+    FRenderBuffer[I].R := 255 - FRenderBuffer[I].R;
+    FRenderBuffer[I].G := 255 - FRenderBuffer[I].G;
+    FRenderBuffer[I].B := 255 - FRenderBuffer[I].B;
+  end;
+end;
+
+procedure TGLPostEffect.MakeDistortEffect;
+var
+  I: Integer;
+  lMaxLength: Integer;
+  lNewIndex: Integer;
+begin
+  lMaxLength := High(FRenderBuffer);
+
+  for I := 0 to lMaxLength do
+  begin
+    lNewIndex := MaxInteger(0, MinInteger(lMaxLength, I + Random(10) - 5));
+    FRenderBuffer[I].R := FRenderBuffer[lNewIndex].R;
+    FRenderBuffer[I].G := FRenderBuffer[lNewIndex].G;
+    FRenderBuffer[I].B := FRenderBuffer[lNewIndex].B;
+  end;
+end;
+
+procedure TGLPostEffect.MakeNoiseEffect;
+var
+  I: Longword;
+  rnd: Single;
+begin
+  for I := 0 to High(FRenderBuffer) do
+  begin
+    rnd := 0.25 + Random(75) / 100;
+
+    FRenderBuffer[I].R := Round(FRenderBuffer[I].R * rnd);
+    FRenderBuffer[I].G := Round(FRenderBuffer[I].G * rnd);
+    FRenderBuffer[I].B := Round(FRenderBuffer[I].B * rnd);
+  end;
+end;
+
+procedure TGLPostEffect.MakeNightVisionEffect;
+var
+  gray: Single;
+  I: Integer;
+  lNewIndex, lMaxLength: Integer;
+begin
+  lMaxLength := High(FRenderBuffer);
+
+  for I := 0 to lMaxLength do
+  begin
+    lNewIndex := MaxInteger(0, MinInteger(lMaxLength, I + Random(20) - 10));
+
+    gray := 60 + (0.30 * FRenderBuffer[lNewIndex].R) +
+      (0.59 * FRenderBuffer[lNewIndex].G) + (0.11 * FRenderBuffer[lNewIndex].B);
+
+    FRenderBuffer[I].R := Round(gray * 0.25);
+    FRenderBuffer[I].G := Round((gray + 4) * 0.6);
+    FRenderBuffer[I].B := Round((gray + 4) * 0.11);
+  end;
+end;
+
+procedure TGLPostEffect.MakeBlurEffect(var rci: TGLRenderContextInfo);
+const
+  lOffset: Integer = 2;
+var
+  I: Integer;
+  lUp: Integer;
+begin
+  lUp := rci.viewPortSize.cx * lOffset;
+  for I := lUp to High(FRenderBuffer) - lUp do
+  begin
+    FRenderBuffer[I].R := (FRenderBuffer[I].R + FRenderBuffer[I - lOffset].R +
+      FRenderBuffer[I + lOffset].R + FRenderBuffer[I - lUp].R + FRenderBuffer
+      [I + lUp].R) div 5;
+    FRenderBuffer[I].G := (FRenderBuffer[I].G + FRenderBuffer[I - lOffset].G +
+      FRenderBuffer[I + lOffset].G + FRenderBuffer[I - lUp].G + FRenderBuffer
+      [I + lUp].R) div 5;
+    FRenderBuffer[I].B := (FRenderBuffer[I].B + FRenderBuffer[I - lOffset].B +
+      FRenderBuffer[I + lOffset].B + FRenderBuffer[I - lUp].G + FRenderBuffer
+      [I + lUp].R) div 5;
+  end;
+end;
+
+{ TGLPostShaderCollectionItem }
+
+procedure TGLPostShaderCollectionItem.Assign(Source: TPersistent);
+begin
+  if Source is TGLPostShaderCollectionItem then
+  begin
+    SetShader(TGLPostShaderCollectionItem(Source).FShader);
+  end
+  else
+    inherited; // Die!!!
+end;
+
+function TGLPostShaderCollectionItem.GetDisplayName: string;
+begin
+  if FShader = nil then
+    Result := ''
+  else
+  begin
+    if FShader.Name <> '' then
+      Result := FShader.Name
+    else
+      Result := FShader.ClassName;
+  end;
+end;
+
+type
+  // Required for Delphi5 compatibility.
+  THackCollection = class(TOwnedCollection)
+  end;
+
+function TGLPostShaderCollectionItem.GetRealOwner: TGLPostShaderHolder;
+begin
+  if Collection = nil then
+    Result := nil
+  else
+    Result := TGLPostShaderHolder(THackCollection(Collection).GetOwner);
+end;
+
+procedure TGLPostShaderCollectionItem.SetShader(const Value: TGLShader);
+var
+  RealOwner: TGLPostShaderHolder;
+begin
+  if FShader = Value then
+    Exit;
+  RealOwner := GetRealOwner;
+
+  if FShader <> nil then
+    FShader.RemoveFreeNotification(RealOwner);
+
+  if not Supports(TObject(Value), IGLPostShader, FPostShaderInterface) then
+    raise EGLPostShaderHolderException.Create
+      ('Shader must support interface IGLPostShader!');
+
+  if RealOwner <> nil then
+    if FPostShaderInterface.GetTextureTarget <> RealOwner.TempTextureTarget then
+      raise EGLPostShaderHolderException.Create
+        (strErrorEx + 'TextureTarget is not compatible!');
+  // If RealOwner = nil, we ignore this case and hope it will turn out ok...
+
+  FShader := Value;
+
+  if FShader <> nil then
+    if RealOwner <> nil then
+      FShader.FreeNotification(RealOwner);
+end;
+
+//------------------------------
+// TGLPostShaderHolder
+//------------------------------
+
+procedure TGLPostShaderHolder.Assign(Source: TPersistent);
+begin
+  if Source is TGLPostShaderHolder then
+  begin
+    FShaders.Assign(TGLPostShaderHolder(Source).FShaders);
+    FTempTextureTarget := TGLPostShaderHolder(Source).FTempTextureTarget;
+  end;
+  inherited;
+end;
+
+constructor TGLPostShaderHolder.Create(Owner: TComponent);
+begin
+  inherited;
+  FTempTexture := TGLTextureHandle.Create;
+  FTempTextureTarget := ttTexture2d;
+  FShaders := TGLPostShaderCollection.Create(Self, TGLPostShaderCollectionItem);
+end;
+
+destructor TGLPostShaderHolder.Destroy;
+begin
+  FShaders.Destroy;
+  FTempTexture.Destroy;
+  inherited;
+end;
+
+procedure TGLPostShaderHolder.DoRender(var rci: TGLRenderContextInfo;
+  renderSelf, renderChildren: Boolean);
+var
+  I: Integer;
+begin
+  if not(rci.ignoreMaterials) and not(csDesigning in ComponentState) and
+    (rci.drawState <> dsPicking) then
+  begin
+    if (FPreviousViewportSize.cx <> rci.viewPortSize.cx) or
+      (FPreviousViewportSize.cy <> rci.viewPortSize.cy) then
+    begin
+      InitTexture(FTempTexture.Handle, rci.viewPortSize, FTempTextureTarget);
+      FPreviousViewportSize := rci.viewPortSize;
+    end;
+
+    if FShaders.Count <> 0 then
+    begin
+      for I := 0 to FShaders.Count - 1 do
+      begin
+        Assert(Assigned(FShaders[I].FShader));
+        if FShaders[I].FShader.Enabled then
+        begin
+          rci.GLStates.ActiveTextureEnabled[FTempTextureTarget] := True;
+          FShaders[I].FShader.Apply(rci, Self);
+          repeat
+            CopyScreenToTexture(rci.viewPortSize,
+              DecodeTextureTarget(FTempTextureTarget));
+            FShaders[I].FPostShaderInterface.DoUseTempTexture(FTempTexture,
+              FTempTextureTarget);
+            DrawTexturedScreenQuad5(rci.viewPortSize);
+          until not FShaders[I].FShader.UnApply(rci);
+          rci.GLStates.ActiveTextureEnabled[FTempTextureTarget] := False;
+        end;
+      end;
+    end;
+  end;
+  if renderChildren then
+    Self.renderChildren(0, Count - 1, rci);
+end;
+
+procedure TGLPostShaderHolder.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited;
+  if Operation = opRemove then
+  begin
+    if AComponent is TGLShader then
+      FShaders.Remove(TGLShader(AComponent));
+  end;
+end;
+
+procedure TGLPostShaderHolder.SetShaders(const Value: TGLPostShaderCollection);
+begin
+  FShaders.Assign(Value);
+end;
+
+{ TGLPostShaderCollection }
+
+function TGLPostShaderCollection.Add: TGLPostShaderCollectionItem;
+begin
+  Result := TGLPostShaderCollectionItem(inherited Add);
+end;
+
+function TGLPostShaderCollection.GetItems(const Index: Integer)
+  : TGLPostShaderCollectionItem;
+begin
+  Result := TGLPostShaderCollectionItem(GetItem(Index));
+end;
+
+procedure TGLPostShaderCollection.Remove(const Item: TGLShader);
+var
+  I: Integer;
+begin
+  if Count <> 0 then
+    for I := Count - 1 downto 0 do
+      if GetItems(I).FShader = Item then
+        Delete(I);
+  // Don't exit because the same shader might be applied more than once.
+end;
+
+procedure TGLPostShaderCollection.SetItems(const Index: Integer;
+  const Value: TGLPostShaderCollectionItem);
+begin
+  GetItems(Index).Assign(Value);
+end;
+
+// ------------------------------------------------
+initialization
+// ------------------------------------------------
+
+RegisterClasses([TGLPostEffect, TGLPostShaderHolder, TGLPostShaderCollection,
+  TGLPostShaderCollectionItem]);
+
+end.

+ 17 - 7
Source/GLSL.ShaderPosts.pas → Source/GLSL.PostShaders.pas

@@ -2,9 +2,19 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLSL.ShaderPosts;
-
-(* Post shaders that simulate shader visions for a mask or the entire scene. *)
+unit GLSL.PostShaders;
+
+(*
+  Post shaders that simulate shader visions for a mask or the entire scene:
+    - TLSLPostBlurShader;
+    - TGLSLPostThermalVisionShader;
+    - TGLSLPostDreamVisionShader;
+    - TGLSLPostNightVisionShader;
+    - TGLSLPostPixelateShader;
+    - TGLSLPostPosterizeShader
+    - TGLSLPostFrostShader;
+    - TGLSLPostTroubleShader;
+*)
 
 interface
 
@@ -12,18 +22,18 @@ interface
 
 uses
   System.Classes,
-  
+
   OpenGLTokens,
   GLTexture,
   GLScene,
   GLState,
   Scene.VectorGeometry,
+  GLRenderContextInfo,
+  GLTextureFormat,
   GLContext,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom,
-  GLRenderContextInfo,
-  GLTextureFormat,
+  GLSL.CustomShader,
   Scene.VectorTypes;
 
 type

+ 5 - 5
Source/GLSL.Shader.pas

@@ -21,7 +21,7 @@ uses
   Scene.VectorTypes,
   GLTexture,
   GLContext,
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLRenderContextInfo,
   GLTextureFormat,
   GLSL.ShaderParameter,
@@ -97,7 +97,7 @@ type
     property TransformFeedBackMode: TGLTransformFeedBackMode read FTransformFeedBackMode write SetTransformFeedBackMode default tfbmInterleaved;
   end;
 
-  {Wrapper around a parameter of a GLSL program. }
+  // Wrapper around a parameter of a GLSL program.
   TGLSLShaderParameter = class(TGLCustomShaderParameter)
   private
     FGLSLProg: TGLProgramHandle;
@@ -163,7 +163,9 @@ type
 implementation
 //------------------------------------------------------------------------
 
-{ TGLCustomGLSLShader }
+//----------------------------------
+// TGLCustomGLSLShader
+//----------------------------------
 
 procedure TGLCustomGLSLShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
 begin
@@ -274,7 +276,6 @@ begin
   end;
 end;
 
-
 function TGLCustomGLSLShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
 begin
   Result := False;
@@ -284,7 +285,6 @@ begin
     FGLSLProg.EndUseProgramObject;
 end;
 
-
 function TGLCustomGLSLShader.ShaderSupported: Boolean;
 begin
   Result := (GL.ARB_shader_objects and GL.ARB_vertex_program and

+ 2 - 2
Source/GLSL.ShaderDiffuseSpecular.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLSL.ShaderDiffuseSpecular;
+unit GLSL.DiffuseSpecularShader;
 
 (*
    This is a collection of GLSL diffuse-specular shaders
@@ -35,8 +35,8 @@ uses
   Scene.PersistentClasses,
   Scene.VectorGeometry,
   Scene.Strings,
-  GLS.ShaderCustom,
   GLSL.Shader,
+  GLSL.CustomShader,
   GLColor,
   GLRenderContextInfo,
   GLMaterial;

+ 1 - 1
Source/GLSL.ShaderErosion.pas

@@ -30,7 +30,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 (* Custom class for GLSLSimpleErosionShader.
  A shader that Erode surface object *)

+ 1 - 1
Source/GLSL.ShaderFur.pas

@@ -32,7 +32,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 type
   TGLCustomGLSLFurShader = class(TGLCustomGLSLShader)

+ 1 - 1
Source/GLSL.ShaderGlass.pas

@@ -33,7 +33,7 @@ uses
   Scene.PersistentClasses,
   GLGraphics,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 (* Custom class for GLSLGlassShader.
   Glass shader : Environment mapping and refraction mapping using the fresnel terms *)

+ 1 - 1
Source/GLSL.ShaderGooch.pas

@@ -35,7 +35,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 // Custom class for GLSLSimpleGoochShader.
 type

+ 1 - 1
Source/GLSL.ShaderIvory.pas

@@ -29,7 +29,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 (* Custom class for GLSLIvoryShader.
  A shader that simulate Ivory Material *)

+ 1 - 1
Source/GLSL.ShaderLattice.pas

@@ -29,7 +29,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 (* Custom class for GLSLSimpleLatticeShader.
  A shader that simulate Lattice *)

+ 1 - 1
Source/GLSL.ShaderSem.pas

@@ -35,7 +35,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 Type
 

+ 1 - 1
Source/GLSL.ShaderToon.pas

@@ -29,7 +29,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 // Custom class for GLSL.ShaderToon.
 type

+ 1 - 1
Source/GLSL.ShaderVertexDisplacement.pas

@@ -36,7 +36,7 @@ uses
   GLTexture,
   GLMaterial,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 type
   (* Custom class for GLSLVertexDisplacementShader.

+ 1 - 1
Source/GLS.CrossXML.pas → Source/Scene.CrossXML.pas

@@ -2,7 +2,7 @@
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 
-unit GLS.CrossXML;
+unit Scene.CrossXML;
 
 (* Cross XML routines *)