Browse Source

Combined GLSL.ShaderBump & GLSL.ShaderBumps units

GLScene 5 years ago
parent
commit
2bad7ab57e
74 changed files with 11588 additions and 9818 deletions
  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 "GLFileMD2"
 #pragma link "GLFile3DS"
 #pragma link "GLFile3DS"
 
 
-#pragma link "GLS.cgBombShader"
+#pragma link "GLSL.cgBombShader"
 
 
 #pragma resource "*.dfm"
 #pragma resource "*.dfm"
 TForm1 *Form1;
 TForm1 *Form1;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -13,7 +13,7 @@
 #include "GLCadencer.hpp"
 #include "GLCadencer.hpp"
 #include "GLCoordinates.hpp"
 #include "GLCoordinates.hpp"
 #include "GLCrossPlatform.hpp"
 #include "GLCrossPlatform.hpp"
-#include "GLS.ShaderCustom.hpp"
+#include "GLSL.CustomShader.hpp"
 #include "GLGeomObjects.hpp"
 #include "GLGeomObjects.hpp"
 #include "GLGraph.hpp"
 #include "GLGraph.hpp"
 #include "GLMaterial.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)
 void __fastcall TForm1::GLUserShader1DoApply(TObject *Sender, TGLRenderContextInfo &rci)
 
 
 {
 {
-  Scene.VectorGeometry::TVector camPos;
+  TVector camPos;
 
 
   programObject = new TGLProgramHandle();
   programObject = new TGLProgramHandle();
   programObject->UseProgramObject();
   programObject->UseProgramObject();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 1 - 1
Packages/GLScene_Cg_DT.dpk

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

+ 1 - 1
Packages/GLScene_Cg_DT.dproj

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

+ 3 - 3
Packages/GLScene_Cg_RT.dpk

@@ -38,8 +38,8 @@ requires
 contains
 contains
   Import.cgGL in '..\Source\Import.cgGL.pas',
   Import.cgGL in '..\Source\Import.cgGL.pas',
   Import.cg in '..\Source\Import.cg.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.
 end.

+ 3 - 3
Packages/GLScene_Cg_RT.dproj

@@ -134,9 +134,9 @@
         <DCCReference Include="GLScene_RT.dcp"/>
         <DCCReference Include="GLScene_RT.dcp"/>
         <DCCReference Include="..\Source\Import.cgGL.pas"/>
         <DCCReference Include="..\Source\Import.cgGL.pas"/>
         <DCCReference Include="..\Source\Import.cg.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">
         <BuildConfiguration Include="Debug">
             <Key>Cfg_2</Key>
             <Key>Cfg_2</Key>
             <CfgParent>Base</CfgParent>
             <CfgParent>Base</CfgParent>

+ 3 - 2
Packages/GLScene_DT.dpk

@@ -56,10 +56,11 @@ contains
   FPlugInManagerEditor in '..\Source\FPlugInManagerEditor.pas' {GLPlugInManagerEditorForm},
   FPlugInManagerEditor in '..\Source\FPlugInManagerEditor.pas' {GLPlugInManagerEditorForm},
   FXCollectionEditor in '..\Source\FXCollectionEditor.pas' {GLXCollectionEditorForm},
   FXCollectionEditor in '..\Source\FXCollectionEditor.pas' {GLXCollectionEditorForm},
   FInfo in '..\Source\FInfo.pas' {GLInfoForm},
   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.
 end.
 
 
 
 
 
 
+

+ 1 - 7
Packages/GLScene_DT.dproj

@@ -167,14 +167,8 @@
         <DCCReference Include="..\Source\FInfo.pas">
         <DCCReference Include="..\Source\FInfo.pas">
             <Form>GLInfoForm</Form>
             <Form>GLInfoForm</Form>
         </DCCReference>
         </DCCReference>
-        <DCCReference Include="..\Source\XCollectionRegister.pas"/>
         <DCCReference Include="..\Source\GLS.SceneRegister.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">
         <BuildConfiguration Include="Debug">
             <Key>Cfg_2</Key>
             <Key>Cfg_2</Key>
             <CfgParent>Base</CfgParent>
             <CfgParent>Base</CfgParent>

+ 13 - 14
Packages/GLScene_RT.dpk

@@ -47,16 +47,16 @@ contains
   FileQ3MD3 in '..\Source\FileQ3MD3.pas',
   FileQ3MD3 in '..\Source\FileQ3MD3.pas',
   FileB3D in '..\Source\FileB3D.pas',
   FileB3D in '..\Source\FileB3D.pas',
   FileGL2 in '..\Source\FileGL2.pas',
   FileGL2 in '..\Source\FileGL2.pas',
-  FileLWObjects in '..\Source\FileLWObjects.pas',
+  Formats.FileLWObjects in '..\Source\Formats.FileLWObjects.pas',
   FileMD2 in '..\Source\FileMD2.pas',
   FileMD2 in '..\Source\FileMD2.pas',
   FileMD3 in '..\Source\FileMD3.pas',
   FileMD3 in '..\Source\FileMD3.pas',
   FileO3TCImage in '..\Source\FileO3TCImage.pas',
   FileO3TCImage in '..\Source\FileO3TCImage.pas',
   FileOCT in '..\Source\FileOCT.pas',
   FileOCT in '..\Source\FileOCT.pas',
   FileTGA in '..\Source\FileTGA.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',
   FileVRMLParser in '..\Source\FileVRMLParser.pas',
-  GLAVIRecorder in '..\Source\GLAVIRecorder.pas',
+  GLS.AVIRecorder in '..\Source\GLS.AVIRecorder.pas',
   GLAnimatedSprite in '..\Source\GLAnimatedSprite.pas',
   GLAnimatedSprite in '..\Source\GLAnimatedSprite.pas',
   GLAnimationUtils in '..\Source\GLAnimationUtils.pas',
   GLAnimationUtils in '..\Source\GLAnimationUtils.pas',
   GLApplicationFileIO in '..\Source\GLApplicationFileIO.pas',
   GLApplicationFileIO in '..\Source\GLApplicationFileIO.pas',
@@ -152,7 +152,7 @@ contains
   GLImageUtils in '..\Source\GLImageUtils.pas',
   GLImageUtils in '..\Source\GLImageUtils.pas',
   GLImposter in '..\Source\GLImposter.pas',
   GLImposter in '..\Source\GLImposter.pas',
   GLIsolines in '..\Source\GLIsolines.pas',
   GLIsolines in '..\Source\GLIsolines.pas',
-  GLIsosurface in '..\Source\GLIsosurface.pas',
+  GLS.Isosurface in '..\Source\GLS.Isosurface.pas',
   GLJoystick in '..\Source\GLJoystick.pas',
   GLJoystick in '..\Source\GLJoystick.pas',
   GLKeyboard in '..\Source\GLKeyboard.pas',
   GLKeyboard in '..\Source\GLKeyboard.pas',
   GLLensFlare in '..\Source\GLLensFlare.pas',
   GLLensFlare in '..\Source\GLLensFlare.pas',
@@ -189,7 +189,7 @@ contains
   GLPolyhedron in '..\Source\GLPolyhedron.pas',
   GLPolyhedron in '..\Source\GLPolyhedron.pas',
   Scene.Polynomials in '..\Source\Scene.Polynomials.pas',
   Scene.Polynomials in '..\Source\Scene.Polynomials.pas',
   GLPortal in '..\Source\GLPortal.pas',
   GLPortal in '..\Source\GLPortal.pas',
-  GLPostEffects in '..\Source\GLPostEffects.pas',
+  GLSL.PostEffects in '..\Source\GLSL.PostEffects.pas',
   GLProcTextures in '..\Source\GLProcTextures.pas',
   GLProcTextures in '..\Source\GLProcTextures.pas',
   GLProjectedTextures in '..\Source\GLProjectedTextures.pas',
   GLProjectedTextures in '..\Source\GLProjectedTextures.pas',
   GLProxyObjects in '..\Source\GLProxyObjects.pas',
   GLProxyObjects in '..\Source\GLProxyObjects.pas',
@@ -198,20 +198,19 @@ contains
   GLS.RandomHDS in '..\Source\GLS.RandomHDS.pas',
   GLS.RandomHDS in '..\Source\GLS.RandomHDS.pas',
   GLRenderContextInfo in '..\Source\GLRenderContextInfo.pas',
   GLRenderContextInfo in '..\Source\GLRenderContextInfo.pas',
   GLS.ArchiveManager in '..\Source\GLS.ArchiveManager.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.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.ShaderCel in '..\Source\GLS.ShaderCel.pas',
   GLS.ShaderCombiner in '..\Source\GLS.ShaderCombiner.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.ShaderMultiMaterial in '..\Source\GLS.ShaderMultiMaterial.pas',
   GLS.ShaderOutline in '..\Source\GLS.ShaderOutline.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.ShaderTextureSharing in '..\Source\GLS.ShaderTextureSharing.pas',
   GLS.ShaderUser in '..\Source\GLS.ShaderUser.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.ShaderErosion in '..\Source\GLSL.ShaderErosion.pas',
   GLSL.ShaderFur in '..\Source\GLSL.ShaderFur.pas',
   GLSL.ShaderFur in '..\Source\GLSL.ShaderFur.pas',
   GLSL.ShaderGlass in '..\Source\GLSL.ShaderGlass.pas',
   GLSL.ShaderGlass in '..\Source\GLSL.ShaderGlass.pas',
@@ -219,7 +218,7 @@ contains
   GLSL.ShaderIvory in '..\Source\GLSL.ShaderIvory.pas',
   GLSL.ShaderIvory in '..\Source\GLSL.ShaderIvory.pas',
   GLSL.ShaderLattice in '..\Source\GLSL.ShaderLattice.pas',
   GLSL.ShaderLattice in '..\Source\GLSL.ShaderLattice.pas',
   GLSL.ShaderParameter in '..\Source\GLSL.ShaderParameter.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.ProjectedTextures in '..\Source\GLSL.ProjectedTextures.pas',
   GLSL.ShaderSem in '..\Source\GLSL.ShaderSem.pas',
   GLSL.ShaderSem in '..\Source\GLSL.ShaderSem.pas',
   GLSL.Shader in '..\Source\GLSL.Shader.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\FileQ3MD3.pas"/>
         <DCCReference Include="..\Source\FileB3D.pas"/>
         <DCCReference Include="..\Source\FileB3D.pas"/>
         <DCCReference Include="..\Source\FileGL2.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\FileMD2.pas"/>
         <DCCReference Include="..\Source\FileMD3.pas"/>
         <DCCReference Include="..\Source\FileMD3.pas"/>
         <DCCReference Include="..\Source\FileO3TCImage.pas"/>
         <DCCReference Include="..\Source\FileO3TCImage.pas"/>
         <DCCReference Include="..\Source\FileOCT.pas"/>
         <DCCReference Include="..\Source\FileOCT.pas"/>
         <DCCReference Include="..\Source\FileTGA.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\FileVRMLParser.pas"/>
-        <DCCReference Include="..\Source\GLAVIRecorder.pas"/>
+        <DCCReference Include="..\Source\GLS.AVIRecorder.pas"/>
         <DCCReference Include="..\Source\GLAnimatedSprite.pas"/>
         <DCCReference Include="..\Source\GLAnimatedSprite.pas"/>
         <DCCReference Include="..\Source\GLAnimationUtils.pas"/>
         <DCCReference Include="..\Source\GLAnimationUtils.pas"/>
         <DCCReference Include="..\Source\GLApplicationFileIO.pas"/>
         <DCCReference Include="..\Source\GLApplicationFileIO.pas"/>
@@ -255,7 +255,7 @@
         <DCCReference Include="..\Source\GLImageUtils.pas"/>
         <DCCReference Include="..\Source\GLImageUtils.pas"/>
         <DCCReference Include="..\Source\GLImposter.pas"/>
         <DCCReference Include="..\Source\GLImposter.pas"/>
         <DCCReference Include="..\Source\GLIsolines.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\GLJoystick.pas"/>
         <DCCReference Include="..\Source\GLKeyboard.pas"/>
         <DCCReference Include="..\Source\GLKeyboard.pas"/>
         <DCCReference Include="..\Source\GLLensFlare.pas"/>
         <DCCReference Include="..\Source\GLLensFlare.pas"/>
@@ -292,7 +292,7 @@
         <DCCReference Include="..\Source\GLPolyhedron.pas"/>
         <DCCReference Include="..\Source\GLPolyhedron.pas"/>
         <DCCReference Include="..\Source\Scene.Polynomials.pas"/>
         <DCCReference Include="..\Source\Scene.Polynomials.pas"/>
         <DCCReference Include="..\Source\GLPortal.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\GLProcTextures.pas"/>
         <DCCReference Include="..\Source\GLProjectedTextures.pas"/>
         <DCCReference Include="..\Source\GLProjectedTextures.pas"/>
         <DCCReference Include="..\Source\GLProxyObjects.pas"/>
         <DCCReference Include="..\Source\GLProxyObjects.pas"/>
@@ -301,20 +301,19 @@
         <DCCReference Include="..\Source\GLS.RandomHDS.pas"/>
         <DCCReference Include="..\Source\GLS.RandomHDS.pas"/>
         <DCCReference Include="..\Source\GLRenderContextInfo.pas"/>
         <DCCReference Include="..\Source\GLRenderContextInfo.pas"/>
         <DCCReference Include="..\Source\GLS.ArchiveManager.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.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.ShaderCel.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderCombiner.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.ShaderMultiMaterial.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderOutline.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.ShaderTextureSharing.pas"/>
         <DCCReference Include="..\Source\GLS.ShaderUser.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.ShaderErosion.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderFur.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderFur.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderGlass.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderGlass.pas"/>
@@ -322,7 +321,7 @@
         <DCCReference Include="..\Source\GLSL.ShaderIvory.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderIvory.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderLattice.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderLattice.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderParameter.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.ProjectedTextures.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderSem.pas"/>
         <DCCReference Include="..\Source\GLSL.ShaderSem.pas"/>
         <DCCReference Include="..\Source\GLSL.Shader.pas"/>
         <DCCReference Include="..\Source\GLSL.Shader.pas"/>

+ 0 - 1
Source/FileTGA.pas

@@ -280,7 +280,6 @@ end;
 initialization
 initialization
 //-------------------------------------------
 //-------------------------------------------
 
 
-  { Register this Fileformat-Handler with GLScene }
   RegisterRasterFormat('tga', 'TARGA Image File', TGLTGAImage);
   RegisterRasterFormat('tga', 'TARGA Image File', TGLTGAImage);
 
 
 end.
 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
 // 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) *)
 (* Simple X format support for Delphi (Microsoft's favorite format) *)
 
 

+ 1 - 1
Source/GLAVIRecorder.pas

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

+ 2 - 1
Source/GLBaseClasses.pas

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

+ 3 - 4
Source/GLCrossPlatform.pas

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

+ 1 - 1
Source/GLFileLWO.pas

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

+ 1 - 1
Source/GLFileX.pas

@@ -23,7 +23,7 @@ uses
   GLMaterial,
   GLMaterial,
 
 
   // Misc
   // Misc
-  FileX;
+  Formats.FileX;
 
 
 type
 type
   TGLXVectorFile = class(TGLVectorFile)
   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.Classes,
   System.SysUtils,
   System.SysUtils,
 
 
+  GLApplicationFileIO,
   Scene.PersistentClasses,
   Scene.PersistentClasses,
-  GLApplicationFileIO;
+  Scene.Strings;
 
 
 type
 type
 
 
@@ -187,9 +188,6 @@ function ArcFileStreamExists(const FileName: string): boolean;
 implementation
 implementation
 // ------------------------------------------------------------------
 // ------------------------------------------------------------------
 
 
-uses
-  Scene.Strings;
-
 var
 var
   vArchiveFileFormats: TGLArchiveFileFormatsList;
   vArchiveFileFormats: TGLArchiveFileFormatsList;
   vArchiveManager: TGLSArchiveManager;
   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}
 {$I GLScene.inc}
 
 
 // uncomment next line to memorize vertex Density value to further use
 // 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.VectorGeometry,
   Scene.VectorLists,
   Scene.VectorLists,
   GLMesh,
   GLMesh,
   GLVectorFileObjects,
   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.
 end.

+ 15 - 16
Source/GLS.SceneRegister.pas

@@ -293,7 +293,7 @@ uses
   GLAsyncHDS,
   GLAsyncHDS,
   GLAsyncTimer,
   GLAsyncTimer,
   GLAtmosphere,
   GLAtmosphere,
-  GLAVIRecorder,
+  GLS.AVIRecorder,
   GLBaseClasses,
   GLBaseClasses,
   GLBitmapFont,
   GLBitmapFont,
   GLBlur,
   GLBlur,
@@ -342,37 +342,36 @@ uses
   GLPerlinPFX,
   GLPerlinPFX,
   GLPolyhedron,
   GLPolyhedron,
   GLPortal,
   GLPortal,
-  GLPostEffects,
+  GLScreen,
+  GLScriptBase,
+  GLShadowHDS,
+  GLShadowPlane,
+  GLShadowVolume,
+  GLSimpleNavigation,
+  GLSkyBox,
+  GLSkydome,
   GLProjectedTextures,
   GLProjectedTextures,
   GLProxyObjects,
   GLProxyObjects,
   GLRenderContextInfo,
   GLRenderContextInfo,
   GLS.ArchiveManager,
   GLS.ArchiveManager,
   GLS.Language,
   GLS.Language,
   GLS.Memo,
   GLS.Memo,
-  GLS.ShaderAsm,
-  GLS.ShaderBump,
   GLS.ShaderCel,
   GLS.ShaderCel,
   GLS.ShaderHiddenLine,
   GLS.ShaderHiddenLine,
   GLS.ShaderCombiner,
   GLS.ShaderCombiner,
   GLS.ShaderMultiMaterial,
   GLS.ShaderMultiMaterial,
   GLS.ShaderOutline,
   GLS.ShaderOutline,
-  GLS.ShaderPhong,
   GLS.ShaderTexCombine,
   GLS.ShaderTexCombine,
   GLS.ShaderTextureSharing,
   GLS.ShaderTextureSharing,
   GLS.ShaderUser,
   GLS.ShaderUser,
   GLS.Utils,
   GLS.Utils,
-  GLScreen,
-  GLScriptBase,
-  GLShadowHDS,
-  GLShadowPlane,
-  GLShadowVolume,
-  GLSimpleNavigation,
-  GLSkyBox,
-  GLSkydome,
+  GLSL.AsmShader,
+  GLSL.PhongShader,
+  GLSL.PostEffects,
   GLSL.ProjectedTextures,
   GLSL.ProjectedTextures,
-  GLSL.ShaderBump,
-  GLSL.ShaderDiffuseSpecular,
-  GLSL.ShaderPosts,
+  GLSL.BumpShaders,
+  GLSL.DiffuseSpecularShader,
+  GLSL.PostShaders,
   GLSL.Shader,
   GLSL.Shader,
   GLSmoothNavigator,
   GLSmoothNavigator,
   GLState,
   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
      TODO: Add more modes here, including sctOneAPTwoAP, which should be the
            default one.
            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,
   TGLShaderCombinerType = (sctOneSPTwoAP, sctTwoSPOneAP,
                            sctOneMPTwoSP, sctTwoMPOneSP);
                            sctOneMPTwoSP, sctTwoMPOneSP);

+ 1 - 2
Source/GLS.Triangulation.pas

@@ -12,8 +12,7 @@ uses
   System.Classes,
   System.Classes,
   System.Types,
   System.Types,
   Vcl.Dialogs,
   Vcl.Dialogs,
-  Vcl.Graphics,
-  
+
   Scene.VectorGeometry;
   Scene.VectorGeometry;
 
 
 // Set these as applicable
 // 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
 // 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 
     TGLAsmShader is a wrapper for all ARB shaders 
     This component is only a template and has to be replaced with a
     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
 interface
@@ -23,7 +23,7 @@ uses
   Scene.VectorTypes,
   Scene.VectorTypes,
   GLTexture,
   GLTexture,
   GLContext,
   GLContext,
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLRenderContextInfo;
   GLRenderContextInfo;
 
 
 type
 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
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 //
 
 
-unit GLSL.ShaderBump;
+unit GLSL.BumpShaders;
 
 
 (*
 (*
    A GLSL shader that applies bump mapping.
    A GLSL shader that applies bump mapping.
@@ -31,22 +31,46 @@ interface
 {$I GLScene.inc}
 {$I GLScene.inc}
 
 
 uses
 uses
+  Winapi.OpenGL,
+  Winapi.OpenGLext,
+
   System.Classes,
   System.Classes,
   System.SysUtils,
   System.SysUtils,
+
+  OpenGLTokens,
+
+  Scene.VectorTypes,
+  Scene.VectorGeometry,
+  GLMaterial,
+  GLGraphics,
+  Scene.VectorLists,
+  GLColor,
+  GLRenderContextInfo,
+  GLState,
+  GLTextureFormat,
+
   GLTexture,
   GLTexture,
   GLScene,
   GLScene,
-  Scene.VectorGeometry,
-  Scene.VectorTypes,
+  GLContext,
   GLCadencer,
   GLCadencer,
   Scene.Strings,
   Scene.Strings,
-  OpenGLTokens,
   GLSL.Shader,
   GLSL.Shader,
-  GLS.ShaderCustom,
-  GLColor,
-  GLRenderContextInfo,
-  GLMaterial;
+  GLSL.CustomShader,
+  GLS.Utils;
 
 
 type
 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);
   EGLSLBumpShaderException = class(EGLSLShaderException);
 
 
   // An abstract class.
   // An abstract class.
@@ -187,14 +211,13 @@ type
   public
   public
     constructor Create(AOwner : TComponent); override;
     constructor Create(AOwner : TComponent); override;
     property LightSources: TGLLightSourceSet read FLightSources write SetLightSources default [1];
     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;
     property LightCompensation: Single read FLightCompensation write SetLightCompensation;
   end;
   end;
 
 
-                {************** Published **************}
-
-  // One light shaders.
+ {************** Published **************}
+   // One light shaders.
   TGLSLBumpShaderMT = class(TGLCustomGLSLBumpShaderMT)
   TGLSLBumpShaderMT = class(TGLCustomGLSLBumpShaderMT)
   published
   published
     property MainTextureName;
     property MainTextureName;
@@ -267,6 +290,78 @@ type
     property LightCompensation;
     property LightCompensation;
   end;
   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
 implementation
 //--------------------------------------------------------------
 //--------------------------------------------------------------
@@ -1090,9 +1185,747 @@ begin
   SetSpecularTexture(Textures[1]);
   SetSpecularTexture(Textures[1]);
 end;
 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
 initialization
+//-----------------------------------------------
+
   RegisterClasses([TGLSLBumpShaderMT, TGLSLBumpShader, TGLSLBumpShaderAM,
   RegisterClasses([TGLSLBumpShaderMT, TGLSLBumpShader, TGLSLBumpShaderAM,
                    TGLSLMLBumpShader, TGLSLMLBumpShaderMT]);
                    TGLSLMLBumpShader, TGLSLMLBumpShaderMT]);
 
 
 end.
 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
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 //
 
 
-unit GLS.cgShaderBomb;
+unit GLSL.CgBombShader;
 
 
 (*  Just a good looking shader *)
 (*  Just a good looking shader *)
 
 
@@ -23,7 +23,7 @@ uses
   GLTextureFormat,
   GLTextureFormat,
 
 
   Import.cgGL,
   Import.cgGL,
-  GLS.cgShader;
+  GLSL.CgShader;
 
 
 type
 type
   ECgBombShaderException = class(ECgShaderException);
   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
 // 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
    A shader that uses a texture to distort the view by adjusting texture
@@ -22,13 +22,13 @@ uses
   GLCadencer, 
   GLCadencer, 
   GLContext, 
   GLContext, 
   GLScene, 
   GLScene, 
-  GLS.ShaderCustom,
-  GLRenderContextInfo, 
+  GLRenderContextInfo,
   GLTextureFormat,
   GLTextureFormat,
 
 
   Import.Cg,
   Import.Cg,
   Import.CgGL,
   Import.CgGL,
-  GLS.cgShader;
+  GLSL.CustomShader,
+  GLSL.CgShader;
 
 
 type
 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
 // 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
 interface
 
 
@@ -20,9 +20,9 @@ uses
 
 
   Import.Cg,
   Import.Cg,
   Import.CgGL,
   Import.CgGL,
-  GLS.SceneRegister,
-  GLS.cgShader,
-  GLS.cgShaderBomb;
+  GLS.SceneRegister,  //?
+  GLSL.CgShader,
+  GLSL.CgBombShader;
 
 
 procedure Register;
 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
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 //
 
 
-unit GLS.cgShader;
+unit GLSL.CgShader;
 
 
 (* Base Cg shader classes *)
 (* Base Cg shader classes *)
 
 
@@ -284,7 +284,8 @@ type
       write SetOnUnApplyVertexProgram;
       write SetOnUnApplyVertexProgram;
     property OnUnApplyFP: TCgUnApplyEvent read GetOnUnApplyFragmentProgram
     property OnUnApplyFP: TCgUnApplyEvent read GetOnUnApplyFragmentProgram
       write SetOnUnApplyFragmentProgram;
       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
     property OnInitialize: TCgShaderEvent read GetOnInitialize
       write SetOnInitialize;
       write SetOnInitialize;
     property DesignEnable: boolean read FDesignEnable write FDesignEnable
     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
 // 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
     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
 // 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. *)
 (*  An ARBvp1.0 + ARBfp1.0 shader that implements phong shading. *)
 
 
@@ -22,9 +22,9 @@ uses
   Scene.VectorLists,
   Scene.VectorLists,
   OpenGLTokens,
   OpenGLTokens,
   GLContext,
   GLContext,
-  GLS.ShaderAsm,
+  GLSL.AsmShader,
   GLRenderContextInfo,
   GLRenderContextInfo,
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLState;
   GLState;
 
 
 type
 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
 // 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
 interface
 
 
@@ -12,18 +22,18 @@ interface
 
 
 uses
 uses
   System.Classes,
   System.Classes,
-  
+
   OpenGLTokens,
   OpenGLTokens,
   GLTexture,
   GLTexture,
   GLScene,
   GLScene,
   GLState,
   GLState,
   Scene.VectorGeometry,
   Scene.VectorGeometry,
+  GLRenderContextInfo,
+  GLTextureFormat,
   GLContext,
   GLContext,
   GLMaterial,
   GLMaterial,
   GLSL.Shader,
   GLSL.Shader,
-  GLS.ShaderCustom,
-  GLRenderContextInfo,
-  GLTextureFormat,
+  GLSL.CustomShader,
   Scene.VectorTypes;
   Scene.VectorTypes;
 
 
 type
 type

+ 5 - 5
Source/GLSL.Shader.pas

@@ -21,7 +21,7 @@ uses
   Scene.VectorTypes,
   Scene.VectorTypes,
   GLTexture,
   GLTexture,
   GLContext,
   GLContext,
-  GLS.ShaderCustom,
+  GLSL.CustomShader,
   GLRenderContextInfo,
   GLRenderContextInfo,
   GLTextureFormat,
   GLTextureFormat,
   GLSL.ShaderParameter,
   GLSL.ShaderParameter,
@@ -97,7 +97,7 @@ type
     property TransformFeedBackMode: TGLTransformFeedBackMode read FTransformFeedBackMode write SetTransformFeedBackMode default tfbmInterleaved;
     property TransformFeedBackMode: TGLTransformFeedBackMode read FTransformFeedBackMode write SetTransformFeedBackMode default tfbmInterleaved;
   end;
   end;
 
 
-  {Wrapper around a parameter of a GLSL program. }
+  // Wrapper around a parameter of a GLSL program.
   TGLSLShaderParameter = class(TGLCustomShaderParameter)
   TGLSLShaderParameter = class(TGLCustomShaderParameter)
   private
   private
     FGLSLProg: TGLProgramHandle;
     FGLSLProg: TGLProgramHandle;
@@ -163,7 +163,9 @@ type
 implementation
 implementation
 //------------------------------------------------------------------------
 //------------------------------------------------------------------------
 
 
-{ TGLCustomGLSLShader }
+//----------------------------------
+// TGLCustomGLSLShader
+//----------------------------------
 
 
 procedure TGLCustomGLSLShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
 procedure TGLCustomGLSLShader.DoApply(var rci: TGLRenderContextInfo; Sender: TObject);
 begin
 begin
@@ -274,7 +276,6 @@ begin
   end;
   end;
 end;
 end;
 
 
-
 function TGLCustomGLSLShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
 function TGLCustomGLSLShader.DoUnApply(var rci: TGLRenderContextInfo): Boolean;
 begin
 begin
   Result := False;
   Result := False;
@@ -284,7 +285,6 @@ begin
     FGLSLProg.EndUseProgramObject;
     FGLSLProg.EndUseProgramObject;
 end;
 end;
 
 
-
 function TGLCustomGLSLShader.ShaderSupported: Boolean;
 function TGLCustomGLSLShader.ShaderSupported: Boolean;
 begin
 begin
   Result := (GL.ARB_shader_objects and GL.ARB_vertex_program and
   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
 // 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
    This is a collection of GLSL diffuse-specular shaders
@@ -35,8 +35,8 @@ uses
   Scene.PersistentClasses,
   Scene.PersistentClasses,
   Scene.VectorGeometry,
   Scene.VectorGeometry,
   Scene.Strings,
   Scene.Strings,
-  GLS.ShaderCustom,
   GLSL.Shader,
   GLSL.Shader,
+  GLSL.CustomShader,
   GLColor,
   GLColor,
   GLRenderContextInfo,
   GLRenderContextInfo,
   GLMaterial;
   GLMaterial;

+ 1 - 1
Source/GLSL.ShaderErosion.pas

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

+ 1 - 1
Source/GLSL.ShaderFur.pas

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

+ 1 - 1
Source/GLSL.ShaderGlass.pas

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

+ 1 - 1
Source/GLSL.ShaderGooch.pas

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

+ 1 - 1
Source/GLSL.ShaderIvory.pas

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

+ 1 - 1
Source/GLSL.ShaderLattice.pas

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

+ 1 - 1
Source/GLSL.ShaderSem.pas

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

+ 1 - 1
Source/GLSL.ShaderToon.pas

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

+ 1 - 1
Source/GLSL.ShaderVertexDisplacement.pas

@@ -36,7 +36,7 @@ uses
   GLTexture,
   GLTexture,
   GLMaterial,
   GLMaterial,
   GLSL.Shader,
   GLSL.Shader,
-  GLS.ShaderCustom;
+  GLSL.CustomShader;
 
 
 type
 type
   (* Custom class for GLSLVertexDisplacementShader.
   (* 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
 // This unit is part of the GLScene Engine, http://glscene.org
 //
 //
 
 
-unit GLS.CrossXML;
+unit Scene.CrossXML;
 
 
 (* Cross XML routines *)
 (* Cross XML routines *)