Browse Source

Added file formatx in gxscene

glscene 11 months ago
parent
commit
8105f2e5d6
100 changed files with 12971 additions and 209 deletions
  1. 1 1
      Examples/AdvDemos/Archipelago/fArchipelagoD.pas
  2. 1 1
      Examples/AdvDemos/Forest/fForestD.pas
  3. 1 1
      Examples/AdvDemos/GLSViewer/Source/fGLSViewer.pas
  4. 1 1
      Examples/AdvDemos/PanoramViewer/fPanoViewerD.pas
  5. 1 1
      Examples/Demos/behaviours/DCEDemo/fDceDemoD.pas
  6. 1 1
      Examples/Demos/behaviours/FPSMovement/fFPSMovementD.pas
  7. 1 1
      Examples/Demos/cgshaders/CloudSky/fCloudSkyD.pas
  8. 1 1
      Examples/Demos/collisions/boxedin/fBoxedinD.pas
  9. 1 1
      Examples/Demos/glslshaders/Mandelbrot/fMandelbrotD.pas
  10. 1 1
      Examples/Demos/glslshaders/ShadersLab/fShaderLabD.pas
  11. 1 1
      Examples/Demos/glslshaders/Shadertoy/fShadertoyD.pas
  12. 1 1
      Examples/Demos/interface/GameMenu/fGameMenuD.pas
  13. 1 1
      Examples/Demos/interface/GizmoEx/fGizmoExD.pas
  14. 1 1
      Examples/Demos/materials/TransparAdv/fTransparAdvD.pas
  15. 4 6
      Examples/Demos/materials/objmaterial/fObjMaterialD.pas
  16. 2 2
      Examples/Demos/meshes/actortwocam/fActorTwocamD.pas
  17. 1 1
      Examples/Demos/meshes/portal/fPortalD.pas
  18. 1 1
      Examples/Demos/meshes/shadedterrain/fShadedTerrainD.pas
  19. 1 1
      Examples/Demos/meshes/synthterr/fSynthTerrainD.pas
  20. 1 1
      Examples/Demos/meshes/terrain/fTerrainD.pas
  21. 1 1
      Examples/Demos/meshes/tiles/fTilesD.pas
  22. 1 1
      Examples/Demos/movements/smoothnavi/fSmoothNaviD.pas
  23. 2 2
      Examples/Demos/physics/ClothActor/fClothActorD.pas
  24. 1 1
      Examples/Demos/physics/NewtonJoints/fNewtonJointsD.pas
  25. 1 1
      Examples/Demos/physics/NewtonWalkCarry/fNewtonWalkCarryD.pas
  26. 1 1
      Examples/Demos/physics/NewtonWalkShoot/fNGDWalkShootD.pas
  27. 1 1
      Examples/Demos/physics/OdeClothify/fOdeClothifyD.pas
  28. 1 1
      Examples/Demos/physics/OdeConveyor/fOdeConveyorD.pas
  29. 1 1
      Examples/Demos/physics/OdeFurball/fOdeFurballD.pas
  30. 1 1
      Examples/Demos/physics/OdeRagdoll/fOdeRagdollD.pas
  31. 1 1
      Examples/Demos/physics/OdeTerrain/fOdeTerrainD.pas
  32. 1 1
      Examples/Demos/physics/PhysXScatter/PhysXScatterFm.pas
  33. 1 1
      Examples/Demos/rendering/Grass/fGrassD.pas
  34. 1 1
      Examples/Demos/rendering/MultiTexture/fMultiTexturesD.pas
  35. 1 1
      Examples/Demos/rendering/OctreeRender/fOctreeRenderD.pas
  36. 2 2
      Examples/Demos/rendering/QuadTreeCulling/fQuadtreeCullingD.pas
  37. 1 1
      Examples/Demos/rendering/SkyBox/fSkyBoxD.pas
  38. 1 1
      Examples/Demos/rendering/celshading/fCelShadingD.pas
  39. 1 1
      Examples/Demos/specialsFX/PFXCursor/fPfxCursorD.pas
  40. 1 1
      Examples/Demos/specialsFX/PFXGallery/fPFXGalleryD.pas
  41. 1 1
      Examples/Demos/sprites/imposters/fImpostersD.pas
  42. 1 1
      Examples/Demos/utilities/GLInfos/fGLInfosD.pas
  43. 1 1
      Examples/Demos/utilities/keymap/fKeymapD.pas
  44. 2 2
      Packages/GLScene_RT.dpk
  45. 2 2
      Packages/GLScene_RT.dproj
  46. 44 45
      Packages/GXScene_RT.dpk
  47. 43 47
      Packages/GXScene_RT.dproj
  48. 1 1
      Source/FmSceneEditor.pas
  49. 1 1
      Source/FmXCollectionEditor.pas
  50. 1 1
      Source/GLS.AnimatedSprite.pas
  51. 1 1
      Source/GLS.Behaviours.pas
  52. 2 2
      Source/GLS.Collision.pas
  53. 1 1
      Source/GLS.DCE.pas
  54. 1 1
      Source/GLS.ExplosionFx.pas
  55. 1 1
      Source/GLS.FPSMovement.pas
  56. 1 1
      Source/GLS.FireFX.pas
  57. 1 1
      Source/GLS.GeomObjects.pas
  58. 4 4
      Source/GLS.GeometryBB.pas
  59. 1 1
      Source/GLS.GizmoEx.pas
  60. 1 1
      Source/GLS.MaterialEx.pas
  61. 1 1
      Source/GLS.Mirror.pas
  62. 1 1
      Source/GLS.Movement.pas
  63. 2 2
      Source/GLS.NGDManager.pas
  64. 1 1
      Source/GLS.ODEManager.pas
  65. 1 1
      Source/GLS.Octree.pas
  66. 1 1
      Source/GLS.ParticleFX.pas
  67. 1 1
      Source/GLS.Particles.pas
  68. 1 1
      Source/GLS.PhysFields.pas
  69. 1 1
      Source/GLS.PhysForces.pas
  70. 1 1
      Source/GLS.PhysInertias.pas
  71. 1 1
      Source/GLS.PhysManager.pas
  72. 1 1
      Source/GLS.Polyhedra.pas
  73. 1 1
      Source/GLS.ProxyObjects.pas
  74. 1 1
      Source/GLS.Pythons.Script.pas
  75. 11 10
      Source/GLS.Scene.pas
  76. 1 1
      Source/GLS.ScriptBase.pas
  77. 1 1
      Source/GLS.ShadowVolume.pas
  78. 1 1
      Source/GLS.SmartObjects.pas
  79. 1 1
      Source/GLS.SmoothNavigator.pas
  80. 1 1
      Source/GLS.SoundManager.pas
  81. 1 1
      Source/GLS.SpacePartition.pas
  82. 1 1
      Source/GLS.ThorFX.pas
  83. 1 1
      Source/GLS.VectorFileObjects.pas
  84. 1 1
      Source/GLS.VerletTypes.pas
  85. 4 3
      Source/GLS.XCollection.pas
  86. 1 1
      Source/GLS.XCollectionRegister.pas
  87. 1 3
      Source/GLScene.Manager.pas
  88. 1 1
      Sourcex/FMxSceneEditor.pas
  89. 1 1
      Sourcex/FMxXCollectionEditor.pas
  90. 683 0
      Sourcex/Formatx.B3D.pas
  91. 1 1
      Sourcex/Formatx.DDSImage.pas
  92. 1266 0
      Sourcex/Formatx.DXTC.pas
  93. 2465 0
      Sourcex/Formatx.LWO.pas
  94. 192 0
      Sourcex/Formatx.MD2.pas
  95. 152 0
      Sourcex/Formatx.MD3.pas
  96. 191 0
      Sourcex/Formatx.OCT.pas
  97. 211 0
      Sourcex/Formatx.Q3BSP.pas
  98. 1 1
      Sourcex/Formatx.Q3MD3.pas
  99. 4640 0
      Sourcex/Formatx.VFW.pas
  100. 2969 0
      Sourcex/Formatx.m3DS.pas

+ 1 - 1
Examples/AdvDemos/Archipelago/fArchipelagoD.pas

@@ -22,7 +22,7 @@ uses
   GLS.VectorLists,
   GLScene.VectorTypes,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.TextureFormat,
   GLScene.Keyboard,
   GLScene.Utils,

+ 1 - 1
Examples/AdvDemos/Forest/fForestD.pas

@@ -19,7 +19,7 @@ uses
 
   GLScene.VectorTypes,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.VectorLists,
   GLS.PersistentClasses,
   GLS.BaseClasses,

+ 1 - 1
Examples/AdvDemos/GLSViewer/Source/fGLSViewer.pas

@@ -44,7 +44,7 @@ uses
   GLS.BaseClasses,
   GLS.PersistentClasses,
   GLScene.TextureFormat,
-  GLScene.XCollection,
+  GLS.XCollection,
 
   GLS.Material,
   GLS.Scene,

+ 1 - 1
Examples/AdvDemos/PanoramViewer/fPanoViewerD.pas

@@ -22,7 +22,7 @@ uses
   GLS.BaseClasses,
   GLScene.VectorGeometry,
   GLScene.Keyboard,
-  GLScene.XCollection,
+  GLS.XCollection,
 
   GLS.Scene,
   GLS.Objects,

+ 1 - 1
Examples/Demos/behaviours/DCEDemo/fDceDemoD.pas

@@ -35,7 +35,7 @@ uses
   GLS.Context,
   GLS.EllipseCollision,
   GLS.RenderContextInfo,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.ProxyObjects,
   GLS.State,
   GLScene.Utils,

+ 1 - 1
Examples/Demos/behaviours/FPSMovement/fFPSMovementD.pas

@@ -20,7 +20,7 @@ uses
   GLS.Texture,
   GLS.Cadencer,
   GLS.FPSMovement,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.State,
   GLS.SceneViewer,
   GLS.Objects,

+ 1 - 1
Examples/Demos/cgshaders/CloudSky/fCloudSkyD.pas

@@ -25,7 +25,7 @@ uses
   GLS.SkyDome,
   GLS.Texture,
   GLS.FileTGA,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Material,
   GLS.Coordinates,
   GLS.BaseClasses,

+ 1 - 1
Examples/Demos/collisions/boxedin/fBoxedinD.pas

@@ -13,7 +13,7 @@ uses
   Vcl.StdCtrls,
   Vcl.ComCtrls,
 
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
   GLS.Scene,
   GLS.VectorFileObjects,

+ 1 - 1
Examples/Demos/glslshaders/Mandelbrot/fMandelbrotD.pas

@@ -23,7 +23,7 @@ uses
   GLS.Cadencer,
   GLS.Scene,
   GLS.Context,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Utils,
   GLS.FileTGA,
   GLS.HUDObjects,

+ 1 - 1
Examples/Demos/glslshaders/ShadersLab/fShaderLabD.pas

@@ -27,7 +27,7 @@ uses
   GLScene.VectorGeometry,
   GLS.BaseClasses,
   GLS.PersistentClasses,
-  GLScene.XCollection,
+  GLS.XCollection,
 
   GLS.Material,
   GLS.Scene,

+ 1 - 1
Examples/Demos/glslshaders/Shadertoy/fShadertoyD.pas

@@ -17,7 +17,7 @@ uses
   GLS.Objects,
   GLS.Cadencer,
   GLS.SceneViewer,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.RenderContextInfo,
   GLS.OpenGLAdapter,
   GLScene.TextureFormat,

+ 1 - 1
Examples/Demos/interface/GameMenu/fGameMenuD.pas

@@ -26,7 +26,7 @@ uses
   GLS.GameMenu,
   GLS.Cadencer,
   GLS.Texture,
-  GLScene.XCollection,
+  GLS.XCollection,
  
   GLS.Material,
   GLS.Coordinates,

+ 1 - 1
Examples/Demos/interface/GizmoEx/fGizmoExD.pas

@@ -22,7 +22,7 @@ uses
   GLS.Objects,
   GLScene.VectorTypes,
   GLS.SceneViewer,
-  GLScene.XCollection,
+  GLS.XCollection,
 
   GLScene.Utils,
   GLS.GizmoEx,

+ 1 - 1
Examples/Demos/materials/TransparAdv/fTransparAdvD.pas

@@ -38,7 +38,7 @@ uses
   GLS.HUDObjects,
   GLS.BitmapFont,
   GLS.WindowsFont,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Keyboard,
   GLS.CompositeImage,
 

+ 4 - 6
Examples/Demos/materials/objmaterial/fObjMaterialD.pas

@@ -116,16 +116,14 @@ begin
   GLPoints1.Style := psRound;
   for I := 0 to NumPoints - 1 do
   begin
-    Color.X := Random();
-    Color.Y := Random();
-    Color.Z := Random();
-
     X := Random(10) - 5;
     Y := Random(10) - 5;
     Z := Random(10) - 5;
-
     GLPoints1.Positions.Add(X * 0.05, Y * 0.05, Z * 0.05);
-    // Fill array of GLPoints
+	
+	Color.X := Random();
+    Color.Y := Random();
+    Color.Z := Random();
     GLPoints1.Colors.AddPoint(Color);
   end;
 //  dcWorld.Remove(GLPoints1, False);

+ 2 - 2
Examples/Demos/meshes/actortwocam/fActorTwocamD.pas

@@ -23,7 +23,7 @@ uses
   GLS.BaseClasses,
   GLScene.Utils,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.PersistentClasses,
 
   GLS.Scene,
@@ -135,7 +135,7 @@ var
   moving: String;
   boost: Single;
 begin
-  // This function uses asynchronous keyboard check (see GLScene.XCollection.pas)
+  // This function uses asynchronous keyboard check (see GLS.XCollection.pas)
   if IsKeyDown(VK_ESCAPE) then
     Close;
   if IsKeyDown('A') then

+ 1 - 1
Examples/Demos/meshes/portal/fPortalD.pas

@@ -24,7 +24,7 @@ uses
   GLScene.Keyboard,
   GLS.Coordinates,
   GLS.BaseClasses,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Utils,
 
   GLS.Texture,

+ 1 - 1
Examples/Demos/meshes/shadedterrain/fShadedTerrainD.pas

@@ -23,7 +23,7 @@ uses
   GLScene.VectorTypes,
   GLScene.VectorGeometry,
   GLScene.Keyboard,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Coordinates,
 
   GLS.Objects,

+ 1 - 1
Examples/Demos/meshes/synthterr/fSynthTerrainD.pas

@@ -30,7 +30,7 @@ uses
   GLScene.VectorGeometry,
   GLS.Coordinates,
   GLS.BaseClasses,
-  GLScene.XCollection,
+  GLS.XCollection,
 
   GLS.ShadowHDS;
 

+ 1 - 1
Examples/Demos/meshes/terrain/fTerrainD.pas

@@ -20,7 +20,7 @@ uses
   GLS.Scene,
   GLScene.VectorTypes,
   GLScene.Keyboard,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
   GLS.Coordinates,
   GLS.BaseClasses,

+ 1 - 1
Examples/Demos/meshes/tiles/fTilesD.pas

@@ -22,7 +22,7 @@ uses
   GLScene.Keyboard,
   GLScene.VectorGeometry,
   GLScene.TextureFormat,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Utils,
 
   GLS.Objects,

+ 1 - 1
Examples/Demos/movements/smoothnavi/fSmoothNaviD.pas

@@ -15,7 +15,7 @@ uses
   GLScene.Keyboard,
   GLS.Coordinates,
   GLS.BaseClasses,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
 
   GLS.Cadencer,

+ 2 - 2
Examples/Demos/physics/ClothActor/fClothActorD.pas

@@ -26,9 +26,9 @@ uses
   GLS.VerletTypes,
   GLS.VerletClothify,
   GLS.ShadowVolume,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.SpacePartition,
 
   GLS.Material,

+ 1 - 1
Examples/Demos/physics/NewtonJoints/fNewtonJointsD.pas

@@ -23,7 +23,7 @@ uses
   GLS.BaseClasses,
   GLScene.VectorGeometry,
   GLS.SimpleNavigation,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.GeomObjects,
   GLS.HUDObjects,
   GLS.BitmapFont,

+ 1 - 1
Examples/Demos/physics/NewtonWalkCarry/fNewtonWalkCarryD.pas

@@ -33,7 +33,7 @@ uses
   GLS.Coordinates,
   GLS.File3DS,
   GLS.Navigator,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorTypes,
   GLS.Color,
   GLS.HUDObjects,

+ 1 - 1
Examples/Demos/physics/NewtonWalkShoot/fNGDWalkShootD.pas

@@ -30,7 +30,7 @@ uses
   GLS.File3DS,
   GLScene.VectorGeometry,
   GLS.Material,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Utils;
 
 type

+ 1 - 1
Examples/Demos/physics/OdeClothify/fOdeClothifyD.pas

@@ -31,7 +31,7 @@ uses
   GLS.Cadencer,
   GLS.ShadowPlane,
   GLS.File3DS,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.SpacePartition,
   GLS.GeomObjects,
   GLS.ShadowVolume,

+ 1 - 1
Examples/Demos/physics/OdeConveyor/fOdeConveyorD.pas

@@ -27,7 +27,7 @@ uses
   GLS.BaseClasses,
   GLS.SceneViewer,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.SimpleNavigation;
 
 type

+ 1 - 1
Examples/Demos/physics/OdeFurball/fOdeFurballD.pas

@@ -29,7 +29,7 @@ uses
   GLS.ShadowPlane,
   GLS.Navigator,
   GLS.VerletTypes,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Color,
  
   GLS.Coordinates,

+ 1 - 1
Examples/Demos/physics/OdeRagdoll/fOdeRagdollD.pas

@@ -26,7 +26,7 @@ uses
   GLS.BitmapFont,
   GLS.WindowsFont,
   GLS.HUDObjects,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.VectorFileObjects,
   GLS.Ragdoll,
   GLS.Texture,

+ 1 - 1
Examples/Demos/physics/OdeTerrain/fOdeTerrainD.pas

@@ -21,7 +21,7 @@ uses
   GLS.TerrainRenderer,
   GLS.Objects,
   GLS.HeightData,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Cadencer,
   GLS.Texture,
   GLS.HUDObjects,

+ 1 - 1
Examples/Demos/physics/PhysXScatter/PhysXScatterFm.pas

@@ -21,7 +21,7 @@ uses
   GLScene.VectorTypes,
   GLS.SceneViewer,
   GLS.Color,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.BaseClasses,
   GLScene.VectorGeometry,
   GLS.GeomObjects,

+ 1 - 1
Examples/Demos/rendering/Grass/fGrassD.pas

@@ -29,7 +29,7 @@ uses
   GLS.AsyncTimer,
   GLS.Material,
   GLS.Coordinates,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.BaseClasses,
   GLS.RenderContextInfo,
   GLScene.TextureFormat,

+ 1 - 1
Examples/Demos/rendering/MultiTexture/fMultiTexturesD.pas

@@ -35,7 +35,7 @@ uses
   GLS.SimpleNavigation,
   GLS.State,
   GLS.Context,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.MultiSampleImage;
 
 type

+ 1 - 1
Examples/Demos/rendering/OctreeRender/fOctreeRenderD.pas

@@ -22,7 +22,7 @@ uses
   GLS.SceneViewer,
   GLScene.VectorGeometry,
   GLScene.VectorTypes,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.Texture,
   GLS.SpacePartition,
 

+ 2 - 2
Examples/Demos/rendering/QuadTreeCulling/fQuadtreeCullingD.pas

@@ -21,7 +21,7 @@ uses
   GLS.SceneViewer,
   GLS.SkyDome,
   GLS.Objects,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.HeightData,
   GLS.TerrainRenderer,
   GLS.Texture,
@@ -30,7 +30,7 @@ uses
   GLS.SpacePartition,
   GLScene.VectorGeometry,
   GLS.BitmapFont,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.WindowsFont,
   GLS.HUDObjects,
 

+ 1 - 1
Examples/Demos/rendering/SkyBox/fSkyBoxD.pas

@@ -23,7 +23,7 @@ uses
   GLS.Cadencer,
   GLS.Navigator,
   GLS.SceneViewer,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.LensFlare,
   GLS.Objects,
   GLS.Material,

+ 1 - 1
Examples/Demos/rendering/celshading/fCelShadingD.pas

@@ -29,7 +29,7 @@ uses
   GLS.Coordinates,
   GLS.BaseClasses,
   GLS.FileMD2,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Utils,
   GLSL.ShapeShaders;
 

+ 1 - 1
Examples/Demos/specialsFX/PFXCursor/fPfxCursorD.pas

@@ -18,7 +18,7 @@ uses
   GLScene.Keyboard,
   GLScene.VectorTypes,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Coordinates,
   GLS.BaseClasses,
 

+ 1 - 1
Examples/Demos/specialsFX/PFXGallery/fPFXGalleryD.pas

@@ -19,7 +19,7 @@ uses
   GLScene.VectorGeometry,
   GLS.Coordinates,
   GLS.BaseClasses,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Utils,
 
   GLS.SceneViewer,

+ 1 - 1
Examples/Demos/sprites/imposters/fImpostersD.pas

@@ -21,7 +21,7 @@ uses
   GLS.Objects,
   GLS.Cadencer,
   GLS.SceneViewer,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.VectorFileObjects,
   GLS.RenderContextInfo,
   GLScene.Utils,

+ 1 - 1
Examples/Demos/utilities/GLInfos/fGLInfosD.pas

@@ -36,7 +36,7 @@ uses
   GLSL.CustomShader,
   GLSL.Shader,
   GLScene.Utils,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.SoundManager,
   GLS.Sounds.BASS,
   GLS.FileWAV,

+ 1 - 1
Examples/Demos/utilities/keymap/fKeymapD.pas

@@ -7,7 +7,7 @@ uses
   Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
   Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Buttons,
   
-  GLScene.XCollection;
+  GLS.XCollection;
 
 type
   TForm1 = class(TForm)

+ 2 - 2
Packages/GLScene_RT.dpk

@@ -133,7 +133,7 @@ contains
   GLScene.Keyboard in '..\Source\GLScene.Keyboard.pas',
   GLS.GameMenu in '..\Source\GLS.GameMenu.pas',
   GLS.GeomObjects in '..\Source\GLS.GeomObjects.pas',
-  GLScene.GeometryBB in '..\Source\GLScene.GeometryBB.pas',
+  GLS.GeometryBB in '..\Source\GLS.GeometryBB.pas',
   GLScene.Generics in '..\Source\GLScene.Generics.pas',
   GLS.Gizmo in '..\Source\GLS.Gizmo.pas',
   GLS.GizmoEx in '..\Source\GLS.GizmoEx.pas',
@@ -244,7 +244,7 @@ contains
   GLS.zBuffer in '..\Source\GLS.zBuffer.pas',
   GLS.Silhouette in '..\Source\GLS.Silhouette.pas',
   GLS.ScriptBase in '..\Source\GLS.ScriptBase.pas',
-  GLScene.XCollection in '..\Source\GLScene.XCollection.pas',
+  GLS.XCollection in '..\Source\GLS.XCollection.pas',
   GLS.XOpenGL in '..\Source\GLS.XOpenGL.pas',
   GLS.InitOpenGL in '..\Source\GLS.InitOpenGL.pas',
   GLScene.OpenGLTokens in '..\Source\GLScene.OpenGLTokens.pas',

+ 2 - 2
Packages/GLScene_RT.dproj

@@ -258,7 +258,7 @@
         <DCCReference Include="..\Source\GLScene.Keyboard.pas"/>
         <DCCReference Include="..\Source\GLS.GameMenu.pas"/>
         <DCCReference Include="..\Source\GLS.GeomObjects.pas"/>
-        <DCCReference Include="..\Source\GLScene.GeometryBB.pas"/>
+        <DCCReference Include="..\Source\GLS.GeometryBB.pas"/>
         <DCCReference Include="..\Source\GLScene.Generics.pas"/>
         <DCCReference Include="..\Source\GLS.Gizmo.pas"/>
         <DCCReference Include="..\Source\GLS.GizmoEx.pas"/>
@@ -369,7 +369,7 @@
         <DCCReference Include="..\Source\GLS.zBuffer.pas"/>
         <DCCReference Include="..\Source\GLS.Silhouette.pas"/>
         <DCCReference Include="..\Source\GLS.ScriptBase.pas"/>
-        <DCCReference Include="..\Source\GLScene.XCollection.pas"/>
+        <DCCReference Include="..\Source\GLS.XCollection.pas"/>
         <DCCReference Include="..\Source\GLS.XOpenGL.pas"/>
         <DCCReference Include="..\Source\GLS.InitOpenGL.pas"/>
         <DCCReference Include="..\Source\GLScene.OpenGLTokens.pas"/>

+ 44 - 45
Packages/GXScene_RT.dpk

@@ -47,6 +47,7 @@ contains
   GXS.AsyncTimer in '..\SourceX\GXS.AsyncTimer.pas',
   GXS.Atmosphere in '..\SourceX\GXS.Atmosphere.pas',
   GXS.AVIRecorder in '..\SourceX\GXS.AVIRecorder.pas',
+  GXS.BaseClasses in '..\sourcex\GXS.BaseClasses.pas',
   GXS.BSP in '..\SourceX\GXS.BSP.pas',
   GXS.BaseMeshSilhouette in '..\SourceX\GXS.BaseMeshSilhouette.pas',
   GXS.Behaviours in '..\SourceX\GXS.Behaviours.pas',
@@ -60,6 +61,7 @@ contains
   GXS.CelShader in '..\SourceX\GXS.CelShader.pas',
   GXS.Collision in '..\SourceX\GXS.Collision.pas',
   GXS.CompositeImage in '..\SourceX\GXS.CompositeImage.pas',
+  GXS.Coordinates in '..\Sourcex\GXS.Coordinates.pas',
   GXS.Console in '..\SourceX\GXS.Console.pas',
   GXS.Context in '..\SourceX\GXS.Context.pas',
   GXS.DCE in '..\SourceX\GXS.DCE.pas',
@@ -148,6 +150,7 @@ contains
   GXS.ObjectManager in '..\SourceX\GXS.ObjectManager.pas',
   GXS.Objects in '..\SourceX\GXS.Objects.pas',
   GXS.Octree in '..\SourceX\GXS.Octree.pas',
+  GXS.OpenGLAdapter in '..\Sourcex\GXS.OpenGLAdapter.pas',
   GXS.InitOpenGL in '..\SourceX\GXS.InitOpenGL.pas',
   GXS.OutlineShader in '..\SourceX\GXS.OutlineShader.pas',
   GXS.ParametricSurfaces in '..\SourceX\GXS.ParametricSurfaces.pas',
@@ -164,7 +167,6 @@ contains
   GXS.ROAMPatch in '..\SourceX\GXS.ROAMPatch.pas',
   GXS.Ragdoll in '..\SourceX\GXS.Ragdoll.pas',
   GXS.RandomHDS in '..\SourceX\GXS.RandomHDS.pas',
-  GLScene.RedBlackTree in '..\Source\GLScene.RedBlackTree.pas',
   GXS.RenderContextInfo in '..\SourceX\GXS.RenderContextInfo.pas',
   GXS.Scene in '..\SourceX\GXS.Scene.pas',
   GXS.WinContext in '..\SourceX\GXS.WinContext.pas',
@@ -205,7 +207,6 @@ contains
   GXS.PAKArchive in '..\SourceX\GXS.PAKArchive.pas',
   GXS.SpacePartition in '..\SourceX\GXS.SpacePartition.pas',
   GXS.XOpenGL in '..\SourceX\GXS.XOpenGL.pas',
-  GLScene.OpenGL4 in '..\Source\GLScene.OpenGL4.pas',
   GXS.ViewerOpenGL in '..\SourceX\GXS.ViewerOpenGL.pas',
   GXSL.AsmShader in '..\SourceX\GXSL.AsmShader.pas',
   GXSL.BumpShaders in '..\SourceX\GXSL.BumpShaders.pas',
@@ -223,55 +224,53 @@ contains
   GXSL.ShapeShaders in '..\SourceX\GXSL.ShapeShaders.pas',
   GXSL.LineShaders in '..\SourceX\GXSL.LineShaders.pas',
   GXSL.MultiMaterialShader in '..\SourceX\GXSL.MultiMaterialShader.pas',
-  PasDblStrUtils in '..\Source\PasDblStrUtils.pas',
-  PasGLTF in '..\Source\PasGLTF.pas',
-  PasJSON in '..\Source\PasJSON.pas',
-  GLScene.Strings in '..\Source\GLScene.Strings.pas',
-  GLScene.VectorTypes in '..\Source\GLScene.VectorTypes.pas',
-  GLScene.VectorTypesExt in '..\Source\GLScene.VectorTypesExt.pas',
-  GLScene.VectorGeometry in '..\Source\GLScene.VectorGeometry.pas',
-  GLScene.OpenGLTokens in '..\Source\GLScene.OpenGLTokens.pas',
-  GXS.OpenGLAdapter in '..\Sourcex\GXS.OpenGLAdapter.pas',
+  GLScene.RedBlackTree in '..\Source\GLScene.RedBlackTree.pas',
+  GLScene.OpenGL4 in '..\Source\GLScene.OpenGL4.pas',
+  GXS.ScriptBase in '..\Sourcex\GXS.ScriptBase.pas',
+  GXS.SmartObjects in '..\Sourcex\GXS.SmartObjects.pas',
+  GXS.CyborgManager in '..\Sourcex\GXS.CyborgManager.pas',
+  GXS.PersistentClasses in '..\Sourcex\GXS.PersistentClasses.pas',
+  GXS.VectorLists in '..\Sourcex\GXS.VectorLists.pas',
+  GXS.Color in '..\Sourcex\GXS.Color.pas',
+  GXS.CurvesAndSurfaces in '..\Sourcex\GXS.CurvesAndSurfaces.pas',
+  GXS.GeometryBB in '..\Sourcex\GXS.GeometryBB.pas',
+  GXS.XCollection in '..\Sourcex\GXS.XCollection.pas',
+  GLScene.AnimationUtils in '..\Source\GLScene.AnimationUtils.pas',
+  GLScene.Generics in '..\Source\GLScene.Generics.pas',
+  GLScene.Keyboard in '..\Source\GLScene.Keyboard.pas',
   GLScene.Logger in '..\Source\GLScene.Logger.pas',
-  GLScene.Spline in '..\Source\GLScene.Spline.pas',
+  GLScene.Manager in '..\Source\GLScene.Manager.pas',
+  GLScene.OpenGLTokens in '..\Source\GLScene.OpenGLTokens.pas',
+  GLScene.PipelineTransform in '..\Source\GLScene.PipelineTransform.pas',
+  GLScene.Polynomials in '..\Source\GLScene.Polynomials.pas',
   GLScene.RandomLib in '..\Source\GLScene.RandomLib.pas',
   GLScene.RGBE in '..\Source\GLScene.RGBE.pas',
+  GLScene.Spline in '..\Source\GLScene.Spline.pas',
+  GLScene.Strings in '..\Source\GLScene.Strings.pas',
+  GLScene.TextureFormat in '..\Source\GLScene.TextureFormat.pas',
+  GLScene.Triangulation in '..\Source\GLScene.Triangulation.pas',
   GLScene.Utils in '..\Source\GLScene.Utils.pas',
-  GLScene.Manager in '..\Source\GLScene.Manager.pas',
-  GLScene.Generics in '..\Source\GLScene.Generics.pas',
-  GLScene.GeometryBB in '..\Source\GLScene.GeometryBB.pas',
-  GXS.CurvesAndSurfaces in '..\Sourcex\GXS.CurvesAndSurfaces.pas',
-  GLScene.AnimationUtils in '..\Source\GLScene.AnimationUtils.pas',
+  GLScene.VectorGeometry in '..\Source\GLScene.VectorGeometry.pas',
+  GLScene.VectorTypes in '..\Source\GLScene.VectorTypes.pas',
+  GLScene.VectorTypesExt in '..\Source\GLScene.VectorTypesExt.pas',
+  Formatx.DXTC in '..\Sourcex\Formatx.DXTC.pas',
+  Formatx.VFW in '..\Sourcex\Formatx.VFW.pas',
+  Formatx.m3DS in '..\Sourcex\Formatx.m3DS.pas',
+  Formatx.m3DSConst in '..\Sourcex\Formatx.m3DSConst.pas',
+  Formatx.m3DSTypes in '..\Sourcex\Formatx.m3DSTypes.pas',
+  Formatx.m3DSUtils in '..\Sourcex\Formatx.m3DSUtils.pas',
+  PasDblStrUtils in '..\Source\PasDblStrUtils.pas',
+  PasGLTF in '..\Source\PasGLTF.pas',
+  PasJSON in '..\Source\PasJSON.pas',
+  Formatx.MD3 in '..\Sourcex\Formatx.MD3.pas',
+  Formatx.MD2 in '..\Sourcex\Formatx.MD2.pas',
+  Formatx.LWO in '..\Sourcex\Formatx.LWO.pas',
+  Formatx.OCT in '..\Sourcex\Formatx.OCT.pas',
+  Formatx.Q3BSP in '..\Sourcex\Formatx.Q3BSP.pas',
   Formatx.X in '..\Sourcex\Formatx.X.pas',
-  GLScene.TextureFormat in '..\Source\GLScene.TextureFormat.pas',
-  Formats.DXTC in '..\Source\Formats.DXTC.pas',
-  Formats.GL2 in '..\Source\Formats.GL2.pas',
-  Formats.m3DS in '..\Source\Formats.m3DS.pas',
-  Formats.m3DSConst in '..\Source\Formats.m3DSConst.pas',
-  Formats.m3DSTypes in '..\Source\Formats.m3DSTypes.pas',
-  Formats.m3DSUtils in '..\Source\Formats.m3DSUtils.pas',
-  Formats.MD2 in '..\Source\Formats.MD2.pas',
-  Formats.MD3 in '..\Source\Formats.MD3.pas',
-  Formats.OCT in '..\Source\Formats.OCT.pas',
-  Formats.Q3BSP in '..\Source\Formats.Q3BSP.pas',
-  Formats.VFW in '..\Source\Formats.VFW.pas',
   Formatx.VRML in '..\Sourcex\Formatx.VRML.pas',
   Formatx.Q3MD3 in '..\Sourcex\Formatx.Q3MD3.pas',
-  Formats.B3D in '..\Source\Formats.B3D.pas',
-  Formats.LWO in '..\Source\Formats.LWO.pas',
-  gnuGettext in '..\Source\gnuGettext.pas',
-  gnuGettextInit in '..\Source\gnuGettextInit.pas',
-  GLScene.XCollection in '..\Source\GLScene.XCollection.pas',
-  GLScene.Keyboard in '..\Source\GLScene.Keyboard.pas',
-  GLScene.Polynomials in '..\Source\GLScene.Polynomials.pas',
-  GLScene.PipelineTransform in '..\Source\GLScene.PipelineTransform.pas',
-  GXS.ScriptBase in '..\Sourcex\GXS.ScriptBase.pas',
-  GXS.SmartObjects in '..\Sourcex\GXS.SmartObjects.pas',
-  GXS.CyborgManager in '..\Sourcex\GXS.CyborgManager.pas',
-  GXS.PersistentClasses in '..\Sourcex\GXS.PersistentClasses.pas',
-  GXS.VectorLists in '..\Sourcex\GXS.VectorLists.pas',
-  GXS.Color in '..\Sourcex\GXS.Color.pas',
-  GXS.BaseClasses in '..\sourcex\GXS.BaseClasses.pas',
-  GXS.Coordinates in '..\Sourcex\GXS.Coordinates.pas';
+  Formatx.B3D in '..\Sourcex\Formatx.B3D.pas';
 
 end.
+

+ 43 - 47
Packages/GXScene_RT.dproj

@@ -196,6 +196,7 @@
         <DCCReference Include="..\SourceX\GXS.AsyncTimer.pas"/>
         <DCCReference Include="..\SourceX\GXS.Atmosphere.pas"/>
         <DCCReference Include="..\SourceX\GXS.AVIRecorder.pas"/>
+        <DCCReference Include="..\sourcex\GXS.BaseClasses.pas"/>
         <DCCReference Include="..\SourceX\GXS.BSP.pas"/>
         <DCCReference Include="..\SourceX\GXS.BaseMeshSilhouette.pas"/>
         <DCCReference Include="..\SourceX\GXS.Behaviours.pas"/>
@@ -209,6 +210,7 @@
         <DCCReference Include="..\SourceX\GXS.CelShader.pas"/>
         <DCCReference Include="..\SourceX\GXS.Collision.pas"/>
         <DCCReference Include="..\SourceX\GXS.CompositeImage.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.Coordinates.pas"/>
         <DCCReference Include="..\SourceX\GXS.Console.pas"/>
         <DCCReference Include="..\SourceX\GXS.Context.pas"/>
         <DCCReference Include="..\SourceX\GXS.DCE.pas"/>
@@ -297,6 +299,7 @@
         <DCCReference Include="..\SourceX\GXS.ObjectManager.pas"/>
         <DCCReference Include="..\SourceX\GXS.Objects.pas"/>
         <DCCReference Include="..\SourceX\GXS.Octree.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.OpenGLAdapter.pas"/>
         <DCCReference Include="..\SourceX\GXS.InitOpenGL.pas"/>
         <DCCReference Include="..\SourceX\GXS.OutlineShader.pas"/>
         <DCCReference Include="..\SourceX\GXS.ParametricSurfaces.pas"/>
@@ -313,7 +316,6 @@
         <DCCReference Include="..\SourceX\GXS.ROAMPatch.pas"/>
         <DCCReference Include="..\SourceX\GXS.Ragdoll.pas"/>
         <DCCReference Include="..\SourceX\GXS.RandomHDS.pas"/>
-        <DCCReference Include="..\Source\GLScene.RedBlackTree.pas"/>
         <DCCReference Include="..\SourceX\GXS.RenderContextInfo.pas"/>
         <DCCReference Include="..\SourceX\GXS.Scene.pas"/>
         <DCCReference Include="..\SourceX\GXS.WinContext.pas"/>
@@ -354,7 +356,6 @@
         <DCCReference Include="..\SourceX\GXS.PAKArchive.pas"/>
         <DCCReference Include="..\SourceX\GXS.SpacePartition.pas"/>
         <DCCReference Include="..\SourceX\GXS.XOpenGL.pas"/>
-        <DCCReference Include="..\Source\GLScene.OpenGL4.pas"/>
         <DCCReference Include="..\SourceX\GXS.ViewerOpenGL.pas"/>
         <DCCReference Include="..\SourceX\GXSL.AsmShader.pas"/>
         <DCCReference Include="..\SourceX\GXSL.BumpShaders.pas"/>
@@ -372,58 +373,53 @@
         <DCCReference Include="..\SourceX\GXSL.ShapeShaders.pas"/>
         <DCCReference Include="..\SourceX\GXSL.LineShaders.pas"/>
         <DCCReference Include="..\SourceX\GXSL.MultiMaterialShader.pas"/>
-        <DCCReference Include="..\Source\PasDblStrUtils.pas"/>
-        <DCCReference Include="..\Source\PasGLTF.pas"/>
-        <DCCReference Include="..\Source\PasJSON.pas"/>
-        <DCCReference Include="..\Source\GLScene.Strings.pas"/>
-        <DCCReference Include="..\Source\GLScene.VectorTypes.pas"/>
-        <DCCReference Include="..\Source\GLScene.VectorTypesExt.pas"/>
-        <DCCReference Include="..\Source\GLScene.VectorGeometry.pas"/>
-        <DCCReference Include="..\Source\GLScene.OpenGLTokens.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.OpenGLAdapter.pas"/>
+        <DCCReference Include="..\Source\GLScene.RedBlackTree.pas"/>
+        <DCCReference Include="..\Source\GLScene.OpenGL4.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.ScriptBase.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.SmartObjects.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.CyborgManager.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.PersistentClasses.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.VectorLists.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.Color.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.CurvesAndSurfaces.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.GeometryBB.pas"/>
+        <DCCReference Include="..\Sourcex\GXS.XCollection.pas"/>
+        <DCCReference Include="..\Source\GLScene.AnimationUtils.pas"/>
+        <DCCReference Include="..\Source\GLScene.Generics.pas"/>
+        <DCCReference Include="..\Source\GLScene.Keyboard.pas"/>
         <DCCReference Include="..\Source\GLScene.Logger.pas"/>
-        <DCCReference Include="..\Source\GLScene.Spline.pas"/>
+        <DCCReference Include="..\Source\GLScene.Manager.pas"/>
+        <DCCReference Include="..\Source\GLScene.OpenGLTokens.pas"/>
+        <DCCReference Include="..\Source\GLScene.PipelineTransform.pas"/>
+        <DCCReference Include="..\Source\GLScene.Polynomials.pas"/>
         <DCCReference Include="..\Source\GLScene.RandomLib.pas"/>
         <DCCReference Include="..\Source\GLScene.RGBE.pas"/>
+        <DCCReference Include="..\Source\GLScene.Spline.pas"/>
+        <DCCReference Include="..\Source\GLScene.Strings.pas"/>
+        <DCCReference Include="..\Source\GLScene.TextureFormat.pas"/>
+        <DCCReference Include="..\Source\GLScene.Triangulation.pas"/>
         <DCCReference Include="..\Source\GLScene.Utils.pas"/>
-        <DCCReference Include="..\Source\GLScene.Manager.pas"/>
-        <DCCReference Include="..\Source\GLScene.Generics.pas"/>
-        <DCCReference Include="..\Source\GLScene.GeometryBB.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.CurvesAndSurfaces.pas"/>
-        <DCCReference Include="..\Source\GLScene.AnimationUtils.pas"/>
+        <DCCReference Include="..\Source\GLScene.VectorGeometry.pas"/>
+        <DCCReference Include="..\Source\GLScene.VectorTypes.pas"/>
+        <DCCReference Include="..\Source\GLScene.VectorTypesExt.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.DXTC.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.VFW.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.m3DS.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.m3DSConst.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.m3DSTypes.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.m3DSUtils.pas"/>
+        <DCCReference Include="..\Source\PasDblStrUtils.pas"/>
+        <DCCReference Include="..\Source\PasGLTF.pas"/>
+        <DCCReference Include="..\Source\PasJSON.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.MD3.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.MD2.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.LWO.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.OCT.pas"/>
+        <DCCReference Include="..\Sourcex\Formatx.Q3BSP.pas"/>
         <DCCReference Include="..\Sourcex\Formatx.X.pas"/>
-        <DCCReference Include="..\Source\GLScene.TextureFormat.pas"/>
-        <DCCReference Include="..\Source\Formats.DXTC.pas"/>
-        <DCCReference Include="..\Source\Formats.GL2.pas"/>
-        <DCCReference Include="..\Source\Formats.m3DS.pas"/>
-        <DCCReference Include="..\Source\Formats.m3DSConst.pas"/>
-        <DCCReference Include="..\Source\Formats.m3DSTypes.pas"/>
-        <DCCReference Include="..\Source\Formats.m3DSUtils.pas"/>
-        <DCCReference Include="..\Source\Formats.MD2.pas"/>
-        <DCCReference Include="..\Source\Formats.MD3.pas"/>
-        <DCCReference Include="..\Source\Formats.OCT.pas"/>
-        <DCCReference Include="..\Source\Formats.Q3BSP.pas"/>
-        <DCCReference Include="..\Source\Formats.VFW.pas"/>
         <DCCReference Include="..\Sourcex\Formatx.VRML.pas"/>
         <DCCReference Include="..\Sourcex\Formatx.Q3MD3.pas"/>
-        <DCCReference Include="..\Source\Formats.B3D.pas"/>
-        <DCCReference Include="..\Source\Formats.LWO.pas"/>
-        <DCCReference Include="..\Source\gnuGettext.pas"/>
-        <DCCReference Include="..\Source\gnuGettextInit.pas"/>
-        <DCCReference Include="..\Source\GLScene.XCollection.pas"/>
-        <DCCReference Include="..\Source\GLScene.Keyboard.pas"/>
-        <DCCReference Include="..\Source\GLScene.Polynomials.pas"/>
-        <DCCReference Include="..\Source\GLScene.PipelineTransform.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.ScriptBase.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.SmartObjects.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.CyborgManager.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.PersistentClasses.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.VectorLists.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.Color.pas"/>
-        <DCCReference Include="..\sourcex\GXS.BaseClasses.pas"/>
-        <DCCReference Include="..\Sourcex\GXS.Coordinates.pas"/>
-        <None Include="..\Sourcex\GXS.Scene.inc"/>
-        <None Include="..\Source\GLScene.Defines.inc"/>
+        <DCCReference Include="..\Sourcex\Formatx.B3D.pas"/>
         <BuildConfiguration Include="Base">
             <Key>Base</Key>
         </BuildConfiguration>

+ 1 - 1
Source/FmSceneEditor.pas

@@ -35,7 +35,7 @@ uses
   GLS.SceneViewer,
   GLScene.Strings,
   FmInfo,
-  GLScene.XCollection,
+  GLS.XCollection,
 
   GLScene.Utils,
   GLS.SceneRegister;

+ 1 - 1
Source/FmXCollectionEditor.pas

@@ -30,7 +30,7 @@ uses
   GLS.Scene,
   GLS.Behaviours,
   GLS.MaterialEx,
-  GLScene.XCollection;
+  GLS.XCollection;
 
 type
   TXCollectionEditorForm = class(TForm)

+ 1 - 1
Source/GLS.AnimatedSprite.pas

@@ -21,7 +21,7 @@ uses
   GLScene.VectorGeometry,
   GLS.Material,
   GLS.PersistentClasses,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.RenderContextInfo,
   GLS.BaseClasses, 
   GLS.Context, 

+ 1 - 1
Source/GLS.Behaviours.pas

@@ -16,7 +16,7 @@ uses
   GLScene.VectorTypes,
   GLS.Scene,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.BaseClasses,
   GLS.Coordinates;
 

+ 2 - 2
Source/GLS.Collision.pas

@@ -18,10 +18,10 @@ uses
   GLScene.OpenGLTokens,
   GLScene.VectorGeometry,
   GLS.Scene,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.VectorLists,
   GLS.VectorFileObjects,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLScene.Manager;
 
 type

+ 1 - 1
Source/GLS.DCE.pas

@@ -35,7 +35,7 @@ uses
   GLS.BaseClasses,
   GLS.Coordinates,
   GLScene.Manager,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.VectorLists,
 
   GLS.Scene,

+ 1 - 1
Source/GLS.ExplosionFx.pas

@@ -32,7 +32,7 @@ uses
   GLS.Scene,
   GLS.VectorFileObjects,
   GLS.VectorLists,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Coordinates,
   GLS.RenderContextInfo,
   GLS.Context,

+ 1 - 1
Source/GLS.FPSMovement.pas

@@ -25,7 +25,7 @@ uses
   GLS.Scene,
   GLS.VectorFileObjects,
   GLS.VectorLists,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.GeomObjects,
   GLS.Navigator,
   GLS.RenderContextInfo,

+ 1 - 1
Source/GLS.FireFX.pas

@@ -18,7 +18,7 @@ uses
   GLScene.OpenGLTokens,
   GLS.Scene,
   GLScene.PipelineTransform,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
   GLS.Context,
   GLS.VectorLists,

+ 1 - 1
Source/GLS.GeomObjects.pas

@@ -32,7 +32,7 @@ uses
   GLS.PersistentClasses,
   GLS.VectorLists,
   GLS.Silhouette,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.VectorFileObjects,
   GLS.Material,
   GLS.Texture,

+ 4 - 4
Source/GLScene.GeometryBB.pas → Source/GLS.GeometryBB.pas

@@ -1,7 +1,7 @@
 //
 // The graphics engine GLScene https://github.com/glscene
 //
-unit GLScene.GeometryBB;
+unit GLS.GeometryBB;
 
 (* Calculations and manipulations on Bounding Boxes *)
 
@@ -13,8 +13,8 @@ uses
   System.SysUtils,
 
   GLScene.VectorGeometry,
-  GLS.VectorLists,
-  GLScene.VectorTypes;
+  GLScene.VectorTypes,
+  GLS.VectorLists;
 
 type
   //  Structure for storing Bounding Boxes 
@@ -205,7 +205,7 @@ const
   CDirPlan: TDirPlan = (0, 0, 1, 1, 2, 2);
 
 implementation // -------------------------------------------------------------
- 
+
 // ------------------------------------------------------------------------------
 // ----------------- BB functions -------------------------------------------
 // ------------------------------------------------------------------------------

+ 1 - 1
Source/GLS.GizmoEx.pas

@@ -33,7 +33,7 @@ uses
   GLS.VectorFileObjects,
   GLS.Coordinates,
   GLS.RenderContextInfo,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLScene.VectorTypes,
   GLS.Canvas,
   GLS.PersistentClasses,

+ 1 - 1
Source/GLS.MaterialEx.pas

@@ -43,7 +43,7 @@ uses
   GLS.PersistentClasses,
   GLS.State,
   GLScene.TextureFormat,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.TextureCombiners,
   GLSL.ShaderParameter,
   GLS.ApplicationFileIO,

+ 1 - 1
Source/GLS.Mirror.pas

@@ -27,7 +27,7 @@ uses
   GLScene.VectorTypes,
   GLS.PersistentClasses,
   GLScene.PipelineTransform,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Texture;
 
 

+ 1 - 1
Source/GLS.Movement.pas

@@ -21,7 +21,7 @@ uses
   GLScene.OpenGLTokens,
   GLS.PersistentClasses,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Spline,
   GLS.BaseClasses,
 

+ 2 - 2
Source/GLS.NGDManager.pas

@@ -25,8 +25,8 @@ uses
   GLScene.VectorTypes,
   GLScene.VectorGeometry, // PGLVector TGLVector TGLMatrix PGLMatrix NullHmgVector...
   GLS.VectorLists, // TGLAffineVectorList for Tree
-  GLScene.XCollection, // TXCollection file function
-  GLScene.GeometryBB, // For show debug
+  GLS.XCollection, // TXCollection file function
+  GLS.GeometryBB, // For show debug
   GLS.BaseClasses,
   GLS.PersistentClasses,
   GLS.Scene,

+ 1 - 1
Source/GLS.ODEManager.pas

@@ -21,7 +21,7 @@ uses
   GLScene.PipelineTransform,
   GLS.PersistentClasses,
   GLScene.Manager,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Scene,
   GLS.Context,
   GLS.Texture,

+ 1 - 1
Source/GLS.Octree.pas

@@ -19,7 +19,7 @@ uses
   GLScene.VectorTypes,
   GLScene.VectorGeometry,
   GLS.VectorLists,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.Context;
 
 type

+ 1 - 1
Source/GLS.ParticleFX.pas

@@ -28,7 +28,7 @@ uses
   GLScene.VectorTypes,
   GLS.PersistentClasses,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Material,
   GLS.Cadencer,
   GLS.VectorLists,

+ 1 - 1
Source/GLS.Particles.pas

@@ -16,7 +16,7 @@ uses
 
   GLScene.VectorTypes,
   GLS.Scene,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.PersistentClasses,
   GLScene.VectorGeometry,
   GLScene.OpenGLTokens,

+ 1 - 1
Source/GLS.PhysFields.pas

@@ -8,7 +8,7 @@ interface
 uses
   System.Classes,
   GLScene.VectorGeometry,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Coordinates,
 
   GLS.Scene,

+ 1 - 1
Source/GLS.PhysForces.pas

@@ -9,7 +9,7 @@ uses
   System.Classes,
 
   GLScene.VectorTypes,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.Scene,
   GLScene.VectorGeometry,
   GLS.Behaviours,

+ 1 - 1
Source/GLS.PhysInertias.pas

@@ -10,7 +10,7 @@ uses
   System.Classes,
 
   GLS.PersistentClasses,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.BaseClasses,
   GLScene.VectorGeometry,
   GLScene.VectorTypes,

+ 1 - 1
Source/GLS.PhysManager.pas

@@ -11,7 +11,7 @@ uses
   System.Classes,
   System.SysUtils,
 
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
   GLS.Scene,
   GLS.PhysForces,

+ 1 - 1
Source/GLS.Polyhedra.pas

@@ -43,7 +43,7 @@ uses
   GLS.Mesh,
   GLScene.Logger,
   GLS.Octree,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.ApplicationFileIO,
   GLS.Context,
   GLS.Color;

+ 1 - 1
Source/GLS.ProxyObjects.pas

@@ -17,7 +17,7 @@ uses
 
   GLScene.OpenGLTokens,
   GLS.Scene,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.PipelineTransform,
   GLScene.VectorGeometry,
   GLS.Texture,

+ 1 - 1
Source/GLS.Pythons.Script.pas

@@ -12,7 +12,7 @@ uses
   System.Classes,
   System.SysUtils,
 
-  GLScene.XCollection,
+  GLS.XCollection,
   GLS.ScriptBase,
   GLScene.Manager,
 

+ 11 - 10
Source/GLS.Scene.pas

@@ -24,18 +24,22 @@ uses
   Vcl.Graphics,
   Vcl.Controls,
 
+  GLScene.VectorTypes,
+  GLScene.VectorGeometry,
   GLScene.OpenGLTokens,
-  GLS.XOpenGL,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.Strings,
+  GLScene.PipelineTransform,
+  GLScene.TextureFormat,
+  GLScene.Utils,
+  GLScene.Logger,
+
   GLS.Context,
-  GLScene.VectorGeometry,
   GLS.Silhouette,
   GLS.PersistentClasses,
-  GLScene.PipelineTransform,
   GLS.State,
   GLS.Graphics,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.VectorLists,
   GLS.Texture,
   GLS.Color,
@@ -43,13 +47,10 @@ uses
   GLS.Coordinates,
   GLS.RenderContextInfo,
   GLS.Material,
-  GLScene.TextureFormat,
+  GLS.XOpenGL,
   GLS.Selection,
-  GLScene.VectorTypes,
   GLS.ApplicationFileIO,
-  GLScene.Utils,
-  GLS.ImageUtils,
-  GLScene.Logger;
+  GLS.ImageUtils;
 
 type
   // Defines which features are taken from the master object.

+ 1 - 1
Source/GLS.ScriptBase.pas

@@ -15,7 +15,7 @@ interface
 
 uses
   System.Classes,
-  GLScene.XCollection;
+  GLS.XCollection;
 
 type
   TGLScriptState = (

+ 1 - 1
Source/GLS.ShadowVolume.pas

@@ -27,7 +27,7 @@ uses
   GLS.PersistentClasses,
   GLS.Coordinates,
   GLScene.PipelineTransform,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.Color,
   GLS.Selection,
   GLS.RenderContextInfo,

+ 1 - 1
Source/GLS.SmartObjects.pas

@@ -41,7 +41,7 @@ uses
   GLS.Material,
   GLS.Mesh,
   GLS.Octree,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.Objects,
   GLS.GeomObjects,
   GLS.ApplicationFileIO,

+ 1 - 1
Source/GLS.SmoothNavigator.pas

@@ -35,7 +35,7 @@ uses
   GLScene.VectorGeometry,
   GLS.Coordinates,
   GLS.Screen, 
-  GLScene.XCollection;
+  GLS.XCollection;
 
 type
 

+ 1 - 1
Source/GLS.SoundManager.pas

@@ -15,7 +15,7 @@ uses
   GLScene.VectorTypes,
   GLS.SoundFileObjects,
   GLS.Scene,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
   GLS.Cadencer,
   GLS.BaseClasses,

+ 1 - 1
Source/GLS.SpacePartition.pas

@@ -41,7 +41,7 @@ uses
   GLS.Coordinates,
   GLScene.VectorTypes,
   GLScene.VectorGeometry,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLS.Context,
   GLS.RenderContextInfo,
   GLS.SceneViewer,

+ 1 - 1
Source/GLS.ThorFX.pas

@@ -18,7 +18,7 @@ uses
 
   GLScene.OpenGLTokens,
   GLS.Scene,
-  GLScene.XCollection,
+  GLS.XCollection,
   GLScene.VectorGeometry,
   GLS.Context,
   GLS.VectorLists,

+ 1 - 1
Source/GLS.VectorFileObjects.pas

@@ -36,7 +36,7 @@ uses
   GLS.PersistentClasses,
   GLS.Coordinates,
   GLS.BaseClasses,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
   GLScene.Utils,
 
   GLS.Scene,

+ 1 - 1
Source/GLS.VerletTypes.pas

@@ -27,7 +27,7 @@ uses
   GLS.Coordinates,
   GLScene.VectorGeometry,
   GLS.VectorLists,
-  GLScene.GeometryBB,
+  GLS.GeometryBB,
 
   GLS.Objects,
   GLS.Scene,

+ 4 - 3
Source/GLScene.XCollection.pas → Source/GLS.XCollection.pas

@@ -1,7 +1,7 @@
 //
 // The graphics engine GLScene https://github.com/glscene
 //
-unit GLScene.XCollection;
+unit GLS.XCollection;
 
 (* A polymorphism-enabled TCollection-like set of classes *)
 
@@ -15,8 +15,9 @@ uses
   System.Classes,
   System.SysUtils,
   System.Types,
-  GLScene.Strings,
-  GLS.PersistentClasses
+  GLS.PersistentClasses,
+  GLScene.Strings
+
 {$IFDEF DEBUG_XCOLLECTION}, System.TypInfo {$ENDIF};
 
 type

+ 1 - 1
Source/GLS.XCollectionRegister.pas

@@ -11,7 +11,7 @@ interface
 
 uses
   System.Classes,
-  GLScene.XCollection,
+  GLS.XCollection,
 
   DesignEditors,
   DesignIntf;

+ 1 - 3
Source/GLScene.Manager.pas

@@ -20,9 +20,7 @@ procedure DeRegisterManager(aManager: TComponent);
 function FindManager(classType: TComponentClass; const managerName: String)
   : TComponent;
 
-// ------------------------------------------------------
-implementation
-// ------------------------------------------------------
+implementation // ------------------------------------------------------------
 
 var
   vManagers: TList;

+ 1 - 1
Sourcex/FMxSceneEditor.pas

@@ -37,7 +37,7 @@ uses
   GXS.SceneViewer,
   GXS.SceneRegister,
   GLScene.Strings,
-  GLScene.XCollection;
+  GXS.XCollection;
 
 type
   TSceneEditorForm = class(TForm)

+ 1 - 1
Sourcex/FMxXCollectionEditor.pas

@@ -33,7 +33,7 @@ uses
   GXS.Scene,
   GLScene.Strings,
   GXS.Behaviours,
-  GLScene.XCollection;
+  GXS.XCollection;
 
 type
   IDesigner = interface //in designintf -> (IDesigner200)

+ 683 - 0
Sourcex/Formatx.B3D.pas

@@ -0,0 +1,683 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.B3D;
+
+(* File streaming class for the B3D loader *)
+
+interface
+
+{$I GLScene.Defines.inc}
+{$R-}
+
+uses
+  System.Classes, 
+  System.SysUtils,
+   
+  GLScene.VectorGeometry, 
+  GLScene.VectorTypes, 
+  GXS.VectorLists;
+
+
+type
+  TB3DChunkType = (bctUnknown, bctHeader, bctTexture, bctBrush, bctNode, bctVertex, bctTriangle,
+    bctMesh, bctBone, bctKeyFrame, bctAnimation);
+
+  PB3DChunk = ^TB3DChunk;
+  TB3DChunk = record
+    chunk: array[0..3] of char;
+    length: Integer;
+  end;
+
+  PBB3DChunk = ^TBB3DChunk;
+  TBB3DChunk = record
+    Version: Integer;
+  end;
+
+  PTEXSChunk = ^TTEXSChunk;
+  TTEXSChunk = record
+    fileName: array[0..255] of char; //texture file name this is the filename of the texture, ie "wall.bmp"  Has to be in the local Directory
+    flags, blend: Integer;  //blitz3D TextureFLags and TextureBlend: default=1,2
+  		            //these are the same as far as I know as the flags for a texture in Blitz3D
+    x_pos, y_pos: Single;   //x and y position of texture: default=0,0
+    x_scale, y_scale: Single; //x and y scale of texture: default=1,1
+    rotation: Single;         //rotation of texture (in radians): default=0 radian = 180/pi degrees
+  end;
+
+  PBRUSChunk = ^TBRUSChunk;
+  TBRUSChunk = record
+    n_texs: Integer;
+    name: array[0..255] of Char; //eg "WATER" - just use texture name by default
+    red, green, blue, alpha: Single;  //Blitz3D Brushcolor and Brushalpha: default=1,1,1,1
+    shininess: Single; //Blitz3D BrushShininess: default=0
+    blend, fx: Integer; //Blitz3D Brushblend and BrushFX: default=1,0
+    texture_id: array of Integer; //textures used in brush, ie if there is more then one texture used, ie Alphamaps, colour maps etc,
+                                  //you put all ID's here as ints.
+  end;
+
+  PVertexData = ^TVertexData;
+  TVertexData = record
+    next: PVertexData;
+    x, y, z: Single; //always present
+    nx, ny, nz: Single; //vertex normal: present if (flags&1)
+    red, green, blue, alpha: Single; //vertex color: present if (flags&2)
+    tex_coords: array of Single; //tex coords
+  end;
+
+  PVRTSChunk = ^TVRTSChunk;
+  TVRTSChunk = record
+    flags: Integer; //1=normal values present, 2=rgba values present
+    tex_coord_sets: Integer; //texture coords per vertex (eg: 1 for simple U/V) max=8
+    tex_coord_set_size: Integer; //components per set (eg: 2 for simple U/V) max=4
+    vertices: PVertexData;
+  end;
+
+  PTRISChunk = ^TTRISChunk;
+  TTRISChunk = record
+    next: PTRISChunk;
+    brush_id: Integer; //brush applied to these TRIs: default=-1
+    vertex_id: array of Integer; //vertex indices
+  end;
+
+  PMESHChunk = ^TMESHChunk;
+  TMESHChunk = record
+    brush_id: Integer; //'master' brush: default=-1
+    vertices: TVRTSChunk;  //vertices
+    triangles: PTRISChunk;  //1 or more sets of triangles
+  end;
+
+  PBONEChunk = ^TBONEChunk;
+  TBONEChunk = record
+    vertex_id: Integer; //vertex affected by this bone
+    weight: Single; //;how much the vertex is affected
+  end;
+
+  PKEYSChunk = ^TKEYSChunk;
+  TKEYSChunk = record
+    next: PKEYSChunk;
+    flags: Integer; //1=position, 2=scale, 4=rotation
+    frame: Integer; //where key occurs
+    position: TAffineVector; //present if (flags&1)
+    scale: TAffineVector; //present if (flags&2)
+    rotation: TGLVector; //present if (flags&4)
+  end;
+
+  PANIMChunk = ^TANIMChunk;
+  TANIMChunk = record
+    flags: Integer; //unused: default=0
+    frames: Integer; //how many frames in anim
+    fps: Single; //default=60
+  end;
+
+  PNODEChunk = ^TNODEChunk;
+  TNODEChunk = record
+    name: array[0..255] of char; //name of node
+    position: TAffineVector;  //local...
+    scale: TAffineVector; //coord...
+    rotation: TGLVector; //system...
+    //array of node elements
+    //should be one of meshes or bones, support meshes only for now
+    meshes: PMESHChunk; //what 'kind' of node this is - if unrecognized, just use a Blitz3D pivot.
+    (*
+    not supprot yet
+    bones: PBONEChunk;
+    *)
+    keys: PKEYSChunk; //optional animation keys
+    nodes: PNODEChunk; //optional child nodes
+    animation: TANIMChunk; //optional animation
+    next: PNODEChunk; //point to the next node
+    level: Integer;
+  end;
+
+type
+  TB3DMaterial = class
+  public
+    MaterialData: TBRUSChunk;
+    constructor Create;
+    destructor Destroy; override;
+    function GetMaterialName: string;
+  end;
+
+  TB3DTexture = class
+  public
+    TextureData: TTEXSChunk;
+    constructor Create;
+    destructor Destroy; override;
+    function GetTextureName: string;
+  end;
+
+  TB3DNode = class
+  public
+    NodeData: PNODEChunk;
+    constructor Create;
+    destructor Destroy; override;
+    function GetNodeName: string;
+    procedure DestroyNodeData(Node: PNODEChunk);
+  end;
+
+  TFileB3D = class
+  private
+    fTextures: TStringList;
+    fMaterials: TStringList;
+    fNodes: TB3DNode;
+    procedure FreeLists;
+    function GetChunkType(const aChunk: TB3DChunk): TB3DChunkType;
+    function SkipChunk(aStream: TStream; const aChunk: TB3DChunk): Integer;
+    function ReadTextureChunk(aStream: TStream; const aChunk: TB3DChunk): Integer;
+    function ReadMaterialChunk(aStream: TStream; const aChunk: TB3DChunk): Integer;
+    function ReadNodeChunk(aStream: TStream; const aChunk: TB3DChunk; Node: PNODEChunk; level: Integer): Integer;
+    function ReadMeshChunk(aStream: TStream; const aChunk: TB3DChunk; Mesh: PMESHChunk): Integer;
+    function ReadVerticesChunk(aStream: TStream; const aChunk: TB3DChunk; Vertices: PVRTSChunk): Integer;
+    function ReadTrianglesChunk(aStream: TStream; const aChunk: TB3DChunk; Triangle: PTRISChunk): Integer;
+  public
+    constructor Create; virtual;
+    destructor Destroy; override;
+    procedure LoadFromStream(aStream : TStream);
+    //for test only
+    procedure Check;
+    
+    property Textures: TStringList read fTextures;
+    property Materials: TStringList read fMaterials;
+    property Nodes: TB3DNode read fNodes;
+  end;
+
+//-----------------------------------------------------------------------
+implementation
+//-----------------------------------------------------------------------
+
+constructor TB3DMaterial.Create;
+begin
+  inherited Create;
+  fillChar(MaterialData, sizeof(TBRUSChunk), 0);
+end;
+
+destructor TB3DMaterial.Destroy;
+begin
+  SetLength(MaterialData.texture_id, 0);
+  inherited Destroy;
+end;
+
+function TB3DMaterial.GetMaterialName: string;
+begin
+  SetString(Result, MaterialData.name, strlen(MaterialData.name));
+end;
+
+constructor TB3DTexture.Create;
+begin
+  inherited Create;
+  fillChar(TextureData, sizeof(TTEXSChunk), 0);
+end;
+
+destructor TB3DTexture.Destroy;
+begin
+  inherited Destroy;
+end;
+
+function TB3DTexture.GetTextureName: string;
+begin
+  SetString(Result, TextureData.fileName, strlen(TextureData.fileName));
+end;
+
+constructor TB3DNode.Create;
+begin
+  inherited Create;
+  NodeData := nil;
+end;
+
+destructor TB3DNode.Destroy;
+begin
+  DestroyNodeData(NodeData);
+  inherited Destroy;
+end;
+
+function TB3DNode.GetNodeName: string;
+begin
+  SetString(Result, NodeData^.name, strlen(NodeData^.name));
+end;
+
+procedure DeleteVertices(var aVertex: PVertexData);
+var
+  V: PVertexData;
+begin
+  while aVertex<>nil do
+  begin
+    SetLength(aVertex^.tex_coords, 0);
+    V := aVertex^.next;
+    freeMem(aVertex);
+    aVertex := nil;
+    DeleteVertices(V);
+  end;
+end;
+
+procedure DeleteTriangles(var aTriangle: PTRISChunk);
+var
+  T: PTRISChunk;
+begin
+  while aTriangle<>nil do
+  begin
+    SetLength(aTriangle^.vertex_id, 0);
+    T := aTriangle^.next;
+    freeMem(aTriangle);
+    aTriangle := nil;
+    DeleteTriangles(T);
+  end;
+end;
+
+procedure TB3DNode.DestroyNodeData(Node: PNODEChunk);
+var
+  oldNode, PNode: PNODEChunk;
+begin
+  PNode := Node;
+  while PNode<>nil do
+  begin
+    if PNode^.meshes<>nil then
+    begin
+      DeleteTriangles(PNode^.meshes^.triangles);
+      DeleteVertices(PNode^.meshes^.vertices.vertices);
+      freeMem(PNode^.meshes);
+      PNode^.meshes := nil;
+    end;
+    if PNode^.keys<>nil then
+      freeMem(PNode^.keys);
+    DestroyNodeData(PNode^.nodes);
+    oldNode := PNode;
+    PNode := PNode^.next;
+    freeMem(oldNode);
+  end;
+end;
+
+//------------------------------------------------------------------------------
+constructor TFileB3D.Create;
+begin
+  inherited Create;
+  fTextures := TStringList.Create;
+  fMaterials := TStringList.Create;
+  fNodes := TB3DNode.Create;
+end;
+
+destructor TFileB3D.Destroy;
+begin
+  FreeLists;
+  fTextures.free;
+  fMaterials.free;
+  fNodes.free;
+  inherited Destroy;
+end;
+
+function TFileB3D.GetChunkType(const aChunk: TB3DChunk): TB3DChunkType;
+begin
+  Result := bctUnKnown;
+  if StrLIComp(aChunk.chunk, 'BB3D', 4)=0 then
+    Result := bctHeader;
+  if StrLIComp(aChunk.chunk, 'TEXS', 4)=0 then
+    Result := bctTexture;
+  if StrLIComp(aChunk.chunk, 'BRUS', 4)=0 then
+    Result := bctBrush;
+  if StrLIComp(aChunk.chunk, 'NODE', 4)=0 then
+    Result := bctNode;
+  if StrLIComp(aChunk.chunk, 'VRTS', 4)=0 then
+    Result := bctVertex;
+  if StrLIComp(aChunk.chunk, 'BONE', 4)=0 then
+    Result := bctBone;
+  if StrLIComp(aChunk.chunk, 'KEYS', 4)=0 then
+    Result := bctKeyFrame;
+  if StrLIComp(aChunk.chunk, 'ANIM', 4)=0 then
+    Result := bctAnimation;
+  if StrLIComp(aChunk.chunk, 'MESH', 4)=0 then
+    Result := bctMesh;
+  if StrLIComp(aChunk.chunk, 'TRIS', 4)=0 then
+    Result := bctTriangle;
+end;
+
+function TFileB3D.SkipChunk(aStream: TStream; const aChunk: TB3DChunk): Integer;
+begin
+  aStream.Seek(aChunk.length, soFromCurrent);
+  Result := aChunk.length;
+end;
+
+function ReadString(aStream: TStream; buffer: PChar; MaxCount: Integer): Integer;
+begin
+  Result := 0;
+  while Result<MaxCount do
+  begin
+    aStream.Read(buffer[Result], sizeof(char));
+    Inc(result);
+    if buffer[result-1]=#0 then
+      break;
+  end;
+end;
+
+function TFileB3D.ReadTextureChunk(aStream: TStream; const aChunk: TB3DChunk): Integer;
+var
+  Texture: TB3DTexture;
+  Count: Integer;
+begin
+  Result := 0;
+  if aChunk.length<5 then
+    exit;
+  Count := 0;
+  while Count<aChunk.length do
+  begin
+    Texture := TB3DTexture.Create;
+    Inc(Count, ReadString(aStream, Texture.TextureData.fileName, 255));
+    Inc(Count, aStream.Read(Texture.TextureData.flags, sizeof(integer)));
+    Inc(Count, aStream.Read(Texture.TextureData.blend, sizeof(integer)));
+    Inc(Count, aStream.Read(Texture.TextureData.x_pos, sizeof(single)));
+    Inc(Count, aStream.Read(Texture.TextureData.y_pos, sizeof(single)));
+    Inc(Count, aStream.Read(Texture.TextureData.x_scale, sizeof(single)));
+    Inc(Count, aStream.Read(Texture.TextureData.y_scale, sizeof(single)));
+    Inc(Count, aStream.Read(Texture.TextureData.rotation, sizeof(single)));
+    fTextures.AddObject(Texture.GetTextureName, Texture);
+  end;
+  Result := fTextures.Count;
+end;
+
+function TFileB3D.ReadMaterialChunk(aStream: TStream; const aChunk: TB3DChunk): Integer;
+var
+  Material: TB3DMaterial;
+  Count, I: Integer;
+  TextureCount: Integer;
+begin
+  Result := 0;
+  if aChunk.length<5 then
+    exit;
+  Count := 0;
+  TextureCount := 0;
+  while Count<aChunk.length do
+  begin
+    Material := TB3DMaterial.Create;
+    if Count=0 then
+    begin
+      Inc(Count, aStream.Read(Material.MaterialData.n_texs, sizeof(integer)));
+      TextureCount := Material.MaterialData.n_texs;
+    end else
+      Material.MaterialData.n_texs := TextureCount;
+    Inc(Count, ReadString(aStream, Material.MaterialData.name, 255));
+    Inc(Count, aStream.Read(Material.MaterialData.red, sizeof(single)));
+    Inc(Count, aStream.Read(Material.MaterialData.green, sizeof(single)));
+    Inc(Count, aStream.Read(Material.MaterialData.blue, sizeof(single)));
+    Inc(Count, aStream.Read(Material.MaterialData.alpha, sizeof(single)));
+    Inc(Count, aStream.Read(Material.MaterialData.shininess, sizeof(single)));
+    Inc(Count, aStream.Read(Material.MaterialData.blend, sizeof(integer)));
+    Inc(Count, aStream.Read(Material.MaterialData.fx, sizeof(integer)));
+    SetLength(Material.MaterialData.texture_id, TextureCount);
+    for I:=0 to TextureCount-1 do
+      Inc(Count, aStream.Read(Material.MaterialData.texture_id[I], sizeof(Integer)));
+    fMaterials.AddObject(Material.GetMaterialName, Material);
+  end;
+  Result := fMaterials.Count;
+end;
+
+function TFileB3D.ReadMeshChunk(aStream: TStream; const aChunk: TB3DChunk; Mesh: PMESHChunk): Integer;
+var
+  C: TB3DChunk;
+  T: PTRISChunk;
+begin
+  Result := 0;
+  fillChar(Mesh^, sizeof(TMESHChunk), 0);
+  Mesh^.brush_id := -1;
+  Inc(Result, aStream.Read(Mesh^.brush_id, sizeof(Integer)));
+  T := nil;
+  while Result<aChunk.length do
+  begin
+    Inc(Result, aStream.Read(C, sizeof(TB3DChunk)));
+    case GetChunkType(C) of
+      bctVertex:
+      begin
+        Inc(Result, ReadVerticesChunk(aStream, C, @(Mesh^.vertices)));
+      end;
+      bctTriangle:
+      begin
+        if Mesh^.triangles=nil then
+        begin
+          GetMem(Mesh^.triangles, sizeof(TTRISChunk));
+          fillChar(Mesh^.triangles^, sizeof(TTRISChunk), 0);
+          Inc(Result, ReadTrianglesChunk(aStream, C, Mesh^.triangles));
+        end else
+        begin
+          if T=nil then
+          begin
+            GetMem(T, sizeof(TTRISChunk));
+            fillChar(T^, sizeof(TTRISChunk), 0);
+            Inc(Result, ReadTrianglesChunk(aStream, C, T));
+            Mesh^.triangles^.next := T;
+          end else
+          begin
+            GetMem(T^.next, sizeof(TTRISChunk));
+            fillChar(T^.next^, sizeof(TTRISChunk), 0);
+            Inc(Result, ReadTrianglesChunk(aStream, C, T^.next));
+            T := T^.next;
+          end;
+        end;
+      end;
+      else
+        inc(Result, SkipChunk(aStream, C));
+    end;
+  end;
+end;
+
+function TFileB3D.ReadVerticesChunk(aStream: TStream; const aChunk: TB3DChunk; Vertices: PVRTSChunk): Integer;
+var
+  v: PVertexData;
+  v1: PVertexData;
+  size: Integer;
+begin
+  Result := 0;
+  fillChar(Vertices^, sizeof(TVRTSChunk), 0);
+  Inc(Result, aStream.Read(Vertices^.flags, sizeof(Integer)));
+  Inc(Result, aStream.Read(Vertices^.tex_coord_sets, sizeof(Integer)));
+  Inc(Result, aStream.Read(Vertices^.tex_coord_set_size, sizeof(Integer)));
+  size := Vertices^.tex_coord_set_size*Vertices^.tex_coord_sets;
+  v := nil;
+  while Result<aChunk.length do
+  begin
+    if Vertices^.vertices=nil then
+    begin
+      GetMem(Vertices^.vertices, sizeof(TVertexData));
+      fillChar(vertices^.vertices^, sizeof(TVertexData), 0);
+    end else
+    begin
+      if v=nil then
+      begin
+        GetMem(v, sizeof(TVertexData));
+        fillChar(v^, sizeof(TVertexData), 0);
+        vertices^.vertices^.next := v;
+      end else
+      begin
+        GetMem(v^.next, sizeof(TVertexData));
+        fillChar(v^.next^, sizeof(TVertexData), 0);
+        v := v^.next;
+      end;
+    end;
+    if v=nil then
+      v1 := vertices^.vertices
+    else
+      v1 := v;
+    Inc(Result, aStream.Read(v1^.x, sizeof(single)));
+    Inc(Result, aStream.Read(v1^.y, sizeof(single)));
+    Inc(Result, aStream.Read(v1^.z, sizeof(single)));
+    //W3D Begin
+    if (Vertices^.flags and 1)>0 then begin
+      Inc(Result, aStream.Read(v1^.nx, sizeof(single)));
+      Inc(Result, aStream.Read(v1^.ny, sizeof(single)));
+      Inc(Result, aStream.Read(v1^.nz, sizeof(single)));
+    end;
+    if (Vertices^.flags and 2)>0 then begin
+      Inc(Result, aStream.Read(v1^.red, sizeof(single)));
+      Inc(Result, aStream.Read(v1^.green, sizeof(single)));
+      Inc(Result, aStream.Read(v1^.blue, sizeof(single)));
+      Inc(Result, aStream.Read(v1^.alpha, sizeof(single)));
+    end;
+    //W3D END
+    SetLength(v1^.tex_coords, size);
+    Inc(Result, aStream.Read(v1^.tex_coords[0], size*sizeof(single)));
+  end;
+end;
+
+function TFileB3D.ReadTrianglesChunk(aStream: TStream; const aChunk: TB3DChunk; Triangle: PTRISChunk): Integer;
+begin
+  Result := 0;
+  if Triangle=nil then
+  begin
+    GetMem(Triangle, sizeof(TTRISChunk));
+    fillChar(Triangle^, sizeof(TTRISChunk), 0);
+    Triangle^.brush_id := -1;
+  end;
+  Inc(Result, aStream.Read(Triangle^.brush_id, sizeof(Integer)));
+  SetLength(Triangle^.vertex_id, (aChunk.length-Result) div sizeof(Integer));
+  Inc(Result, aStream.Read(Triangle^.vertex_id[0], (aChunk.length-Result)));
+end;
+
+//read in only the mesh data, the keyframes and animation had been dropped
+function TFileB3D.ReadNodeChunk(aStream: TStream; const aChunk: TB3DChunk; Node: PNODEChunk; level: Integer): Integer;
+var
+  Count: Integer;
+  C: TB3DChunk;
+  N: PNODEChunk;
+begin
+  N := nil;
+  fillChar(Node^, sizeof(TNODEChunk), 0);
+  Node^.level := level;
+  Count := 0;
+  Inc(Count, ReadString(aStream, Node^.name, 255));
+  Inc(Count, aStream.Read(Node^.position.X, sizeof(TAffineVector)));
+  Inc(Count, aStream.Read(Node^.scale.X, sizeof(TAffineVector)));
+  Inc(Count, aStream.Read(Node^.rotation.X, sizeof(TGLVector)));
+  while Count<aChunk.length do
+  begin
+    Inc(Count, aStream.Read(C, sizeof(TB3DChunk)));
+    case GetChunkType(C) of
+      bctMesh:
+      begin
+        GetMem(Node^.meshes, sizeof(TMESHChunk));
+        Inc(Count, ReadMeshChunk(aStream, C, Node^.meshes));
+      end;
+      bctKeyframe:
+      begin
+        Inc(Count, SkipChunk(aStream, C));
+      end;
+      bctNode:
+      begin
+        if N=nil then
+        begin
+          GetMem(N, sizeof(TNODEChunk));
+          fillChar(N^, sizeof(TNODEChunk), 0);
+          Inc(Count, ReadNodeChunk(aStream, C, N, level + 1));
+          Node^.next := N;
+        end else
+        begin
+          GetMem(N^.next, sizeof(TNODEChunk));
+          fillChar(N^.next^, sizeof(TNODEChunk), 0);
+          Inc(Count, ReadNodeChunk(aStream, C, N^.next, level + 1));
+          N := N^.next;
+        end;
+      end;
+      bctAnimation:
+      begin
+        Inc(Count, SkipChunk(aStream, C));
+      end;
+      else
+        Inc(Count, SkipChunk(aStream, C));
+    end;
+  end;
+  Result := Count;
+end;
+
+procedure TFileB3D.LoadFromStream(aStream : TStream);
+var
+  aChunk: TB3DChunk;
+  FileSize: Integer;
+begin
+  FileSize := aStream.Size;
+  while aStream.Position<FileSize do
+  begin
+    aStream.Read(aChunk, sizeof(TB3DChunk));
+    case GetChunkType(aChunk) of
+      bctHeader:
+      begin
+        FileSize := aChunk.length - sizeof(TB3DChunk) - sizeof(TBB3DChunk);
+        aStream.Seek(sizeof(TBB3DChunk), soFromCurrent);
+      end;
+      bctTexture:
+      begin
+        ReadTextureChunk(aStream, aChunk);
+      end;
+      bctBrush:
+      begin
+        ReadMaterialChunk(aStream, aChunk);
+      end;
+      bctNode:
+      begin
+        if fNodes.NodeData=nil then
+        begin
+          GetMem(fNodes.NodeData, sizeof(TNODEChunk));
+          ReadNodeChunk(aStream, aChunk, fNodes.NodeData, 0);
+        end;
+      end;
+      else
+        SkipChunk(aStream, aChunk);
+    end;
+  end;
+end;
+
+procedure TFileB3D.FreeLists;
+begin
+  while fTextures.Count>0 do
+  begin
+    fTextures.Objects[0].free;
+    ftextures.Delete(0);
+  end;
+  while fMaterials.Count>0 do
+  begin
+    fMaterials.Objects[0].free;
+    fMaterials.Delete(0);
+  end;
+end;
+
+//for test only
+procedure TFileB3D.Check;
+var
+  NodeLevel: Integer;
+//  NodeCount: Integer;
+  Node: PNODEChunk;
+//  VerticesCount: Integer;
+//  FaceCount: Integer;
+  Face: PTRISChunk;
+  Vertex: PVertexData;
+begin
+  NodeLevel := 0;
+//  NodeCount := 0;
+//  VerticesCount := 0;
+//  FaceCount := 0;
+  Node := fNodes.NodeData;
+  while Node<>nil do
+  begin
+    if Node^.meshes<>nil then
+//      Inc(NodeCount);
+    if Node^.level>NodeLevel then
+      NodeLevel := Node^.level;
+    if Node^.meshes<>nil then
+    begin
+      Vertex := Node^.meshes.vertices.vertices;
+      while Vertex<>nil do
+      begin
+//        Inc(VerticesCount);
+        Vertex := Vertex.next;
+      end;
+      Face := Node^.meshes.triangles;
+      while Face<>nil do
+      begin
+//        Inc(FaceCount);
+        Face := Face.next;
+      end;
+    end;
+    Node := Node^.next;
+  end;
+
+  //MessageBeep(FaceCount);
+  //MessageBeep(VerticesCount);
+  //MessageBeep(NodeLevel);
+  //MessageBeep(NodeCount);
+end;
+
+end.

+ 1 - 1
Sourcex/Formatx.DDSImage.pas

@@ -30,7 +30,7 @@ uses
   GLScene.TextureFormat,
   GXS.FileDDS,
 
-  Formats.DXTC;
+  Formatx.DXTC;
 
 
 type

+ 1266 - 0
Sourcex/Formatx.DXTC.pas

@@ -0,0 +1,1266 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.DXTC;
+
+(*
+  DXTC (also S3TC) decoding.
+  Adapted from DevIL image library (http://openil.sourceforge.net)
+*)
+
+interface
+
+{.$I GLScene.Defines.inc}
+
+{$Z4}  // Minimum enum size = dword
+
+uses
+  Winapi.OpenGL,
+  Winapi.OpenGLext,
+  System.SysUtils,
+
+  GLScene.TextureFormat;
+
+const
+  DDSD_CAPS = $00000001;
+  DDSD_HEIGHT = $00000002;
+  DDSD_WIDTH = $00000004;
+  DDSD_PITCH = $00000008;
+  DDSD_PIXELFORMAT = $00001000;
+  DDSD_MIPMAPCOUNT = $00020000;
+  DDSD_LINEARSIZE = $00080000;
+  DDSD_DEPTH = $00800000;
+
+  DDPF_ALPHAPIXELS = $00000001;
+  DDPF_A = $00000002;
+  DDPF_FOURCC = $00000004;
+  DDPF_RGB = $00000040;
+  DDPF_RGBA = $00000041;
+  DDPF_L = $00020000;
+  DDPF_LA = $00020001;
+
+  DDSCAPS_COMPLEX = $00000008;
+  DDSCAPS_TEXTURE = $00001000;
+  DDSCAPS_MIPMAP = $00400000;
+
+  DDSCAPS2_CUBEMAP = $00000200;
+  DDSCAPS2_CUBEMAP_POSITIVEX = $00000400;
+  DDSCAPS2_CUBEMAP_NEGATIVEX = $00000800;
+  DDSCAPS2_CUBEMAP_POSITIVEY = $00001000;
+  DDSCAPS2_CUBEMAP_NEGATIVEY = $00002000;
+  DDSCAPS2_CUBEMAP_POSITIVEZ = $00004000;
+  DDSCAPS2_CUBEMAP_NEGATIVEZ = $00008000;
+  DDSCAPS2_VOLUME = $00200000;
+
+type
+  TDDPIXELFORMAT = record
+    dwSize, dwFlags, dwFourCC, dwRGBBitCount, dwRBitMask, dwGBitMask, dwBBitMask,
+      dwRGBAlphaBitMask: Cardinal;
+  end;
+
+  TDDSURFACEDESC2 = record
+    dwSize, dwFlags, dwHeight, dwWidth, dwPitchOrLinearSize,
+    (* The number of bytes per scan line in an
+      uncompressed texture; the total number of bytes
+      in the top level texture for a compressed texture. *)
+    dwDepth, dwMipMapCount: Cardinal;
+    dwReserved1: array [0 .. 10] of Cardinal;
+    ddpf: TDDPIXELFORMAT;
+    dwCaps, dwCaps2, dwCaps3, dwCaps4: Cardinal;
+    dwReserved2: Cardinal;
+  end;
+
+  TDDSHeader = record
+    Magic: Cardinal;
+    SurfaceFormat: TDDSURFACEDESC2;
+  end;
+
+  DXTColBlock = record
+    col0: Word;
+    col1: Word;
+    row: array [0 .. 3] of Byte;
+  end;
+
+  PDXTColBlock = ^DXTColBlock;
+
+  DXT3AlphaBlock = record
+    row: array [0 .. 3] of Word;
+  end;
+
+  PDXT3AlphaBlock = ^DXT3AlphaBlock;
+
+  DXT5AlphaBlock = record
+    alpha0: Byte;
+    alpha1: Byte;
+    row: array [0 .. 5] of Byte;
+  end;
+
+  PDXT5AlphaBlock = ^DXT5AlphaBlock;
+
+const
+  // TDXGI_FORMAT =
+  // (
+  DXGI_FORMAT_FORCE_UINT = -1;
+  DXGI_FORMAT_UNKNOWN = 0;
+  DXGI_FORMAT_R32G32B32A32_TYPELESS = 1;
+  DXGI_FORMAT_R32G32B32A32_FLOAT = 2;
+  DXGI_FORMAT_R32G32B32A32_UINT = 3;
+  DXGI_FORMAT_R32G32B32A32_SINT = 4;
+  DXGI_FORMAT_R32G32B32_TYPELESS = 5;
+  DXGI_FORMAT_R32G32B32_FLOAT = 6;
+  DXGI_FORMAT_R32G32B32_UINT = 7;
+  DXGI_FORMAT_R32G32B32_SINT = 8;
+  DXGI_FORMAT_R16G16B16A16_TYPELESS = 9;
+  DXGI_FORMAT_R16G16B16A16_FLOAT = 10;
+  DXGI_FORMAT_R16G16B16A16_UNORM = 11;
+  DXGI_FORMAT_R16G16B16A16_UINT = 12;
+  DXGI_FORMAT_R16G16B16A16_SNORM = 13;
+  DXGI_FORMAT_R16G16B16A16_SINT = 14;
+  DXGI_FORMAT_R32G32_TYPELESS = 15;
+  DXGI_FORMAT_R32G32_FLOAT = 16;
+  DXGI_FORMAT_R32G32_UINT = 17;
+  DXGI_FORMAT_R32G32_SINT = 18;
+  DXGI_FORMAT_R32G8X24_TYPELESS = 19;
+  DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20;
+  DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21;
+  DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22;
+  DXGI_FORMAT_R10G10B10A2_TYPELESS = 23;
+  DXGI_FORMAT_R10G10B10A2_UNORM = 24;
+  DXGI_FORMAT_R10G10B10A2_UINT = 25;
+  DXGI_FORMAT_R11G11B10_FLOAT = 26;
+  DXGI_FORMAT_R8G8B8A8_TYPELESS = 27;
+  DXGI_FORMAT_R8G8B8A8_UNORM = 28;
+  DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29;
+  DXGI_FORMAT_R8G8B8A8_UINT = 30;
+  DXGI_FORMAT_R8G8B8A8_SNORM = 31;
+  DXGI_FORMAT_R8G8B8A8_SINT = 32;
+  DXGI_FORMAT_R16G16_TYPELESS = 33;
+  DXGI_FORMAT_R16G16_FLOAT = 34;
+  DXGI_FORMAT_R16G16_UNORM = 35;
+  DXGI_FORMAT_R16G16_UINT = 36;
+  DXGI_FORMAT_R16G16_SNORM = 37;
+  DXGI_FORMAT_R16G16_SINT = 38;
+  DXGI_FORMAT_R32_TYPELESS = 39;
+  DXGI_FORMAT_D32_FLOAT = 40;
+  DXGI_FORMAT_R32_FLOAT = 41;
+  DXGI_FORMAT_R32_UINT = 42;
+  DXGI_FORMAT_R32_SINT = 43;
+  DXGI_FORMAT_R24G8_TYPELESS = 44;
+  DXGI_FORMAT_D24_UNORM_S8_UINT = 45;
+  DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46;
+  DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47;
+  DXGI_FORMAT_R8G8_TYPELESS = 48;
+  DXGI_FORMAT_R8G8_UNORM = 49;
+  DXGI_FORMAT_R8G8_UINT = 50;
+  DXGI_FORMAT_R8G8_SNORM = 51;
+  DXGI_FORMAT_R8G8_SINT = 52;
+  DXGI_FORMAT_R16_TYPELESS = 53;
+  DXGI_FORMAT_R16_FLOAT = 54;
+  DXGI_FORMAT_D16_UNORM = 55;
+  DXGI_FORMAT_R16_UNORM = 56;
+  DXGI_FORMAT_R16_UINT = 57;
+  DXGI_FORMAT_R16_SNORM = 58;
+  DXGI_FORMAT_R16_SINT = 59;
+  DXGI_FORMAT_R8_TYPELESS = 60;
+  DXGI_FORMAT_R8_UNORM = 61;
+  DXGI_FORMAT_R8_UINT = 62;
+  DXGI_FORMAT_R8_SNORM = 63;
+  DXGI_FORMAT_R8_SINT = 64;
+  DXGI_FORMAT_A8_UNORM = 65;
+  DXGI_FORMAT_R1_UNORM = 66;
+  DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67;
+  DXGI_FORMAT_R8G8_B8G8_UNORM = 68;
+  DXGI_FORMAT_G8R8_G8B8_UNORM = 69;
+  DXGI_FORMAT_BC1_TYPELESS = 70;
+  DXGI_FORMAT_BC1_UNORM = 71;
+  DXGI_FORMAT_BC1_UNORM_SRGB = 72;
+  DXGI_FORMAT_BC2_TYPELESS = 73;
+  DXGI_FORMAT_BC2_UNORM = 74;
+  DXGI_FORMAT_BC2_UNORM_SRGB = 75;
+  DXGI_FORMAT_BC3_TYPELESS = 76;
+  DXGI_FORMAT_BC3_UNORM = 77;
+  DXGI_FORMAT_BC3_UNORM_SRGB = 78;
+  DXGI_FORMAT_BC4_TYPELESS = 79;
+  DXGI_FORMAT_BC4_UNORM = 80;
+  DXGI_FORMAT_BC4_SNORM = 81;
+  DXGI_FORMAT_BC5_TYPELESS = 82;
+  DXGI_FORMAT_BC5_UNORM = 83;
+  DXGI_FORMAT_BC5_SNORM = 84;
+  DXGI_FORMAT_B5G6R5_UNORM = 85;
+  DXGI_FORMAT_B5G5R5A1_UNORM = 86;
+  DXGI_FORMAT_B8G8R8A8_UNORM = 87;
+  DXGI_FORMAT_B8G8R8X8_UNORM = 88;
+  DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89;
+  DXGI_FORMAT_B8G8R8A8_TYPELESS = 90;
+  DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91;
+  DXGI_FORMAT_B8G8R8X8_TYPELESS = 92;
+  DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93;
+  DXGI_FORMAT_BC6H_TYPELESS = 94;
+  DXGI_FORMAT_BC6H_UF16 = 95;
+  DXGI_FORMAT_BC6H_SF16 = 96;
+  DXGI_FORMAT_BC7_TYPELESS = 97;
+  DXGI_FORMAT_BC7_UNORM = 98;
+  DXGI_FORMAT_BC7_UNORM_SRGB = 99;
+  // );
+
+  // TD3D11_RESOURCE_DIMENSION =
+  // (
+  D3D11_RESOURCE_DIMENSION_UNKNOWN = 0;
+  D3D11_RESOURCE_DIMENSION_BUFFER = 1;
+  D3D11_RESOURCE_DIMENSION_TEXTURE1D = 2;
+  D3D11_RESOURCE_DIMENSION_TEXTURE2D = 3;
+  D3D11_RESOURCE_DIMENSION_TEXTURE3D = 4;
+  // );
+
+type
+  TDDS_HEADER_DXT10 = record
+    dxgiFormat: Integer; // TDXGI_FORMAT;
+    resourceDimension: Integer; // TD3D11_RESOURCE_DIMENSION;
+    miscFlag: Cardinal;
+    arraySize: Cardinal;
+    reserved: Cardinal;
+  end;
+
+  TFOURCC = array [0 .. 3] of AnsiChar;
+
+const
+  FOURCC_UNKNOWN = 0;
+  FOURCC_R8G8B8 = 20;
+  FOURCC_A8R8G8B8 = 21;
+  FOURCC_X8R8G8B8 = 22;
+  FOURCC_R5G6B5 = 23;
+  FOURCC_X1R5G5B5 = 24;
+  FOURCC_A1R5G5B5 = 25;
+  FOURCC_A4R4G4B4 = 26;
+  FOURCC_R3G3B2 = 27;
+  FOURCC_A8 = 28;
+  FOURCC_A8R3G3B2 = 29;
+  FOURCC_X4R4G4B4 = 30;
+  FOURCC_A2B10G10R10 = 31;
+  FOURCC_A8B8G8R8 = 32;
+  FOURCC_X8B8G8R8 = 33;
+  FOURCC_G16R16 = 34;
+  FOURCC_A2R10G10B10 = 35;
+  FOURCC_A16B16G16R16 = 36;
+
+  FOURCC_L8 = 50;
+  FOURCC_A8L8 = 51;
+  FOURCC_A4L4 = 52;
+  FOURCC_DXT1 = $31545844;
+  FOURCC_DXT2 = $32545844;
+  FOURCC_DXT3 = $33545844;
+  FOURCC_DXT4 = $34545844;
+  FOURCC_DXT5 = $35545844;
+  FOURCC_ATI1 = $31495441;
+  FOURCC_ATI2 = $32495441;
+
+  FOURCC_D16_LOCKABLE = 70;
+  FOURCC_D32 = 71;
+  FOURCC_D24X8 = 77;
+  FOURCC_D16 = 80;
+
+  FOURCC_D32F_LOCKABLE = 82;
+
+  FOURCC_L16 = 81;
+
+  // Floating point surface formats
+
+  // s10e5 formats (16-bits per channel)
+  FOURCC_R16F = 111;
+  FOURCC_G16R16F = 112;
+  FOURCC_A16B16G16R16F = 113;
+
+  // IEEE s23e8 formats (32-bits per channel)
+  FOURCC_R32F = 114;
+  FOURCC_G32R32F = 115;
+  FOURCC_A32B32G32R32F = 116;
+
+  // DX10 header indicator
+  FOURCC_DX10 = $47495844;
+
+type
+  TGLImageDataFormat = record
+    ColorFlag: Cardinal;
+    RBits, GBits, BBits, ABits: Cardinal;
+    colorFormat: Cardinal;
+    TexFormat: TGLinternalFormat;
+    dType: Cardinal;
+  end;
+
+const
+  cImageDataFormat8bits: array [0 .. 3] of TGLImageDataFormat = ((ColorFlag: DDPF_RGB; RBits: $E0;
+    GBits: $1C; BBits: $03; ABits: $00; colorFormat: GL_RGB; TexFormat: tfR3_G3_B2;
+    dType: GL_UNSIGNED_BYTE_3_3_2),
+
+    (ColorFlag: DDPF_LA; RBits: $0F; GBits: $00; BBits: $00; ABits: $F0;
+    colorFormat: GL_LUMINANCE_ALPHA; TexFormat: tfLUMINANCE4_ALPHA4; dType: GL_UNSIGNED_BYTE),
+
+    (ColorFlag: DDPF_A; RBits: $00; GBits: $00; BBits: $00; ABits: $FF; colorFormat: GL_ALPHA;
+    TexFormat: tfALPHA8; dType: GL_UNSIGNED_BYTE),
+
+    (ColorFlag: DDPF_L; RBits: $FF; GBits: $00; BBits: $00; ABits: $00; colorFormat: GL_LUMINANCE;
+    TexFormat: tfLUMINANCE8; dType: GL_UNSIGNED_BYTE));
+
+  cImageDataFormat16bits: array [0 .. 4] of TGLImageDataFormat = ((ColorFlag: DDPF_RGBA;
+    RBits: $0F00; GBits: $F0; BBits: $0F; ABits: $F000; colorFormat: GL_BGRA; TexFormat: tfRGBA4;
+    dType: GL_UNSIGNED_SHORT_4_4_4_4_REV),
+
+    (ColorFlag: DDPF_RGB; RBits: $F800; GBits: $07E0; BBits: $1F; ABits: $00; colorFormat: GL_RGB;
+    TexFormat: tfRGB5; dType: GL_UNSIGNED_SHORT_5_6_5),
+
+    (ColorFlag: DDPF_L; RBits: $FFFF; GBits: $00; BBits: $00; ABits: $00; colorFormat: GL_LUMINANCE;
+    TexFormat: tfLUMINANCE16; dType: GL_UNSIGNED_SHORT),
+
+    (ColorFlag: DDPF_LA; RBits: $FF; GBits: $00; BBits: $00; ABits: $FF00;
+    colorFormat: GL_LUMINANCE_ALPHA; TexFormat: tfLUMINANCE8_ALPHA8; dType: GL_UNSIGNED_BYTE),
+
+    (ColorFlag: DDPF_RGBA; RBits: $7C00; GBits: $03E0; BBits: $1F; ABits: $8000;
+    colorFormat: GL_BGRA; TexFormat: tfRGB5_A1; dType: GL_UNSIGNED_SHORT_1_5_5_5_REV));
+
+  cImageDataFormat24bits: array [0 .. 0] of TGLImageDataFormat = ((ColorFlag: DDPF_RGB;
+    RBits: $FF0000; GBits: $FF00; BBits: $FF; ABits: $00; colorFormat: GL_BGR; TexFormat: tfRGB8;
+    dType: GL_UNSIGNED_BYTE));
+
+  cImageDataFormat32bits: array [0 .. 6] of TGLImageDataFormat = ((ColorFlag: DDPF_RGBA; RBits: $FF;
+    GBits: $FF00; BBits: $FF0000; ABits: $FF000000; colorFormat: GL_RGBA; TexFormat: tfRGBA8;
+    dType: GL_UNSIGNED_BYTE),
+
+    (ColorFlag: DDPF_RGBA; RBits: $FF0000; GBits: $FF00; BBits: $FF; ABits: $FF000000;
+    colorFormat: GL_BGRA; TexFormat: tfRGBA8; dType: GL_UNSIGNED_BYTE),
+
+    (ColorFlag: DDPF_RGBA; RBits: $3FF00000; GBits: $0FFC00; BBits: $03FF; ABits: $0C0000000;
+    colorFormat: GL_RGBA; TexFormat: tfRGB10_A2; dType: GL_UNSIGNED_INT_2_10_10_10_REV),
+
+    (ColorFlag: DDPF_RGBA; RBits: $03FF; GBits: $FFC00; BBits: $3FF00000; ABits: $C0000000;
+    colorFormat: GL_BGRA; TexFormat: tfRGB10_A2; dType: GL_UNSIGNED_INT_2_10_10_10_REV),
+
+    (ColorFlag: DDPF_RGBA; RBits: $FF0000; GBits: $FF00; BBits: $FF; ABits: $FF000000;
+    colorFormat: GL_BGRA; TexFormat: tfRGB8; dType: GL_UNSIGNED_INT_8_8_8_8),
+
+    (ColorFlag: DDPF_RGBA; RBits: $FF; GBits: $FF00; BBits: $FF0000; ABits: $FF000000;
+    colorFormat: GL_RGBA; TexFormat: tfRGB8; dType: GL_UNSIGNED_INT_8_8_8_8),
+
+    (ColorFlag: DDPF_RGB; RBits: $FFFF; GBits: $FFFF0000; BBits: $00; ABits: $00;
+    colorFormat: GL_RG; TexFormat: tfRG16; dType: GL_UNSIGNED_SHORT));
+
+procedure DecodeDXT1toBitmap32(encData, decData: PByteArray; w, h: Integer; var trans: Boolean);
+procedure DecodeDXT3toBitmap32(encData, decData: PByteArray; w, h: Integer);
+procedure DecodeDXT5toBitmap32(encData, decData: PByteArray; w, h: Integer);
+procedure flip_blocks_dxtc1(data: PGLubyte; numBlocks: Integer);
+procedure flip_blocks_dxtc3(data: PGLubyte; numBlocks: Integer);
+procedure flip_blocks_dxtc5(data: PGLubyte; numBlocks: Integer);
+procedure flip_dxt5_alpha(block: PDXT5AlphaBlock);
+
+function DDSHeaderToGLEnum(const DX9header: TDDSHeader; const DX11header: TDDS_HEADER_DXT10;
+  const useDX11: Boolean; out iFormat: TGLinternalFormat; out colorFormat: Cardinal;
+  out dataType: Cardinal; out bpe: Integer): Boolean;
+
+function GLEnumToDDSHeader(var DX9header: TDDSHeader; var DX11header: TDDS_HEADER_DXT10;
+  const useDX11: Boolean; const iFormat: TGLinternalFormat; const colorFormat: Cardinal;
+  const dataType: Cardinal; const bpe: Integer): Boolean;
+
+function FindDDSCompatibleDataFormat(const iFormat: TGLinternalFormat; out colorFormat: Cardinal;
+  out dataType: Cardinal): Boolean;
+
+// --------------------------------------------------
+implementation
+// --------------------------------------------------
+
+procedure DecodeColor565(col: Word; out r, g, b: Byte);
+begin
+  r := col and $1F;
+  g := (col shr 5) and $3F;
+  b := (col shr 11) and $1F;
+end;
+
+procedure DecodeDXT1toBitmap32(encData, decData: PByteArray; w, h: Integer; var trans: Boolean);
+var
+  x, y, i, j, k, select: Integer;
+  col0, col1: Word;
+  colors: array [0 .. 3] of array [0 .. 3] of Byte;
+  bitmask: Cardinal;
+  temp: PGLubyte;
+  r0, g0, b0, r1, g1, b1: Byte;
+begin
+  trans := False;
+
+  if not(Assigned(encData) and Assigned(decData)) then
+    exit;
+
+  temp := PGLubyte(encData);
+  for y := 0 to (h div 4) - 1 do
+  begin
+    for x := 0 to (w div 4) - 1 do
+    begin
+      col0 := PWord(temp)^;
+      Inc(temp, 2);
+      col1 := PWord(temp)^;
+      Inc(temp, 2);
+      bitmask := PCardinal(temp)^;
+      Inc(temp, 4);
+
+      DecodeColor565(col0, r0, g0, b0);
+      DecodeColor565(col1, r1, g1, b1);
+
+      colors[0][0] := r0 shl 3;
+      colors[0][1] := g0 shl 2;
+      colors[0][2] := b0 shl 3;
+      colors[0][3] := $FF;
+      colors[1][0] := r1 shl 3;
+      colors[1][1] := g1 shl 2;
+      colors[1][2] := b1 shl 3;
+      colors[1][3] := $FF;
+
+      if col0 > col1 then
+      begin
+        colors[2][0] := (2 * colors[0][0] + colors[1][0] + 1) div 3;
+        colors[2][1] := (2 * colors[0][1] + colors[1][1] + 1) div 3;
+        colors[2][2] := (2 * colors[0][2] + colors[1][2] + 1) div 3;
+        colors[2][3] := $FF;
+        colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
+        colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
+        colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
+        colors[3][3] := $FF;
+      end
+      else
+      begin
+        trans := True;
+        colors[2][0] := (colors[0][0] + colors[1][0]) div 2;
+        colors[2][1] := (colors[0][1] + colors[1][1]) div 2;
+        colors[2][2] := (colors[0][2] + colors[1][2]) div 2;
+        colors[2][3] := $FF;
+        colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
+        colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
+        colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
+        colors[3][3] := 0;
+      end;
+
+      k := 0;
+      for j := 0 to 3 do
+      begin
+        for i := 0 to 3 do
+        begin
+          select := (bitmask and (3 shl (k * 2))) shr (k * 2);
+          if ((4 * x + i) < w) and ((4 * y + j) < h) then
+            PCardinal(@decData[((4 * y + j) * w + (4 * x + i)) * 4])^ := Cardinal(colors[select]);
+          Inc(k);
+        end;
+      end;
+
+    end;
+  end;
+end;
+
+procedure DecodeDXT3toBitmap32(encData, decData: PByteArray; w, h: Integer);
+var
+  x, y, i, j, k, select: Integer;
+  col0, col1, wrd: Word;
+  colors: array [0 .. 3] of array [0 .. 3] of Byte;
+  bitmask, offset: Cardinal;
+  temp: PGLubyte;
+  r0, g0, b0, r1, g1, b1: Byte;
+  alpha: array [0 .. 3] of Word;
+begin
+  if not(Assigned(encData) and Assigned(decData)) then
+    exit;
+
+  temp := PGLubyte(encData);
+  for y := 0 to (h div 4) - 1 do
+  begin
+    for x := 0 to (w div 4) - 1 do
+    begin
+      alpha[0] := PWord(temp)^;
+      Inc(temp, 2);
+      alpha[1] := PWord(temp)^;
+      Inc(temp, 2);
+      alpha[2] := PWord(temp)^;
+      Inc(temp, 2);
+      alpha[3] := PWord(temp)^;
+      Inc(temp, 2);
+      col0 := PWord(temp)^;
+      Inc(temp, 2);
+      col1 := PWord(temp)^;
+      Inc(temp, 2);
+      bitmask := PCardinal(temp)^;
+      Inc(temp, 4);
+
+      DecodeColor565(col0, r0, g0, b0);
+      DecodeColor565(col1, r1, g1, b1);
+
+      colors[0][0] := r0 shl 3;
+      colors[0][1] := g0 shl 2;
+      colors[0][2] := b0 shl 3;
+      colors[0][3] := $FF;
+      colors[1][0] := r1 shl 3;
+      colors[1][1] := g1 shl 2;
+      colors[1][2] := b1 shl 3;
+      colors[1][3] := $FF;
+      colors[2][0] := (2 * colors[0][0] + colors[1][0] + 1) div 3;
+      colors[2][1] := (2 * colors[0][1] + colors[1][1] + 1) div 3;
+      colors[2][2] := (2 * colors[0][2] + colors[1][2] + 1) div 3;
+      colors[2][3] := $FF;
+      colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
+      colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
+      colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
+      colors[3][3] := $FF;
+
+      k := 0;
+      for j := 0 to 3 do
+      begin
+        for i := 0 to 3 do
+        begin
+          select := (bitmask and (3 shl (k * 2))) shr (k * 2);
+          if ((4 * x + i) < w) and ((4 * y + j) < h) then
+            PCardinal(@decData[((4 * y + j) * w + (4 * x + i)) * 4])^ := Cardinal(colors[select]);
+          Inc(k);
+        end;
+      end;
+
+      for j := 0 to 3 do
+      begin
+        wrd := alpha[j];
+        for i := 0 to 3 do
+        begin
+          if (((4 * x + i) < w) and ((4 * y + j) < h)) then
+          begin
+            offset := ((4 * y + j) * w + (4 * x + i)) * 4 + 3;
+            decData[offset] := wrd and $0F;
+            decData[offset] := decData[offset] or (decData[offset] shl 4);
+          end;
+          wrd := wrd shr 4;
+        end;
+      end;
+
+    end;
+  end;
+end;
+
+procedure DecodeDXT5toBitmap32(encData, decData: PByteArray; w, h: Integer);
+var
+  x, y, i, j, k, select: Integer;
+  col0, col1: Word;
+  colors: array [0 .. 3] of array [0 .. 3] of Byte;
+  bits, bitmask, offset: Cardinal;
+  temp, alphamask: PGLubyte;
+  r0, g0, b0, r1, g1, b1: Byte;
+  alphas: array [0 .. 7] of Byte;
+begin
+  if not(Assigned(encData) and Assigned(decData)) then
+    exit;
+
+  temp := PGLubyte(encData);
+  for y := 0 to (h div 4) - 1 do
+  begin
+    for x := 0 to (w div 4) - 1 do
+    begin
+      alphas[0] := temp^;
+      Inc(temp);
+      alphas[1] := temp^;
+      Inc(temp);
+      alphamask := temp;
+      Inc(temp, 6);
+      col0 := PWord(temp)^;
+      Inc(temp, 2);
+      col1 := PWord(temp)^;
+      Inc(temp, 2);
+      bitmask := PCardinal(temp)^;
+      Inc(temp, 4);
+
+      DecodeColor565(col0, r0, g0, b0);
+      DecodeColor565(col1, r1, g1, b1);
+
+      colors[0][0] := r0 shl 3;
+      colors[0][1] := g0 shl 2;
+      colors[0][2] := b0 shl 3;
+      colors[0][3] := $FF;
+      colors[1][0] := r1 shl 3;
+      colors[1][1] := g1 shl 2;
+      colors[1][2] := b1 shl 3;
+      colors[1][3] := $FF;
+      colors[2][0] := (2 * colors[0][0] + colors[1][0] + 1) div 3;
+      colors[2][1] := (2 * colors[0][1] + colors[1][1] + 1) div 3;
+      colors[2][2] := (2 * colors[0][2] + colors[1][2] + 1) div 3;
+      colors[2][3] := $FF;
+      colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
+      colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
+      colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
+      colors[3][3] := $FF;
+
+      k := 0;
+      for j := 0 to 3 do
+      begin
+        for i := 0 to 3 do
+        begin
+          select := (bitmask and (3 shl (k * 2))) shr (k * 2);
+          if ((4 * x + i) < w) and ((4 * y + j) < h) then
+            PCardinal(@decData[((4 * y + j) * w + (4 * x + i)) * 4])^ := Cardinal(colors[select]);
+          Inc(k);
+        end;
+      end;
+
+      if (alphas[0] > alphas[1]) then
+      begin
+        alphas[2] := (6 * alphas[0] + 1 * alphas[1] + 3) div 7;
+        alphas[3] := (5 * alphas[0] + 2 * alphas[1] + 3) div 7;
+        alphas[4] := (4 * alphas[0] + 3 * alphas[1] + 3) div 7;
+        alphas[5] := (3 * alphas[0] + 4 * alphas[1] + 3) div 7;
+        alphas[6] := (2 * alphas[0] + 5 * alphas[1] + 3) div 7;
+        alphas[7] := (1 * alphas[0] + 6 * alphas[1] + 3) div 7;
+      end
+      else
+      begin
+        alphas[2] := (4 * alphas[0] + 1 * alphas[1] + 2) div 5;
+        alphas[3] := (3 * alphas[0] + 2 * alphas[1] + 2) div 5;
+        alphas[4] := (2 * alphas[0] + 3 * alphas[1] + 2) div 5;
+        alphas[5] := (1 * alphas[0] + 4 * alphas[1] + 2) div 5;
+        alphas[6] := 0;
+        alphas[7] := $FF;
+      end;
+
+      bits := PCardinal(alphamask)^;
+      for j := 0 to 1 do
+      begin
+        for i := 0 to 3 do
+        begin
+          if (((4 * x + i) < w) and ((4 * y + j) < h)) then
+          begin
+            offset := ((4 * y + j) * w + (4 * x + i)) * 4 + 3;
+            decData[offset] := alphas[bits and 7];
+          end;
+          bits := bits shr 3;
+        end;
+      end;
+
+      Inc(alphamask, 3);
+      bits := PCardinal(alphamask)^;
+      for j := 2 to 3 do
+      begin
+        for i := 0 to 3 do
+        begin
+          if (((4 * x + i) < w) and ((4 * y + j) < h)) then
+          begin
+            offset := ((4 * y + j) * w + (4 * x + i)) * 4 + 3;
+            decData[offset] := alphas[bits and 7];
+          end;
+          bits := bits shr 3;
+        end;
+      end;
+
+    end;
+  end;
+end;
+
+//==============================================================
+procedure flip_blocks_dxtc1(data: PGLubyte; numBlocks: Integer);
+var
+  curblock: PDXTColBlock;
+  temp: Byte;
+  i: Integer;
+begin
+  curblock := PDXTColBlock(data);
+  for i := 0 to numBlocks - 1 do
+  begin
+    temp := curblock.row[0];
+    curblock.row[0] := curblock.row[3];
+    curblock.row[3] := temp;
+    temp := curblock.row[1];
+    curblock.row[1] := curblock.row[2];
+    curblock.row[2] := temp;
+
+    Inc(curblock);
+  end;
+end;
+
+// flip a DXT3 color block
+//===============================================================
+procedure flip_blocks_dxtc3(data: PGLubyte; numBlocks: Integer);
+var
+  curblock: PDXTColBlock;
+  alphablock: PDXT3AlphaBlock;
+  tempS: Word;
+  tempB: Byte;
+  i: Integer;
+begin
+  curblock := PDXTColBlock(data);
+  for i := 0 to numBlocks - 1 do
+  begin
+    alphablock := PDXT3AlphaBlock(curblock);
+
+    tempS := alphablock.row[0];
+    alphablock.row[0] := alphablock.row[3];
+    alphablock.row[3] := tempS;
+    tempS := alphablock.row[1];
+    alphablock.row[1] := alphablock.row[2];
+    alphablock.row[2] := tempS;
+
+    Inc(curblock);
+
+    tempB := curblock.row[0];
+    curblock.row[0] := curblock.row[3];
+    curblock.row[3] := tempB;
+    tempB := curblock.row[1];
+    curblock.row[1] := curblock.row[2];
+    curblock.row[2] := tempB;
+
+    Inc(curblock);
+  end;
+end;
+
+//=================================================
+procedure flip_dxt5_alpha(block: PDXT5AlphaBlock);
+const
+  mask = $00000007; // bits = 00 00 01 11
+var
+  GBits: array [0 .. 3, 0 .. 3] of Byte;
+  bits: Integer;
+begin
+  bits := 0;
+  Move(block.row[0], bits, sizeof(Byte) * 3);
+
+  GBits[0][0] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[0][1] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[0][2] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[0][3] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[1][0] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[1][1] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[1][2] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[1][3] := Byte(bits and mask);
+
+  bits := 0;
+  Move(block.row[3], bits, sizeof(Byte) * 3);
+
+  GBits[2][0] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[2][1] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[2][2] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[2][3] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[3][0] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[3][1] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[3][2] := Byte(bits and mask);
+  bits := bits shr 3;
+  GBits[3][3] := Byte(bits and mask);
+
+  // clear existing alpha bits
+  FillChar(block.row, sizeof(Byte) * 6, 0);
+
+  bits := block.row[0] + block.row[1] * $100 + block.row[2] * $10000;
+
+  bits := bits or (GBits[3][0] shl 0);
+  bits := bits or (GBits[3][1] shl 3);
+  bits := bits or (GBits[3][2] shl 6);
+  bits := bits or (GBits[3][3] shl 9);
+
+  bits := bits or (GBits[2][0] shl 12);
+  bits := bits or (GBits[2][1] shl 15);
+  bits := bits or (GBits[2][2] shl 18);
+  bits := bits or (GBits[2][3] shl 21);
+
+  block.row[0] := bits and $FF;
+  block.row[1] := (bits shr 8) and $FF;
+  block.row[2] := (bits shr 16) and $FF;
+
+  bits := block.row[3] + block.row[4] * $100 + block.row[5] * $10000;
+
+  bits := bits or (GBits[1][0] shl 0);
+  bits := bits or (GBits[1][1] shl 3);
+  bits := bits or (GBits[1][2] shl 6);
+  bits := bits or (GBits[1][3] shl 9);
+
+  bits := bits or (GBits[0][0] shl 12);
+  bits := bits or (GBits[0][1] shl 15);
+  bits := bits or (GBits[0][2] shl 18);
+  bits := bits or (GBits[0][3] shl 21);
+
+  block.row[3] := bits and $FF;
+  block.row[4] := (bits shr 8) and $FF;
+  block.row[5] := (bits shr 16) and $FF;
+end;
+
+//==============================================================
+procedure flip_blocks_dxtc5(data: PGLubyte; numBlocks: Integer);
+var
+  curblock: PDXTColBlock;
+  temp: Byte;
+  i: Integer;
+begin
+  curblock := PDXTColBlock(data);
+  for i := 0 to numBlocks - 1 do
+  begin
+    flip_dxt5_alpha(PDXT5AlphaBlock(curblock));
+    Inc(curblock);
+    temp := curblock.row[0];
+    curblock.row[0] := curblock.row[3];
+    curblock.row[3] := temp;
+    temp := curblock.row[1];
+    curblock.row[1] := curblock.row[2];
+    curblock.row[2] := temp;
+    Inc(curblock);
+  end;
+end;
+
+function DDSHeaderToGLEnum(const DX9header: TDDSHeader; const DX11header: TDDS_HEADER_DXT10;
+  const useDX11: Boolean; out iFormat: TGLinternalFormat; out colorFormat: Cardinal;
+  out dataType: Cardinal; out bpe: Integer): Boolean;
+var
+  i: Integer;
+begin
+  Result := True;
+  if useDX11 then
+  begin
+    Assert(False, 'DXGI images not supported.');
+  end
+  // Use DX9 formats
+  else
+  begin
+    // figure out what the image format is
+    if (DX9header.SurfaceFormat.ddpf.dwFlags and DDPF_FOURCC) <> 0 then
+    begin
+      case DX9header.SurfaceFormat.ddpf.dwFourCC of
+        FOURCC_DXT1:
+          begin
+            colorFormat := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+            iFormat := tfCOMPRESSED_RGBA_S3TC_DXT1;
+            dataType := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+            bpe := 8;
+          end;
+        FOURCC_DXT2, FOURCC_DXT3:
+          begin
+            colorFormat := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+            iFormat := tfCOMPRESSED_RGBA_S3TC_DXT3;
+            dataType := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+            bpe := 16;
+          end;
+        FOURCC_DXT4, FOURCC_DXT5:
+          begin
+            colorFormat := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+            iFormat := tfCOMPRESSED_RGBA_S3TC_DXT5;
+            dataType := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+            bpe := 16;
+          end;
+        FOURCC_ATI1:
+          begin
+            colorFormat := GL_COMPRESSED_RED_RGTC1;
+            iFormat := tfCOMPRESSED_RED_RGTC1;
+            dataType := GL_COMPRESSED_RED_RGTC1;
+            bpe := 8;
+          end;
+        FOURCC_ATI2:
+          begin
+            colorFormat := GL_COMPRESSED_RG_RGTC2;
+            iFormat := tfCOMPRESSED_RG_RGTC2;
+            dataType := GL_COMPRESSED_RG_RGTC2;
+            bpe := 16;
+          end;
+        FOURCC_R8G8B8:
+          begin
+            colorFormat := GL_BGR;
+            iFormat := tfRGB8;
+            dataType := GL_UNSIGNED_BYTE;
+            bpe := 3;
+          end;
+        FOURCC_A8R8G8B8:
+          begin
+            colorFormat := GL_BGRA;
+            iFormat := tfRGBA8;
+            dataType := GL_UNSIGNED_BYTE;
+            bpe := 4;
+          end;
+        FOURCC_X8R8G8B8:
+          begin
+            colorFormat := GL_BGRA;
+            iFormat := tfRGB8;
+            dataType := GL_UNSIGNED_INT_8_8_8_8;
+            bpe := 4;
+          end;
+        FOURCC_R5G6B5:
+          begin
+            colorFormat := GL_RGB;
+            iFormat := tfRGB5;
+            dataType := GL_UNSIGNED_SHORT_5_6_5;
+            bpe := 2;
+          end;
+        FOURCC_A8:
+          begin
+            colorFormat := GL_ALPHA;
+            iFormat := tfALPHA8;
+            dataType := GL_UNSIGNED_BYTE;
+            bpe := 1;
+          end;
+        FOURCC_A2B10G10R10:
+          begin
+            colorFormat := GL_RGBA;
+            iFormat := tfRGB10_A2;
+            dataType := GL_UNSIGNED_INT_10_10_10_2;
+            bpe := 4;
+          end;
+        FOURCC_A8B8G8R8:
+          begin
+            colorFormat := GL_RGBA;
+            iFormat := tfRGBA8;
+            dataType := GL_UNSIGNED_BYTE;
+            bpe := 4;
+          end;
+        FOURCC_X8B8G8R8:
+          begin
+            colorFormat := GL_RGBA;
+            iFormat := tfRGB8;
+            dataType := GL_UNSIGNED_INT_8_8_8_8;
+            bpe := 4;
+          end;
+        FOURCC_A2R10G10B10:
+          begin
+            colorFormat := GL_BGRA;
+            iFormat := tfRGB10_A2;
+            dataType := GL_UNSIGNED_INT_10_10_10_2;
+            bpe := 4;
+          end;
+        FOURCC_A16B16G16R16:
+          begin
+            colorFormat := GL_RGBA;
+            iFormat := tfR16G16B16A16;
+            dataType := GL_UNSIGNED_SHORT;
+            bpe := 8;
+          end;
+        FOURCC_L8:
+          begin
+            colorFormat := GL_LUMINANCE;
+            iFormat := tfLUMINANCE8;
+            dataType := GL_UNSIGNED_BYTE;
+            bpe := 1;
+          end;
+        FOURCC_A8L8:
+          begin
+            colorFormat := GL_LUMINANCE_ALPHA;
+            iFormat := tfLUMINANCE8_ALPHA8;
+            dataType := GL_UNSIGNED_BYTE;
+            bpe := 2;
+          end;
+        FOURCC_L16:
+          begin
+            colorFormat := GL_LUMINANCE;
+            iFormat := tfLUMINANCE16;
+            dataType := GL_UNSIGNED_SHORT;
+            bpe := 2;
+          end;
+        FOURCC_R16F:
+          begin
+            colorFormat := GL_RED;
+            iFormat := tfLUMINANCE_FLOAT16;
+            dataType := GL_HALF_FLOAT_ARB;
+            bpe := 2;
+          end;
+        FOURCC_A16B16G16R16F:
+          begin
+            colorFormat := GL_RGBA;
+            iFormat := tfRGBA_FLOAT16;
+            dataType := GL_HALF_FLOAT_ARB;
+            bpe := 8;
+          end;
+        FOURCC_R32F:
+          begin
+            colorFormat := GL_RED;
+            iFormat := tfLUMINANCE_FLOAT32;
+            dataType := GL_FLOAT;
+            bpe := 4;
+          end;
+        FOURCC_G16R16:
+          begin
+            colorFormat := GL_RG;
+            iFormat := tfRG16;
+            dataType := GL_UNSIGNED_SHORT;
+            bpe := 4;
+          end;
+        FOURCC_G16R16F:
+          begin
+            colorFormat := GL_RG;
+            iFormat := tfRG16F;
+            dataType := GL_HALF_FLOAT;
+            bpe := 4;
+          end;
+        FOURCC_G32R32F:
+          begin
+            colorFormat := GL_RG;
+            iFormat := tfRG32F;
+            dataType := GL_FLOAT;
+            bpe := 8;
+          end;
+        FOURCC_UNKNOWN, FOURCC_X1R5G5B5, FOURCC_A1R5G5B5, FOURCC_A4R4G4B4, FOURCC_R3G3B2,
+          FOURCC_A8R3G3B2, FOURCC_X4R4G4B4, FOURCC_A4L4, FOURCC_D16_LOCKABLE, FOURCC_D32,
+          FOURCC_D24X8, FOURCC_D16, FOURCC_D32F_LOCKABLE:
+          Result := False; // these are unsupported for now
+      end; // of case
+    end // not FOURCC
+
+    else
+      with DX9header.SurfaceFormat.ddpf do
+        case dwRGBBitCount of
+          8:
+            begin
+              for i := 0 to High(cImageDataFormat8bits) do
+                if (cImageDataFormat8bits[i].ColorFlag = dwFlags) and
+                  (cImageDataFormat8bits[i].RBits = dwRBitMask) and
+                  (cImageDataFormat8bits[i].GBits = dwGBitMask) and
+                  (cImageDataFormat8bits[i].BBits = dwBBitMask) and
+                  (cImageDataFormat8bits[i].ABits = dwRGBAlphaBitMask) then
+                begin
+                  colorFormat := cImageDataFormat8bits[i].colorFormat;
+                  iFormat := cImageDataFormat8bits[i].TexFormat;
+                  dataType := cImageDataFormat8bits[i].dType;
+                  Result := True;
+                  Break;
+                end;
+              bpe := 1;
+            end;
+          16:
+            begin
+              for i := 0 to High(cImageDataFormat16bits) do
+                if (cImageDataFormat16bits[i].ColorFlag = dwFlags) and
+                  (cImageDataFormat16bits[i].RBits = dwRBitMask) and
+                  (cImageDataFormat16bits[i].GBits = dwGBitMask) and
+                  (cImageDataFormat16bits[i].BBits = dwBBitMask) and
+                  (cImageDataFormat16bits[i].ABits = dwRGBAlphaBitMask) then
+                begin
+                  colorFormat := cImageDataFormat16bits[i].colorFormat;
+                  iFormat := cImageDataFormat16bits[i].TexFormat;
+                  dataType := cImageDataFormat16bits[i].dType;
+                  Result := True;
+                  Break;
+                end;
+              bpe := 2;
+            end;
+          24:
+            begin
+              for i := 0 to High(cImageDataFormat24bits) do
+                if (cImageDataFormat24bits[i].ColorFlag = dwFlags) and
+                  (cImageDataFormat24bits[i].RBits = dwRBitMask) and
+                  (cImageDataFormat24bits[i].GBits = dwGBitMask) and
+                  (cImageDataFormat24bits[i].BBits = dwBBitMask) and
+                  (cImageDataFormat24bits[i].ABits = dwRGBAlphaBitMask) then
+                begin
+                  colorFormat := cImageDataFormat24bits[i].colorFormat;
+                  iFormat := cImageDataFormat24bits[i].TexFormat;
+                  dataType := cImageDataFormat24bits[i].dType;
+                  Result := True;
+                  Break;
+                end;
+              bpe := 3;
+            end;
+          32:
+            begin
+              for i := 0 to High(cImageDataFormat32bits) do
+                if (cImageDataFormat32bits[i].ColorFlag = dwFlags) and
+                  (cImageDataFormat32bits[i].RBits = dwRBitMask) and
+                  (cImageDataFormat32bits[i].GBits = dwGBitMask) and
+                  (cImageDataFormat32bits[i].BBits = dwBBitMask) and
+                  (cImageDataFormat32bits[i].ABits = dwRGBAlphaBitMask) then
+                begin
+                  colorFormat := cImageDataFormat32bits[i].colorFormat;
+                  iFormat := cImageDataFormat32bits[i].TexFormat;
+                  dataType := cImageDataFormat32bits[i].dType;
+                  Result := True;
+                  Break;
+                end;
+              bpe := 4;
+            end;
+        else
+          Result := False;
+        end; // of case
+  end;
+end;
+
+//-------------------------------------------------------------------------------------
+
+function GLEnumToDDSHeader(var DX9header: TDDSHeader; var DX11header: TDDS_HEADER_DXT10;
+  const useDX11: Boolean; const iFormat: TGLinternalFormat; const colorFormat: Cardinal;
+  const dataType: Cardinal; const bpe: Integer): Boolean;
+var
+  i: Integer;
+begin
+  Result := True;
+  if useDX11 then
+  begin
+    Assert(False, 'DXGI images not supported.');
+  end;
+
+  if IsCompressedFormat(iFormat) then
+  begin
+    with DX9header.SurfaceFormat.ddpf do
+    begin
+      dwFlags := DDPF_FOURCC;
+      case iFormat of
+        tfCOMPRESSED_RGB_S3TC_DXT1:
+          dwFourCC := FOURCC_DXT1;
+        tfCOMPRESSED_RGBA_S3TC_DXT1:
+          dwFourCC := FOURCC_DXT1;
+        tfCOMPRESSED_RGBA_S3TC_DXT3:
+          dwFourCC := FOURCC_DXT3;
+        tfCOMPRESSED_RGBA_S3TC_DXT5:
+          dwFourCC := FOURCC_DXT5;
+        tfCOMPRESSED_LUMINANCE_LATC1:
+          dwFourCC := FOURCC_ATI1;
+        tfCOMPRESSED_LUMINANCE_ALPHA_LATC2:
+          dwFourCC := FOURCC_ATI2;
+      else
+        Result := False;
+      end;
+    end;
+  end
+  else if IsFloatFormat(iFormat) then
+  begin
+    with DX9header.SurfaceFormat.ddpf do
+    begin
+      dwFlags := DDPF_FOURCC;
+      case iFormat of
+        tfINTENSITY_FLOAT16, tfLUMINANCE_FLOAT16, tfR16F:
+          dwFourCC := FOURCC_R16F;
+        tfRGBA_FLOAT16:
+          dwFourCC := FOURCC_A16B16G16R16F;
+        tfINTENSITY_FLOAT32, tfLUMINANCE_FLOAT32, tfR32F:
+          dwFourCC := FOURCC_R32F;
+        tfLUMINANCE_ALPHA_FLOAT16, tfRG16F:
+          dwFourCC := FOURCC_G16R16F;
+        tfLUMINANCE_ALPHA_FLOAT32, tfRG32F:
+          dwFourCC := FOURCC_G32R32F;
+        tfRGBA_FLOAT32:
+          dwFourCC := FOURCC_A32B32G32R32F
+      else
+        Result := False;
+      end;
+    end;
+  end
+  else
+    with DX9header.SurfaceFormat.ddpf do
+    begin
+      dwFourCC := 0;
+      dwRGBBitCount := bpe * 8;
+      case bpe of
+        1:
+          begin
+            for i := 0 to High(cImageDataFormat8bits) do
+              if (cImageDataFormat8bits[i].colorFormat = colorFormat) and
+                (cImageDataFormat8bits[i].TexFormat = iFormat) and
+                (cImageDataFormat8bits[i].dType = dataType) then
+              begin
+                dwFlags := cImageDataFormat8bits[i].ColorFlag;
+                dwRBitMask := cImageDataFormat8bits[i].RBits;
+                dwGBitMask := cImageDataFormat8bits[i].GBits;
+                dwBBitMask := cImageDataFormat8bits[i].BBits;
+                dwRGBAlphaBitMask := cImageDataFormat8bits[i].ABits;
+                Break;
+              end;
+          end;
+
+        2:
+          begin
+            for i := 0 to High(cImageDataFormat16bits) do
+              if (cImageDataFormat16bits[i].colorFormat = colorFormat) and
+                (cImageDataFormat16bits[i].TexFormat = iFormat) and
+                (cImageDataFormat16bits[i].dType = dataType) then
+              begin
+                dwFlags := cImageDataFormat16bits[i].ColorFlag;
+                dwRBitMask := cImageDataFormat16bits[i].RBits;
+                dwGBitMask := cImageDataFormat16bits[i].GBits;
+                dwBBitMask := cImageDataFormat16bits[i].BBits;
+                dwRGBAlphaBitMask := cImageDataFormat16bits[i].ABits;
+                Break;
+              end;
+          end;
+
+        3:
+          begin
+            for i := 0 to High(cImageDataFormat24bits) do
+              if (cImageDataFormat24bits[i].colorFormat = colorFormat) and
+                (cImageDataFormat24bits[i].TexFormat = iFormat) and
+                (cImageDataFormat24bits[i].dType = dataType) then
+              begin
+                dwFlags := cImageDataFormat24bits[i].ColorFlag;
+                dwRBitMask := cImageDataFormat24bits[i].RBits;
+                dwGBitMask := cImageDataFormat24bits[i].GBits;
+                dwBBitMask := cImageDataFormat24bits[i].BBits;
+                dwRGBAlphaBitMask := cImageDataFormat24bits[i].ABits;
+                Break;
+              end;
+          end;
+
+        4:
+          begin
+            for i := 0 to High(cImageDataFormat32bits) do
+              if (cImageDataFormat32bits[i].colorFormat = colorFormat) and
+                (cImageDataFormat32bits[i].TexFormat = iFormat) and
+                (cImageDataFormat32bits[i].dType = dataType) then
+              begin
+                dwFlags := cImageDataFormat32bits[i].ColorFlag;
+                dwRBitMask := cImageDataFormat32bits[i].RBits;
+                dwGBitMask := cImageDataFormat32bits[i].GBits;
+                dwBBitMask := cImageDataFormat32bits[i].BBits;
+                dwRGBAlphaBitMask := cImageDataFormat32bits[i].ABits;
+                Break;
+              end;
+          end;
+
+      else
+        Result := False;
+      end; // of case
+    end;
+
+end;
+
+//---------------------------------------------------------------------------------------------
+
+function FindDDSCompatibleDataFormat(const iFormat: TGLinternalFormat; out colorFormat: Cardinal;
+  out dataType: Cardinal): Boolean;
+var
+  i: Integer;
+begin
+  Result := False;
+  // 32 bits data format
+  for i := 0 to High(cImageDataFormat32bits) do
+    if cImageDataFormat32bits[i].TexFormat = iFormat then
+    begin
+      colorFormat := cImageDataFormat32bits[i].colorFormat;
+      dataType := cImageDataFormat32bits[i].dType;
+      Result := True;
+      exit;
+    end;
+  // 24 bits data format
+  for i := 0 to High(cImageDataFormat24bits) do
+    if cImageDataFormat24bits[i].TexFormat = iFormat then
+    begin
+      colorFormat := cImageDataFormat24bits[i].colorFormat;
+      dataType := cImageDataFormat24bits[i].dType;
+      Result := True;
+      exit;
+    end;
+  // 16 bits data format
+  for i := 0 to High(cImageDataFormat16bits) do
+    if cImageDataFormat16bits[i].TexFormat = iFormat then
+    begin
+      colorFormat := cImageDataFormat16bits[i].colorFormat;
+      dataType := cImageDataFormat16bits[i].dType;
+      Result := True;
+      exit;
+    end;
+  // 8 bits data format
+  for i := 0 to High(cImageDataFormat8bits) do
+    if cImageDataFormat8bits[i].TexFormat = iFormat then
+    begin
+      colorFormat := cImageDataFormat8bits[i].colorFormat;
+      dataType := cImageDataFormat8bits[i].dType;
+      Result := True;
+      exit;
+    end;
+end;
+
+end.

+ 2465 - 0
Sourcex/Formatx.LWO.pas

@@ -0,0 +1,2465 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.LWO;
+(*
+
+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
+
+
+uses
+  System.Classes,
+  System.SysUtils,
+  System.IOUtils,
+  System.Math,
+  GLScene.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);
+
+{$IFDEF WIN32}
+      CurPols[CurPols.Count - 1].FID := CurId;
+{$ELSE}
+//      CurPols[CurPols.Count - 1].FID := CurId;
+{$ENDIF}
+      LoadFromStream(AStream);
+    end
+    else if (CurId = ID_VMAP) or (CurId = ID_VMAD) then
+    begin
+      CurPnts.Add(GetChunkClass(CurId, TLWChunk).Create);
+{$IFDEF WIN32}
+      CurPnts[CurPnts.Count - 1].FID := CurId;
+{$ELSE}
+//      CurPnts[CurPnts.Count - 1].FID := CurId;
+{$ENDIF}
+      LoadFromStream(AStream);
+    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);
+{$IFDEF WIN32}
+      CurItems[CurItems.Count - 1].FID := CurId;
+{$ELSE}
+//      CurItems[CurItems.Count - 1].FID := CurId;
+{$ENDIF}
+      LoadFromStream(AStream);
+    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);
+{$IFDEF WIN32}
+     with Items[Items.Count - 1] do
+{$ELSE}
+///    with Items[Items.Count - 1] do
+{$ENDIF}
+    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);
+
+{$IFDEF WIN32}
+     with Items[Items.Count - 1] do
+{$ELSE}
+///    with Items[Items.Count - 1] do
+{$ENDIF}
+    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.

+ 192 - 0
Sourcex/Formatx.MD2.pas

@@ -0,0 +1,192 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.MD2;
+
+(* Loading methods for MD2 file format *)
+
+interface
+
+{$R-}
+{$I GLScene.Defines.inc}
+
+uses
+  System.Classes,
+  System.SysUtils,
+   
+  GLScene.VectorTypes;
+
+const
+  MAX_MD2_TRIANGLES = 4096;
+  MAX_MD2_VERTICES = 2048;
+  MAX_MD2_FRAMES = 512;
+  MAX_MD2_SKINS = 32;
+  MAX_MD2_SKINNAME = 64;
+
+type
+  PMD2VertexIndex = ^TMD2VertexIndex;
+  TMD2VertexIndex = record
+    A, B, C: integer;
+    A_S, A_T,
+    B_S, B_T,
+    C_S, C_T: single;
+  end;
+
+  TMD2Triangle = record
+    VertexIndex: TVector3s;
+    TextureCoordIndex: TVector3s;
+  end;
+
+  TMD2TriangleVertex = record
+    Vert: array[0..2] of byte;
+    LightnormalIndex: byte;
+  end;
+
+  PMD2AliasFrame = ^TMD2AliasFrame;
+  TMD2AliasFrame = record
+    Scale: TVector3f;
+    Translate: TVector3f;
+    Name: array[0..15] of AnsiChar;
+    Vertices: array[0..0] of TMD2TriangleVertex;
+  end;
+
+  TMD2Header = record
+    Ident: integer;
+    Version: integer;
+
+    SkinWidth: integer;
+    SkinHeight: integer;
+    FrameSize: integer;
+
+    Num_Skins: integer;
+    Num_Vertices: integer;
+    Num_TextureCoords: integer;
+    Num_VertexIndices: integer;
+    Num_GLCommdands: integer;
+    Num_Frames: integer;
+
+    Offset_skins: integer;
+    Offset_st: integer;
+    Offset_tris: integer;
+    Offset_frames: integer;
+    Offset_glcmds: integer;
+    Offset_end: integer;
+  end;
+
+  TIndexList = array of TMD2VertexIndex;
+  TGLVertexList = array of array of TVector3f;
+
+
+type
+  TFileMD2 = class
+  private
+    FiFrames: longint;
+    FiVertices: longint;
+    FiTriangles: longint;
+    procedure FreeLists;
+  public
+    fIndexList : TIndexList;
+    fVertexList : TGLVertexList;
+    FrameNames : TStrings;
+    constructor Create; virtual;
+    destructor Destroy; override;
+    procedure LoadFromStream(aStream : TStream);
+    property iFrames: longInt read FiFrames;
+    property iVertices: longInt read FiVertices;
+    property iTriangles: longInt read FiTriangles;
+
+    property IndexList: TIndexList read fIndexList;
+    property VertexList: TGLVertexList read fVertexList;
+  end;
+
+implementation // ------------------------------------------------------------
+
+// ------------------
+// ------------------ TFileMD2 ------------------
+// ------------------
+
+constructor TFileMD2.Create;
+begin
+  inherited;
+  FreeLists;
+  FrameNames := TStringList.Create;
+end;
+
+destructor TFileMD2.Destroy;
+begin
+  FreeLists;
+  FrameNames.Free;
+  inherited;
+end;
+
+procedure TFileMD2.FreeLists;
+begin
+  SetLength(fIndexList,0);
+  SetLength(fVertexList,0,0);
+  FiFrames := 0;
+  FiVertices := 0;
+  FiTriangles := 0;
+end;
+
+procedure TFileMD2.LoadFromStream(aStream : TStream);
+var
+  Skins: array[0..MAX_MD2_SKINS - 1, 0..63] of AnsiChar;
+  TextureCoords: array[0..MAX_MD2_VERTICES - 1] of TVector2s;
+  Buffer: array[0..MAX_MD2_VERTICES * 4 + 127] of byte;
+  Header: TMD2Header;
+  Triangle: TMD2Triangle;
+  I: integer;
+  J: integer;
+  Frame: PMD2AliasFrame;
+  FrameName : String;
+
+begin
+  FreeLists;
+  // read the modelinfo
+  aStream.Read(Header, SizeOf(Header));
+  FiFrames := Header.Num_Frames;
+  FiVertices := Header.Num_Vertices;
+  FiTriangles := Header.Num_VertexIndices;
+  SetLength(fIndexList, FiTriangles);
+  SetLength(fVertexList, FiFrames, FiVertices);
+  // get the skins...
+  aStream.Read(Skins, Header.Num_Skins * MAX_MD2_SKINNAME);
+  // ...and the texcoords
+  aStream.Read(TextureCoords, Header.Num_TextureCoords * SizeOf(TVector2s));
+  for I := 0 to Header.Num_VertexIndices - 1 do begin
+    aStream.Read(Triangle, SizeOf(TMD2Triangle));
+     with fIndexList[I] do begin
+      A := Triangle.VertexIndex.Z;
+      B := Triangle.VertexIndex.Y;
+      C := Triangle.VertexIndex.X;
+      A_S := TextureCoords[Triangle.TextureCoordIndex.Z].X / Header.SkinWidth;
+      A_T := TextureCoords[Triangle.TextureCoordIndex.Z].Y / Header.SkinHeight;
+      B_S := TextureCoords[Triangle.TextureCoordIndex.Y].X / Header.SkinWidth;
+      B_T := TextureCoords[Triangle.TextureCoordIndex.Y].Y / Header.SkinHeight;
+      C_S := TextureCoords[Triangle.TextureCoordIndex.X].X / Header.SkinWidth;
+      C_T := TextureCoords[Triangle.TextureCoordIndex.X].Y / Header.SkinHeight;
+    end;
+  end;
+  for I := 0 to Header.Num_Frames - 1 do begin
+    Frame := PMD2AliasFrame(@Buffer);
+    // read animation / frame info
+    aStream.Read(Frame^, Header.FrameSize);
+    FrameName := Trim(String(Frame^.Name));
+    if CharInSet(Copy(FrameName, Length(FrameName) - 1, 1)[1], ['0'..'9']) then
+      FrameName := Copy(FrameName, 1, Length(FrameName) - 2)
+    else
+      FrameName := Copy(FrameName, 1, Length(FrameName) - 1);
+    if FrameNames.IndexOf(FrameName) < 0 then
+      FrameNames.AddObject(FrameName, TObject(Cardinal(I)));
+    // fill the vertices list
+     for J := 0 to FiVertices - 1 do begin
+       fVertexList[i][J].X := Frame^.Vertices[J].Vert[0] * Frame^.Scale.X + Frame^.Translate.X;
+       fVertexList[i][J].Y := Frame^.Vertices[J].Vert[1] * Frame^.Scale.Y + Frame^.Translate.Y;
+       fVertexList[i][J].Z := Frame^.Vertices[J].Vert[2] * Frame^.Scale.Z + Frame^.Translate.Z;
+     end;
+  end;
+end;
+
+//---------------------------------------------------------------------------
+
+end.

+ 152 - 0
Sourcex/Formatx.MD3.pas

@@ -0,0 +1,152 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.MD3;
+
+(* File loading methods for the MD3 file format *)
+
+interface
+
+uses
+  System.Classes,
+  GLScene.VectorTypes;
+
+type
+  // Quake3 MD3 structure types
+  TMD3Tag = record
+    strName: array [0 .. 63] of AnsiChar;
+    vPosition: TVector3f;
+    rotation: TMatrix3f;
+  end;
+
+  (* This part of the MD3 structure called 2 things:
+    A frame and a bone. It doesn't matter because we don't use it *)
+  (*
+    TMD3Frame = record
+    min_bound,max_bounds,
+    local_origin  : TVector3f;
+    radius        : single;
+    name          : array[0..15] of char;
+    end;
+  *)
+  TMD3Bone = record
+    mins, maxs, position: TVector3f;
+    scale: single;
+    creator: array [0 .. 15] of AnsiChar;
+  end;
+
+  TMD3Triangle = record
+    vertex: TVector3s; // value/64 to get real number position
+    normal: TVector2b; // Latitude,Longitude
+  end;
+
+  TMD3Face = record
+    vertexIndices: TVector3i;
+  end;
+
+  TMD3TexCoord = record
+    textureCoord: TVector2f;
+  end;
+
+  TMD3Skin = record
+    strName: array [0 .. 63] of AnsiChar;
+    shaderIndex: Integer;
+  end;
+
+  TMD3Header = record
+    fileID: array [0 .. 3] of AnsiChar;
+    version: Integer;
+    strFile: array [0 .. 63] of AnsiChar;
+    flags, numFrames, numTags, numMeshes, numMaxSkins, headerSize, tagStart,
+      tagEnd, fileSize: Integer;
+  end;
+
+  TMD3MeshHeader = record
+    meshID: array [0 .. 3] of AnsiChar;
+    strName: array [0 .. 63] of AnsiChar;
+    flags, numMeshFrames, numSkins, numVertices, numTriangles, triStart,
+      headerSize, uvStart, vertexStart, meshSize: Integer;
+  end;
+
+  TMD3MeshData = record
+    MeshHeader: TMD3MeshHeader;
+    Skins: array of TMD3Skin;
+    Triangles: array of TMD3Face;
+    TexCoords: array of TMD3TexCoord;
+    Vertices: array of TMD3Triangle;
+  end;
+
+  // MD3 Main file class
+
+  TFileMD3 = class
+  public
+    ModelHeader: TMD3Header;
+    Bones: array of TMD3Bone;
+    Tags: array of TMD3Tag;
+    MeshData: array of TMD3MeshData;
+
+    procedure LoadFromStream(aStream: TStream);
+  end;
+
+implementation // ------------------------------------------------------------
+
+// ------------------
+// ------------------ TFileMD3 ------------------
+// ------------------
+
+procedure TFileMD3.LoadFromStream(aStream: TStream);
+var
+  i: Integer;
+  meshOffset: LongInt;
+begin
+  aStream.Read(ModelHeader, sizeof(ModelHeader));
+
+  // Test for correct file ID and version
+  Assert(ModelHeader.fileID = 'IDP3', 'Incorrect MD3 file ID');
+  Assert(ModelHeader.version = 15, 'Incorrect MD3 version number');
+
+  // Read in the bones
+  SetLength(Bones, ModelHeader.numFrames);
+  aStream.Read(Bones[0], sizeof(TMD3Bone) * ModelHeader.numFrames);
+
+  // Read in the Tags
+  SetLength(Tags, ModelHeader.numFrames * ModelHeader.numTags);
+  if ModelHeader.numTags > 0 then
+    aStream.Read(Tags[0], sizeof(TMD3Tag) * ModelHeader.numFrames *
+      ModelHeader.numTags);
+
+  // Read in the Mesh data
+  meshOffset := aStream.position;
+  SetLength(MeshData, ModelHeader.numMeshes);
+  for i := 0 to ModelHeader.numMeshes - 1 do
+  begin
+    with MeshData[i] do
+    begin
+      aStream.position := meshOffset;
+      aStream.Read(MeshHeader, sizeof(MeshHeader));
+      // Set up the dynamic arrays
+      SetLength(Skins, MeshHeader.numSkins);
+      SetLength(Triangles, MeshHeader.numTriangles);
+      SetLength(TexCoords, MeshHeader.numVertices);
+      SetLength(Vertices, MeshHeader.numVertices * MeshHeader.numMeshFrames);
+      // Skins
+      aStream.Read(Skins[0], sizeof(TMD3Skin) * MeshHeader.numSkins);
+      // Face data
+      aStream.position := meshOffset + MeshHeader.triStart;
+      aStream.Read(Triangles[0], sizeof(TMD3Face) * MeshHeader.numTriangles);
+      // Texture coordinates
+      aStream.position := meshOffset + MeshHeader.uvStart;
+      aStream.Read(TexCoords[0], sizeof(TMD3TexCoord) * MeshHeader.numVertices);
+      // Vertices
+      aStream.position := meshOffset + MeshHeader.vertexStart;
+      aStream.Read(Vertices[0], sizeof(TMD3Triangle) * MeshHeader.numMeshFrames
+        * MeshHeader.numVertices);
+      // Increase the offset
+      meshOffset := meshOffset + MeshHeader.meshSize;
+    end;
+  end;
+end;
+
+// ------------------------------------------------------------------
+
+end.

+ 191 - 0
Sourcex/Formatx.OCT.pas

@@ -0,0 +1,191 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.OCT;
+
+(* Loader for FSRad OCT files *)
+
+interface
+
+{$I GLScene.Defines.inc}
+
+uses
+  System.Classes,
+  System.SysUtils,
+
+  GLScene.VectorGeometry,
+  GLScene.VectorTypes,
+  GXS.VectorLists;
+
+type
+
+  TOCTHeader = record
+    numVerts: Integer;
+    numFaces: Integer;
+    numTextures: Integer;
+    numLightmaps: Integer;
+    numLights: Integer;
+  end;
+
+  TOCTVertex = record
+    tv: TTexPoint; // texture coordinates
+    lv: TTexPoint; // lightmap coordinates
+    pos: TAffineVector; // vertex position
+  end;
+
+  TOCTFace = record
+    start: Integer; // first face vert in vertex array
+    num: Integer; // number of verts in the face
+    id: Integer; // texture index into the texture array
+    lid: Integer; // lightmap index into the lightmap array
+    p: THmgPlane;
+  end;
+
+  POCTFace = ^TOCTFace;
+
+  TOCTTexture = record
+    id: Integer; // texture id
+    Name: array [0 .. 63] of AnsiChar; // texture name
+  end;
+
+  TOCTLightmap = record
+    id: Integer; // lightmaps id
+    map: array [0 .. 49151] of Byte; // 128 x 128 raw RGB data
+  end;
+
+  POCTLightmap = ^TOCTLightmap;
+
+  TOCTLight = record
+    pos: TAffineVector; // Position
+    color: TAffineVector; // Color (RGB)
+    intensity: Integer; // Intensity
+  end;
+
+  TOCTFile = class(TObject)
+  public
+    Header: TOCTHeader;
+    Vertices: array of TOCTVertex;
+    Faces: array of TOCTFace;
+    Textures: array of TOCTTexture;
+    Lightmaps: array of TOCTLightmap;
+    Lights: array of TOCTLight;
+    PlayerPos: TAffineVector;
+    constructor Create; overload;
+    constructor Create(octStream: TStream); overload;
+    (* Saves content to stream in OCT format.
+      The Header is automatically prepared before streaming. *)
+    procedure SaveToStream(aStream: TStream);
+    procedure AddTriangles(vertexCoords: TgxAffineVectorList;
+      texMapCoords: TgxAffineVectorList; const textureName: String);
+    procedure AddLight(const lightPos: TAffineVector; const lightColor: TGLVector;
+      lightIntensity: Integer);
+  end;
+
+implementation // ------------------------------------------------------------
+
+// ------------------
+// ------------------ TOCTFile ------------------
+// ------------------
+
+constructor TOCTFile.Create;
+begin
+  inherited Create;
+end;
+
+constructor TOCTFile.Create(octStream: TStream);
+begin
+  inherited Create;
+  // Read in the header
+  octStream.Read(Header, SizeOf(Header));
+  // then the rest of the stuff
+  SetLength(Vertices, Header.numVerts);
+  octStream.Read(Vertices[0], Header.numVerts * SizeOf(TOCTVertex));
+  SetLength(Faces, Header.numFaces);
+  octStream.Read(Faces[0], Header.numFaces * SizeOf(TOCTFace));
+  SetLength(Textures, Header.numTextures);
+  octStream.Read(Textures[0], Header.numTextures * SizeOf(TOCTTexture));
+  SetLength(Lightmaps, Header.numLightmaps);
+  octStream.Read(Lightmaps[0], Header.numLightmaps * SizeOf(TOCTLightmap));
+  SetLength(Lights, Header.numLights);
+  octStream.Read(Lights[0], Header.numLights * SizeOf(TOCTLight));
+  octStream.Read(PlayerPos, SizeOf(PlayerPos))
+end;
+
+procedure TOCTFile.SaveToStream(aStream: TStream);
+begin
+  with Header, aStream do
+  begin
+    numVerts := Length(Vertices);
+    numFaces := Length(Faces);
+    numTextures := Length(Textures);
+    numLightmaps := Length(Lightmaps);
+    numLights := Length(Lights);
+
+    Write(Header, SizeOf(Header));
+    Write(Vertices[0], numVerts * SizeOf(TOCTVertex));
+    Write(Faces[0], numFaces * SizeOf(TOCTFace));
+    Write(Textures[0], numTextures * SizeOf(TOCTTexture));
+    Write(Lightmaps[0], numLightmaps * SizeOf(TOCTLightmap));
+    Write(Lights[0], numLights * SizeOf(TOCTLight));
+    Write(PlayerPos, SizeOf(PlayerPos))
+  end;
+end;
+
+procedure TOCTFile.AddTriangles(vertexCoords: TgxAffineVectorList;
+  texMapCoords: TgxAffineVectorList; const textureName: String);
+var
+  i: Integer;
+  baseIdx, texIdx: Integer;
+begin
+  Assert((texMapCoords = nil) or (texMapCoords.Count = vertexCoords.Count));
+
+  texIdx := Length(Textures);
+  SetLength(Textures, texIdx + 1);
+  Move(textureName[1], Textures[texIdx].Name[0], Length(textureName));
+  SetLength(Lightmaps, 1);
+  FillChar(Lightmaps[0].map[0], 128 * 3, 255);
+
+  baseIdx := Length(Vertices);
+  SetLength(Vertices, baseIdx + vertexCoords.Count);
+  for i := 0 to vertexCoords.Count - 1 do
+    with Vertices[baseIdx + i] do
+    begin
+      pos := vertexCoords.List[i];
+      if Assigned(texMapCoords) then
+        tv := PTexPoint(@texMapCoords.List[i])^;
+    end;
+
+  SetLength(Faces, vertexCoords.Count div 3);
+  i := 0;
+  while i < vertexCoords.Count do
+  begin
+    with Faces[i div 3] do
+    begin
+      start := baseIdx + i;
+      num := 3;
+      id := texIdx;
+      p := PlaneMake(vertexCoords[i], CalcPlaneNormal(vertexCoords[i + 0],
+        vertexCoords[i + 1], vertexCoords[i + 0]));
+    end;
+    Inc(i, 3);
+  end;
+end;
+
+procedure TOCTFile.AddLight(const lightPos: TAffineVector;
+  const lightColor: TGLVector; lightIntensity: Integer);
+var
+  n: Integer;
+begin
+  n := Length(Lights);
+  SetLength(Lights, n + 1);
+  with Lights[n] do
+  begin
+    pos := lightPos;
+    color := PAffineVector(@lightColor)^;
+    intensity := lightIntensity;
+  end;
+end;
+
+//---------------------------------------------------------------------------
+
+end.

+ 211 - 0
Sourcex/Formatx.Q3BSP.pas

@@ -0,0 +1,211 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.Q3BSP;
+
+(* Simple Quake III BSP file loader. *)
+
+interface
+
+uses
+  System.Classes,
+  System.SysUtils,
+  GLScene.VectorTypes;
+
+const
+  FACE_POLYGON = 1;
+
+const
+  MAX_TEXTURES = 1000;
+
+type
+
+  TBSPHeader = record
+    StrID: array [0 .. 3] of AnsiChar; // This should always be 'IBSP'
+    Version: Integer; // This should be 0x2e for Quake 3 files
+  end;
+
+  TBSPLump = record
+    Offset: Integer; // The offset into the file for the start of this lump
+    Length: Integer; // The length in bytes for this lump
+  end;
+
+  TBSPBBox = array [0 .. 5] of Integer;
+
+  TBSPNode = record
+    Plane: Integer; // Space partitioning plane
+    Children: array [0 .. 1] of Integer; // Back and front child nodes
+    BBox: TBSPBBox; // Bounding box of node
+  end;
+
+  TBSPLeaf = record
+    Cluster: Integer; // Visibility cluster number
+    Area: Integer; // Volume of the leaf
+    BBox: TBSPBBox; // Bounding box of leaf
+    FirstFace, NumFaces: Integer;
+    // Lookup for the face list (indexes are for faces)
+    FirstBrush, NumBrushes: Integer;
+    // Lookup for the brush list (indexes are for brushes)
+  end;
+
+  TBSPModel = record
+    BBox: TBSPBBox; // Bounding box of model
+    FirstFace, NumFaces: Integer;
+    // Lookup for the face list (indexes are for faces)
+    FirstBrush, NumBrushes: Integer;
+    // Lookup for the brush list (indexes are for brushes)
+  end;
+
+  TBSPVertex = record
+    Position: TVector3f; // (x, y, z) position.
+    TextureCoord: TVector2f; // (u, v) texture coordinate
+    LightmapCoord: TVector2f; // (u, v) lightmap coordinate
+    Normal: TVector3f; // (x, y, z) normal vector
+    Color: array [0 .. 3] of Byte // RGBA color for the vertex
+    end;
+    PBSPVertex = ^TBSPVertex;
+
+    TBSPFace = record textureID: Integer; // The index into the texture array
+    effect: Integer; // The index for the effects (or -1 = n/a)
+    FaceType: Integer; // 1=polygon, 2=patch, 3=mesh, 4=billboard
+    startVertIndex: Integer; // The starting index into this face's first vertex
+    numOfVerts: Integer; // The number of vertices for this face
+    meshVertIndex: Integer; // The index into the first meshvertex
+    numMeshVerts: Integer; // The number of mesh vertices
+    lightmapID: Integer; // The texture index for the lightmap
+    lMapCorner: array [0 .. 1] of Integer;
+    // The face's lightmap corner in the image
+    lMapSize: array [0 .. 1] of Integer; // The size of the lightmap section
+    lMapPos: TVector3f; // The 3D origin of lightmap.
+    lMapVecs: array [0 .. 1] of TVector3f;
+    // The 3D space for s and t unit vectors.
+    vNormal: TVector3f; // The face normal.
+    Size: array [0 .. 1] of Integer; // The bezier patch dimensions.
+  end;
+
+  PBSPFace = ^TBSPFace;
+
+  TBSPTexture = record
+    TextureName: array [0 .. 63] of WideChar;
+    // The name of the texture w/o the extension
+    flags: Integer; // The surface flags (unknown)
+    contents: Integer; // The content flags (unknown)
+  end;
+
+  PBSPTexture = ^TBSPTexture;
+
+  TBSPLightmap = record
+    imageBits: array [0 .. 49151] of Byte; // The RGB data in a 128x128 image
+  end;
+
+  PBSPLightmap = ^TBSPLightmap;
+
+  TBSPVisData = record
+    numOfClusters: Integer;
+    bytesPerCluster: Integer;
+    bitSets: array of Byte;
+  end;
+
+  TQ3BSP = class(TObject)
+  public
+    Header: TBSPHeader;
+    Lumps: array of TBSPLump;
+    numOfVerts: Integer;
+    NumOfNodes: Integer;
+    NumOfPlanes: Integer;
+    NumOfLeaves: Integer;
+    NumOfFaces: Integer;
+    NumOfTextures: Integer;
+    NumOfLightmaps: Integer;
+    Vertices: array of TBSPVertex;
+    Nodes: array of TBSPNode;
+    Planes: array of TVector4f;
+    Leaves: array of TBSPLeaf;
+    Faces: array of TBSPFace;
+    Textures: array of TBSPTexture; // texture names (without extension)
+    Lightmaps: array of TBSPLightmap;
+    VisData: TBSPVisData;
+    constructor Create(bspStream: TStream);
+  end;
+
+const
+  kEntities = 0; // Stores player/object positions, etc...
+  kTextures = 1; // Stores texture information
+  kPlanes = 2; // Stores the splitting planes
+  kNodes = 3; // Stores the BSP nodes
+  kLeafs = 4; // Stores the leafs of the nodes
+  kLeafFaces = 5; // Stores the leaf's indices into the faces
+  kLeafBrushes = 6; // Stores the leaf's indices into the brushes
+  kModels = 7; // Stores the info of world models
+  kBrushes = 8; // Stores the brushes info (for collision)
+  kBrushSides = 9; // Stores the brush surfaces info
+  kVertices = 10; // Stores the level vertices
+  kMeshVerts = 11; // Stores the model vertices offsets
+  kShaders = 12; // Stores the shader files (blending, anims..)
+  kFaces = 13; // Stores the faces for the level
+  kLightmaps = 14; // Stores the lightmaps for the level
+  kLightVolumes = 15; // Stores extra world lighting information
+  kVisData = 16; // Stores PVS and cluster info (visibility)
+  kMaxLumps = 17; // A constant to store the number of lumps
+
+implementation // -----------------------------------------------------------
+
+// ------------------
+// ------------------ TQ3BSP ------------------
+// ------------------
+
+constructor TQ3BSP.Create(bspStream: TStream);
+begin
+  SetLength(Lumps, kMaxLumps);
+
+  // Read in the header and lump data
+  bspStream.Read(Header, SizeOf(Header));
+  bspStream.Read(Lumps[0], kMaxLumps * SizeOf(TBSPLump));
+
+  NumOfNodes := Round(Lumps[kNodes].Length / SizeOf(TBSPNode));
+  SetLength(Nodes, NumOfNodes);
+  bspStream.Position := Lumps[kNodes].Offset;
+  bspStream.Read(Nodes[0], NumOfNodes * SizeOf(TBSPNode));
+
+  NumOfPlanes := Round(Lumps[kPlanes].Length / SizeOf(TVector4f));
+  SetLength(Planes, NumOfPlanes);
+  bspStream.Position := Lumps[kPlanes].Offset;
+  bspStream.Read(Planes[0], NumOfPlanes * SizeOf(TVector4f));
+
+  NumOfLeaves := Round(Lumps[kLeafs].Length / SizeOf(TBSPLeaf));
+  SetLength(Leaves, NumOfLeaves);
+  bspStream.Position := Lumps[kLeafs].Offset;
+  bspStream.Read(Leaves[0], NumOfLeaves * SizeOf(TBSPLeaf));
+
+  numOfVerts := Round(Lumps[kVertices].Length / SizeOf(TBSPVertex));
+  SetLength(Vertices, numOfVerts);
+  bspStream.Position := Lumps[kVertices].Offset;
+  bspStream.Read(Vertices[0], numOfVerts * SizeOf(TBSPVertex));
+
+  NumOfFaces := Round(Lumps[kFaces].Length / SizeOf(TBSPFace));
+  SetLength(Faces, NumOfFaces);
+  bspStream.Position := Lumps[kFaces].Offset;
+  bspStream.Read(Faces[0], NumOfFaces * SizeOf(TBSPFace));
+
+  NumOfTextures := Round(Lumps[kTextures].Length / SizeOf(TBSPTexture));
+  SetLength(Textures, NumOfTextures);
+  bspStream.Position := Lumps[kTextures].Offset;
+  bspStream.Read(Textures[0], NumOfTextures * SizeOf(TBSPTexture));
+
+  NumOfLightmaps := Round(Lumps[kLightmaps].Length / SizeOf(TBSPLightmap));
+  SetLength(Lightmaps, NumOfLightmaps);
+  bspStream.Position := Lumps[kLightmaps].Offset;
+  bspStream.Read(Lightmaps[0], NumOfLightmaps * SizeOf(TBSPLightmap));
+
+  bspStream.Position := Lumps[kVisData].Offset;
+  bspStream.Read(VisData.numOfClusters, SizeOf(Integer));
+  bspStream.Read(VisData.bytesPerCluster, SizeOf(Integer));
+  if VisData.numOfClusters * VisData.bytesPerCluster > 0 then
+  begin
+    SetLength(VisData.bitSets, VisData.numOfClusters * VisData.bytesPerCluster);
+    bspStream.Read(VisData.bitSets[0], VisData.numOfClusters *
+      VisData.bytesPerCluster);
+  end;
+end;
+
+end.

+ 1 - 1
Sourcex/Formatx.Q3MD3.pas

@@ -20,7 +20,7 @@ uses
 
   GXS.VectorFileObjects,
   GXS.Material,
-  Formats.MD3;
+  Formatx.MD3;
 
 type
   (* This class is used to extract the tag transform information

+ 4640 - 0
Sourcex/Formatx.VFW.pas

@@ -0,0 +1,4640 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.VFW;
+
+(****************************************************************************
+ *
+ *      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 )                          *)
+(*                                                                            *)
+(******************************************************************************)
+
+interface
+
+{.$UNDEF UNICODE}
+{$I GLScene.Defines.inc}
+
+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.

+ 2969 - 0
Sourcex/Formatx.m3DS.pas

@@ -0,0 +1,2969 @@
+//
+// The graphics engine GLScene https://github.com/glscene
+//
+unit Formatx.m3DS;
+
+(*
+  Implementation of an universal 3DS file reader (and writer). This is the main file of the
+  3DS import library. Currently only loading of 3DS files (Mesh files  * .3ds, Project files  * .prj
+  and Material files  * .mli) is supported.
+  Note: Be careful when using LoadFromStream, because chunk data (in opposition to the
+  chunk structure) will be loaded on demand, i.e. when it is needed. Therefore the
+  passed stream must be available during load.
+  LoadFromStream does not make a copy of the passed stream, but keeps a reference
+  which must stay valid either during the entire lifetime of TFile3DS or at least
+  'til all chunks have been read (by accessing them all once).
+*)
+
+interface
+
+{$I GLScene.Defines.inc}
+
+{$ALIGN ON}
+{$MINENUMSIZE 4}
+{$RANGECHECKS OFF}
+
+uses 
+  System.Classes, 
+  System.SysUtils,
+
+  Formatx.m3DSTypes;
+
+type
+  TFile3DS = class;
+
+  TLoadProgress = procedure(StreamPos, StreamMax: Longint) of object;
+  // Progress : TProgressBar;
+  //
+  // This allows to use something like that:
+  //
+  // procedure TSomeForm.CreateForm(Sender: TObject);
+  // begin
+  // ....
+  // 3DSReader.OnProgress := LoadProgress;
+  // ....
+  // end;
+
+  // procedure TSomeForm.LoadProgress(StreamPos, StreamMax : Longint);
+  // begin
+  // if StreamMax <> 0 then
+  // Progress.MaxValue := StreamMax;
+  // Progress.Position := StreamPos;
+  // end;
+
+  // ----- support classes -----
+  // All structure data of a 3DS file is actually held in TFile3DS.FDatabase as a
+  // tree with lots of links across the various chunks.
+  // For convinience and speed the data of the chunks is collected into some
+  // special structures (FMaterialList etc.) and presented to the user
+  // by the following helper classes:
+
+  TMaterialList = class
+  private
+    FOwner: TFile3DS;
+    FLocalList: TList;
+    function GetCount: Integer;
+    function GetMaterial(Index: Integer): PMaterial3DS;
+    function GetMaterialByName(const Name: String): PMaterial3DS;
+  public
+    constructor Create(AOwner: TFile3DS); virtual;
+    destructor Destroy; override;
+    procedure ClearList;
+    property Count: Integer read GetCount;
+    property Material[Index: Integer]: PMaterial3DS read GetMaterial; default;
+    property MaterialByName[const Name: String]: PMaterial3DS read GetMaterialByName;
+  end;
+
+  TObjectList = class
+  private
+    FOwner: TFile3DS;
+    FMeshList, 
+	FOmniList, 
+	FSpotList, 
+	FCameraList: TList;
+    function GetCamera(Index: Integer): PCamera3DS;
+    function GetCamCount: Integer;
+    function GetMeshObjectCount: Integer;
+    function GetMesh(Index: Integer): PMesh3DS;
+    function GetOmniCount: Integer;
+    function GetOmniLight(Index: Integer): PLight3DS;
+    function GetSpotCount: Integer;
+    function GetSpotLight(Index: Integer): PLight3DS;
+  public
+    constructor Create(AOwner: TFile3DS); virtual;
+    destructor Destroy; override;
+    procedure ClearLists;
+    property CameraCount: Integer read GetCamCount;
+    property MeshCount: Integer read GetMeshObjectCount;
+    property OmniLightCount: Integer read GetOmniCount;
+    property SpotLightCount: Integer read GetSpotCount;
+    property Mesh[Index: Integer]: PMesh3DS read GetMesh;
+    property Camera[Index: Integer]: PCamera3DS read GetCamera;
+    property OmniLight[Index: Integer]: PLight3DS read GetOmniLight;
+    property SpotLight[Index: Integer]: PLight3DS read GetSpotLight;
+  end;
+
+  TKeyFramer = class
+  private
+    FOwner: TFile3DS;
+    FMeshMotionList,
+	FOmniMotionList, 
+	FSpotMotionList, 
+	FCameraMotionList: TList;
+    FAmbientMotion: PKFAmbient3DS;
+    function GetAmbientMotion: PKFAmbient3DS;
+    function GetCameraMotion(Index: Integer): PKFCamera3DS;
+    function GetCamMotionCount: Integer;
+    function GetKFSets: TKFSets3DS;
+    function GetMeshMotionCount: Integer;
+    function GetMeshMotion(Index: Integer): PKFMesh3DS;
+    function GetOmniMotionCount: Integer;
+    function GetOmniLightMotion(Index: Integer): PKFOmni3DS;
+    function GetSpotMotionCount: Integer;
+    function GetSpotLightMotion(Index: Integer): PKFSpot3DS;
+  public
+    constructor Create(AOwner: TFile3DS); virtual;
+    destructor Destroy; override;
+    procedure ClearLists;
+    property AmbientLightMotion: PKFAmbient3DS read GetAmbientMotion;
+    property CameraMotionCount: Integer read GetCamMotionCount;
+    property MeshMotionCount: Integer read GetMeshMotionCount;
+    property OmniLightMotionCount: Integer read GetOmniMotionCount;
+    property SpotLightMotionCount: Integer read GetSpotMotionCount;
+    property MeshMotion[Index: Integer]: PKFMesh3DS read GetMeshMotion; default;
+    property CameraMotion[Index: Integer]: PKFCamera3DS read GetCameraMotion;
+    property OmniLightMotion[Index: Integer]: PKFOmni3DS read GetOmniLightMotion;
+    property Settings: TKFSets3DS read GetKFSets;
+    property SpotLightMotion[Index: Integer]: PKFSpot3DS read GetSpotLightMotion;
+  end;
+
+  (* The main class that supplies the user with all available data
+    from a specific 3DS file. The data is currently read only, but the class might be
+    finished sometime later... *)
+  TFile3DS = class
+  private
+    FNodeList: PNodeList;
+    FDatabase: TDatabase3DS;
+    FStream: TStream;
+    FOwnStream: Boolean;
+    FMaterialList: TMaterialList;
+    FObjectList: TObjectList;
+    FKeyFramer: TKeyFramer;
+    FFileName: String;
+    FOnLoadProgress: TLoadProgress;
+    function GetAtmosphereData: TAtmosphere3DS;
+    function GetBackgroundData: TBackground3DS;
+    function GetDatabaseType: TDBType3DS;
+    function GetMeshSettings: TMeshSet3DS;
+    function GetViewportData: TViewport3DS;
+    function GetDatabaseRelease: TReleaseLevel;
+    function GetMeshRelease: TReleaseLevel;
+  protected
+    procedure AddToNodeList(Chunk: PChunk3DS);
+    procedure AssignParentNames;
+    procedure CheckListNodeIDs;
+    procedure CreateDatabase;
+    function FindNodeByID(ID: SmallInt): PNodeList;
+    function GetChunkNodeID(Chunk: PChunk3DS): SmallInt;
+    procedure InitDatabase;
+    function IsNode(Tag: Word): Boolean;
+    procedure KFAddParentName(Chunk: PChunk3DS; const Name: String3DS);
+    procedure MakeNode(var Node: PNodeList);
+    procedure ParseDatabase;
+    procedure ReadChildren(Parent: PChunk3DS);
+    procedure ReadXDataEntryChildren(Parent: PChunk3DS);
+    procedure ReleaseDatabase;
+    procedure ReleaseNodeList;
+    procedure ReleaseStream;
+  public
+    constructor Create; virtual;
+    constructor CreateFromFile(const FileName: String); virtual;
+    destructor Destroy; override;
+    procedure ClearLists;
+    // database methods
+    procedure DumpDataBase(Strings: TStrings; DumpLevel: TDumpLevel);
+    procedure LoadFromFile(const FileName: String);
+    procedure LoadFromStream(const aStream: TStream);
+    // basic access methods
+    function ReadByte: Byte;
+    function ReadCardinal: Cardinal;
+    procedure ReadChunkData(Chunk: PChunk3DS);
+    procedure ReadData(Size: Integer; Data: Pointer);
+    function ReadDouble: Double;
+    function ReadFace: TFace3DS;
+    procedure ReadHeader(var ChunkType: Word; var ChunkSize: Cardinal);
+    function ReadInteger: Integer;
+    function ReadKeyHeader: TKeyHeader3DS;
+    function ReadPoint: TPoint3DS;
+    function ReadShort: SmallInt;
+    function ReadSingle: Single;
+    function ReadString: PChar3DS;
+    function ReadTexVert: TTexVert3DS;
+    function ReadTrackHeader: TTrackHeader3DS;
+    function ReadWord: Word;
+    procedure FinishHeader(StartPos, EndPos: Cardinal);
+    function InitChunkData(Chunk: PChunk3DS): Pointer;
+    procedure SeekChild(Chunk: PChunk3DS);
+    procedure Skip(AValue: Integer);
+    procedure WriteByte(AValue: Byte);
+    procedure WriteCardinal(AValue: Cardinal);
+    procedure WriteData(Size: Integer; Data: Pointer);
+    procedure WriteDouble(AValue: Double);
+    procedure WriteFace(const F: TFace3DS);
+    procedure WriteFixedString(const AValue: String3DS; Len: Integer);
+    procedure WriteHeader(ChunkType: Word; ChunkSize: Cardinal);
+    procedure WriteInteger(AValue: Integer);
+    procedure WriteKeyHeader(const K: TKeyHeader3DS);
+    procedure WritePoint(const P: TPoint3DS);
+    procedure WriteShort(AValue: SmallInt);
+    procedure WriteSingle(AValue: Single);
+    procedure WriteString(const AValue: String3DS);
+    procedure WriteTexVertex(const T: TTexVert3DS);
+    procedure WriteTrackHeader(const T: TTrackHeader3DS);
+    procedure WriteWord(AValue: Word);
+    property Atmosphere: TAtmosphere3DS read GetAtmosphereData;
+    property Background: TBackground3DS read GetBackgroundData;
+    property DatabaseRelease: TReleaseLevel read GetDatabaseRelease;
+    property DatabaseType: TDBType3DS read GetDatabaseType;
+    property FileName: String read FFileName;
+    // this is only valid if loaded from a file
+    property KeyFramer: TKeyFramer read FKeyFramer;
+    property Materials: TMaterialList read FMaterialList;
+    property MeshRelease: TReleaseLevel read GetMeshRelease;
+    property MeshSettings: TMeshSet3DS read GetMeshSettings;
+    property Objects: TObjectList read FObjectList;
+    property Viewport: TViewport3DS read GetViewportData;
+    property OnLoadProgress: TLoadProgress read FOnLoadProgress write FOnLoadProgress;
+  end;
+
+implementation // -------------------------------------------------------------
+
+uses
+  Formatx.m3DSConst,
+  Formatx.m3DSUtils;
+
+function StrPasFree(P: PChar3DS): String;
+begin
+  Result := string(StrPas(P));
+  FreeMem(P);
+end;
+
+// ----------------- TMaterialList --------------------------------------------
+
+constructor TMaterialList.Create(AOwner: TFile3DS);
+
+begin
+  FOwner := AOwner;
+  FLocalList := TList.Create;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+destructor TMaterialList.Destroy;
+
+begin
+  ClearList;
+  FLocalList.Free;
+  inherited Destroy;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TMaterialList.ClearList;
+
+var
+  I: Integer;
+  Mat: PMaterial3DS;
+
+begin
+  for I := 0 to FLocalList.Count - 1 do
+    if FLocalList[I] <> nil then
+    begin
+      Mat := FLocalList[I];
+      // free structure data
+      ReleaseMaterial(Mat);
+    end;
+  FLocalList.Count := 0;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TMaterialList.GetCount: Integer;
+
+begin
+  if (FLocalList.Count = 0) and (FOwner.FDatabase.MatListDirty) then
+    FLocalList.Count := GetMaterialCount(FOwner, FOwner.FDatabase);;
+  Result := FLocalList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TMaterialList.GetMaterial(Index: Integer): PMaterial3DS;
+
+var
+  NewEntry: PMaterial3DS;
+
+begin
+  Result := nil;
+  if Count = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FLocalList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetMaterialByIndex(FOwner, FOwner.FDatabase, Index);
+    FLocalList[Index] := NewEntry;
+  end;
+  Result := FLocalList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TMaterialList.GetMaterialByName(const Name: String): PMaterial3DS;
+
+var
+  Entry: PMaterial3DS;
+  Index: Integer;
+
+begin
+  Result := nil;
+  for Index := 0 to Count - 1 do
+  begin
+    Entry := GetMaterial(Index);
+    if Entry = nil then
+      Continue;
+    if CompareText(string(Entry.NameStr), Name) = 0 then
+    begin
+      Result := Entry;
+      Break;
+    end;
+  end;
+end;
+
+// ----------------- TObjectList ---------------------------------------------------------------------------------------
+
+constructor TObjectList.Create(AOwner: TFile3DS);
+
+begin
+  FOwner := AOwner;
+  FMeshList := TList.Create;
+  FOmniList := TList.Create;
+  FSpotList := TList.Create;
+  FCameraList := TList.Create;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+destructor TObjectList.Destroy;
+
+begin
+  ClearLists;
+  FMeshList.Free;
+  FOmniList.Free;
+  FSpotList.Free;
+  FCameraList.Free;
+  inherited Destroy;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TObjectList.ClearLists;
+
+var
+  I: Integer;
+
+begin
+  for I := 0 to FMeshList.Count - 1 do
+    ReleaseMeshObj(FMeshList[I]);
+  FMeshList.Clear;
+
+  for I := 0 to FOmniList.Count - 1 do
+    ReleaseLight(FOmniList[I]);
+  FOmniList.Clear;
+
+  for I := 0 to FSpotList.Count - 1 do
+    ReleaseLight(FSpotList[I]);
+  FSpotList.Clear;
+
+  for I := 0 to FCameraList.Count - 1 do
+    ReleaseCamera(FCameraList[I]);
+  FCameraList.Clear;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetCamera(Index: Integer): PCamera3DS;
+
+var
+  NewEntry: PCamera3DS;
+
+begin
+  Result := nil;
+  if CameraCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FCameraList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetCameraByIndex(FOwner, FOwner.FDatabase, Index);
+    FCameraList[Index] := NewEntry;
+  end;
+  Result := FCameraList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetCamCount: Integer;
+
+begin
+  if FCameraList.Count = 0 then
+    FCameraList.Count := GetCameraCount(FOwner, FOwner.FDatabase);
+  Result := FCameraList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetMeshObjectCount: Integer;
+
+begin
+  if FMeshList.Count = 0 then
+    FMeshList.Count := GetMeshCount(FOwner, FOwner.FDatabase);
+  Result := FMeshList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetMesh(Index: Integer): PMesh3DS;
+
+var
+  NewEntry: PMesh3DS;
+
+begin
+  Result := nil;
+  if MeshCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FMeshList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetMeshByIndex(FOwner, FOwner.FDatabase, Index);
+    FMeshList[Index] := NewEntry;
+  end;
+  Result := FMeshList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetOmniCount: Integer;
+
+begin
+  if FOmniList.Count = 0 then
+    FOmniList.Count := GetOmniLightCount(FOwner, FOwner.FDatabase);
+  Result := FOmniList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetOmniLight(Index: Integer): PLight3DS;
+
+var
+  NewEntry: PLight3DS;
+
+begin
+  Result := nil;
+  if OmniLightCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FOmniList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetOmniLightByIndex(FOwner, FOwner.FDatabase, Index);
+    FOmniList[Index] := NewEntry;
+  end;
+  Result := FOmniList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetSpotCount: Integer;
+
+begin
+  if FSpotList.Count = 0 then
+    FSpotList.Count := GetSpotLightCount(FOwner, FOwner.FDatabase);
+  Result := FSpotList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TObjectList.GetSpotLight(Index: Integer): PLight3DS;
+
+var
+  NewEntry: PLight3DS;
+
+begin
+  Result := nil;
+  if SpotLightCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FSpotList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetSpotLightByIndex(FOwner, FOwner.FDatabase, Index);
+    FSpotList[Index] := NewEntry;
+  end;
+  Result := FSpotList[Index];
+end;
+
+// ----------------- TKeyFramer ----------------------------------------------------------------------------------------
+
+constructor TKeyFramer.Create(AOwner: TFile3DS);
+
+begin
+  FOwner := AOwner;
+  FMeshMotionList := TList.Create;
+  FOmniMotionList := TList.Create;
+  FSpotMotionList := TList.Create;
+  FCameraMotionList := TList.Create;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+destructor TKeyFramer.Destroy;
+
+begin
+  ClearLists;
+  FMeshMotionList.Free;
+  FOmniMotionList.Free;
+  FSpotMotionList.Free;
+  FCameraMotionList.Free;
+  inherited;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetAmbientMotion: PKFAmbient3DS;
+
+begin
+  if FAmbientMotion = nil then
+  begin
+    New(FAmbientMotion);
+    FillChar(FAmbientMotion^, SizeOf(FAmbientMotion^), 0);
+    FAmbientMotion^ := GetAmbientLightMotion(FOwner, FOwner.FDatabase);
+  end;
+  Result := FAmbientMotion;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetCameraMotion(Index: Integer): PKFCamera3DS;
+
+var
+  NewEntry: PKFCamera3DS;
+
+begin
+  Result := nil;
+  if CameraMotionCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FCameraMotionList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetCameraMotionByIndex(FOwner, FOwner.FDatabase, Index);
+    FCameraMotionList[Index] := NewEntry;
+  end;
+  Result := FCameraMotionList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetCamMotionCount: Integer;
+
+begin
+  if FCameraMotionList.Count = 0 then
+    FCameraMotionList.Count := GetCameraNodeCount(FOwner, FOwner.FDatabase);
+  Result := FCameraMotionList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetKFSets: TKFSets3DS;
+
+begin
+  Result := GetKFSettings(FOwner, FOwner.FDatabase);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetMeshMotionCount: Integer;
+
+begin
+  if FMeshMotionList.Count = 0 then
+    FMeshMotionList.Count := GetObjectNodeCount(FOwner, FOwner.FDatabase);
+  Result := FMeshMotionList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetMeshMotion(Index: Integer): PKFMesh3DS;
+
+var
+  NewEntry: PKFMesh3DS;
+
+begin
+  Result := nil;
+  if MeshMotionCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FMeshMotionList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetObjectMotionByIndex(FOwner, FOwner.FDatabase, Index);
+    FMeshMotionList[Index] := NewEntry;
+  end;
+  Result := FMeshMotionList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetOmniMotionCount: Integer;
+
+begin
+  if FOmniMotionList.Count = 0 then
+    FOmniMotionList.Count := GetOmniLightNodeCount(FOwner, FOwner.FDatabase);
+  Result := FOmniMotionList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetOmniLightMotion(Index: Integer): PKFOmni3DS;
+
+var
+  NewEntry: PKFOmni3DS;
+
+begin
+  Result := nil;
+  if OmniLightMotionCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FOmniMotionList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetOmniLightMotionByIndex(FOwner, FOwner.FDatabase, Index);
+    FOmniMotionList[Index] := NewEntry;
+  end;
+  Result := FOmniMotionList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetSpotMotionCount: Integer;
+
+begin
+  if FSpotMotionList.Count = 0 then
+    FSpotMotionList.Count := GetSpotLightNodeCount(FOwner, FOwner.FDatabase);
+  Result := FSpotMotionList.Count;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TKeyFramer.GetSpotLightMotion(Index: Integer): PKFSpot3DS;
+
+var
+  NewEntry: PKFSpot3DS;
+
+begin
+  Result := nil;
+  if SpotLightMotionCount = 0 then
+    Exit; // force reading the list if it was modified
+
+  if FSpotMotionList[Index] = nil then
+  begin
+    New(NewEntry);
+    FillChar(NewEntry^, SizeOf(NewEntry^), 0);
+    NewEntry^ := GetSpotLightMotionByIndex(FOwner, FOwner.FDatabase, Index);
+    FSpotMotionList[Index] := NewEntry;
+  end;
+  Result := FSpotMotionList[Index];
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TKeyFramer.ClearLists;
+
+var
+  I: Integer;
+
+begin
+  for I := 0 to FMeshMotionList.Count - 1 do
+    ReleaseObjectMotion(FMeshMotionList[I]);
+  FMeshMotionList.Clear;
+
+  for I := 0 to FOmniMotionList.Count - 1 do
+    ReleaseOmnilightMotion(FOmniMotionList[I]);
+  FOmniMotionList.Clear;
+
+  for I := 0 to FSpotMotionList.Count - 1 do
+    ReleaseSpotlightMotion(FSpotMotionList[I]);
+  FSpotMotionList.Clear;
+
+  for I := 0 to FCameraMotionList.Count - 1 do
+    ReleaseCameraMotion(FCameraMotionList[I]);
+  FCameraMotionList.Clear;
+
+  if assigned(FAmbientMotion) then
+    ReleaseAmbientLightMotion(FAmbientMotion);
+  FAmbientMotion := nil;
+end;
+
+// ----------------- TFile3DS ------------------------------------------------------------------------------------------
+
+constructor TFile3DS.Create;
+
+begin
+  FMaterialList := TMaterialList.Create(Self);
+  FObjectList := TObjectList.Create(Self);
+  FKeyFramer := TKeyFramer.Create(Self);
+end;
+
+constructor TFile3DS.CreateFromFile(const FileName: String);
+begin
+  Create;
+  FFileName := FileName;
+  FStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+  InitDatabase;
+  CreateDatabase;
+end;
+
+destructor TFile3DS.Destroy;
+begin
+  FKeyFramer.Free;
+  FObjectList.Free;
+  FMaterialList.Free;
+  ReleaseDatabase;
+  ReleaseStream;
+  inherited Destroy;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.AddToNodeList(Chunk: PChunk3DS);
+
+// creates a node, put node in list and fill-in structure
+
+var
+  NewNode: PNodeList;
+  HdrChunk, InstChunk: PChunk3DS;
+
+begin
+  MakeNode(NewNode);
+  if NewNode = nil then
+    Exit;
+
+  HdrChunk := FindChunk(Chunk, NODE_HDR);
+  if HdrChunk = nil then
+    Exit;
+
+  ReadChunkData(HdrChunk);
+  if HdrChunk = nil then
+    Exit;
+
+  // fill in node Data
+  NewNode.Name := HdrChunk.Data.NodeHdr.ObjNameStr;
+  NewNode.ID := GetChunkNodeID(Chunk);
+  NewNode.Tag := Chunk.Tag;
+  NewNode.ParentID := HdrChunk.Data.NodeHdr.ParentIndex;
+  NewNode.Next := nil;
+  NewNode.InstStr := '';
+
+  // check for instance
+  if Chunk.Tag = OBJECT_NODE_TAG then
+  begin
+    InstChunk := FindChunk(Chunk, INSTANCE_NAME);
+    if assigned(InstChunk) then
+    begin
+      ReadChunkData(InstChunk);
+      NewNode.InstStr := string(StrPas(InstChunk.Data.InstanceName));
+      FreeChunkData(InstChunk);
+    end;
+  end;
+  HdrChunk.Data.NodeHdr.ObjNameStr := '';
+  FreeChunkData(HdrChunk);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.AssignParentNames;
+
+// traverse keyframe data and assign parent names to its own chunk PARENT_NAME
+// which is a child of NODE_HDR
+
+var
+  Chunk, KfDataChunk, HdrChunk, NameChunk, IdChunk: PChunk3DS;
+  I: Integer;
+  IDNode, IDParentNode: PNodeList;
+  Name, Inst: String3DS;
+
+begin
+  KfDataChunk := FindChunk(FDatabase.TopChunk, KFDATA);
+  if KfDataChunk = nil then
+    Exit;
+
+  // Find chunks in KFRAMER
+  for I := 1 to NodeTagCount do
+  begin
+    Chunk := FindChunk(KfDataChunk, NodeTags[I]);
+    while assigned(Chunk) do
+    begin
+      HdrChunk := FindChunk(Chunk, NODE_HDR);
+      if assigned(HdrChunk) then
+      begin
+        IdChunk := FindChunk(Chunk, NODE_ID);
+        if assigned(IdChunk) then
+        begin
+          ReadChunkData(IdChunk);
+          if assigned(IdChunk.Data.KFID) then
+          begin
+            // Find table entry for node of interest
+            IDNode := FindNodeByID(IdChunk.Data.KFID^);
+            // no ID (bad) or no parent (ok)
+            if assigned(IDNode) and (IDNode.ParentID <> -1) then
+            begin
+              // find table entry for parent
+              IDParentNode := FindNodeByID(IDNode.ParentID);
+              if assigned(IDParentNode) then
+              begin
+                Name := UTF8String(IDParentNode.Name);
+                Inst := UTF8String(IDParentNode.InstStr);
+              end;
+
+              if Length(Name) > 0 then
+              begin
+                // concatenate names if there is an inst name
+                if Length(Inst) > 0 then
+                  Name := Name + '.' + Inst;
+
+                // if PARENT chunk exists, copy into it
+                NameChunk := FindChunk(HdrChunk, PARENT_NAME);
+                if assigned(NameChunk) then
+                begin
+                  ReadChunkData(NameChunk);
+                  if assigned(NameChunk.Data.InstanceName) then
+                  begin
+                    NameChunk.Data.InstanceName := AllocMem(Length(Name) + 1);
+                    Move(Name[1], NameChunk.Data.InstanceName^,  Length(Name) + 1);
+                  end;
+                end
+                else
+                  KFAddParentName(HdrChunk, Name); // creates PARENT_NAME chunk
+              end;
+            end;
+          end;
+        end;
+      end;
+      Chunk := FindNextChunk(Chunk.Sibling, NodeTags[I]);
+    end;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.CheckListNodeIDs;
+
+// Earlier versions (pre 3) of 3dStudio had no node ids, they simply used the order
+// in which they came along, if so put in NODE IDs. Assuming that if one node
+// has no ID the whole list get renumbered.
+
+var
+  ID: PNodeList;
+  Index: SmallInt;
+
+begin
+  ID := FNodeList;
+
+  while assigned(ID) do
+  begin
+    if (ID.ID = KNoID) then // if somebody has no ID renumber list
+    begin
+      Index := 0;
+      ID := FNodeList;
+      while assigned(ID) do
+      begin
+        ID.ID := Index;
+        Inc(Index);
+        ID := ID.Next;
+      end;
+      Break;
+    end;
+    ID := ID.Next;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.FindNodeByID(ID: SmallInt): PNodeList;
+
+begin
+  Result := FNodeList;
+  while assigned(Result) do
+  begin
+    if Result.ID = ID then
+      Break;
+    Result := Result.Next;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.DumpDataBase(Strings: TStrings; DumpLevel: TDumpLevel);
+
+// dumps entire database into the given string class
+
+var
+  OldSeparator: Char;
+
+begin
+
+  OldSeparator := FormatSettings.DecimalSeparator;
+  FormatSettings.DecimalSeparator := '.';
+  try
+    if Assigned(FDatabase.TopChunk) then
+      DumpChunk(Self, Strings, FDatabase.TopChunk, 0, DumpLevel);
+  finally
+    FormatSettings.DecimalSeparator := OldSeparator;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetChunkNodeID(Chunk: PChunk3DS): SmallInt;
+
+var
+  IdChunk: PChunk3DS;
+
+begin
+  Result := KNoID;
+  IdChunk := FindChunk(Chunk, NODE_ID);
+  if assigned(IdChunk) then
+  begin
+    ReadChunkData(IdChunk);
+    if assigned(IdChunk.Data.KFID) then
+      Result := IdChunk.Data.KFID^;
+    FreeChunkData(IdChunk);
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.IsNode(Tag: Word): Boolean;
+
+var
+  I: Integer;
+
+begin
+  Result := False;
+  for I := 1 to NodeTagCount do
+    if Tag = NodeTags[I] then
+    begin
+      Result := True;
+      Break;
+    end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.KFAddParentName(Chunk: PChunk3DS; const Name: String3DS);
+var
+  Temp: PChunk3DS;
+begin
+  InitChunk(Temp);
+  Temp.Tag := PARENT_NAME;
+  Temp.Data.Dummy := AllocMem(Length(Name) + 1);
+  Move(Name[1], Temp.Data.Dummy^, Length(Name) + 1);
+  AddChildOrdered(Chunk, Temp);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.MakeNode(var Node: PNodeList);
+
+// add node to linked list (uninitialized)
+
+var
+  ID: PNodeList;
+
+begin
+  ID := FNodeList;
+  Node := AllocMem(SizeOf(TNodeList));
+  if assigned(Node) then
+  begin
+    // first node ?
+    if ID = nil then
+      FNodeList := Node
+    else // add to list
+    begin
+      while assigned(ID.Next) do
+        ID := ID.Next;
+      ID.Next := Node;
+    end;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ParseDatabase;
+
+var
+  Chunk, KfDataChunk: PChunk3DS;
+
+begin
+  KfDataChunk := FindChunk(FDatabase.TopChunk, KFDATA);
+  if assigned(KfDataChunk) then
+  begin
+    Chunk := KfDataChunk.Children;
+    while assigned(Chunk) do
+    begin
+      if IsNode(Chunk.Tag) then
+        AddToNodeList(Chunk);
+      Chunk := Chunk.Sibling;
+    end;
+    CheckListNodeIDs;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ReadXDataEntryChildren(Parent: PChunk3DS);
+
+var
+  ParentBody: Cardinal;
+  Child: PChunk3DS;
+
+begin
+  SeekChild(Parent);
+  ParentBody := Parent.Position + Parent.Size;
+
+  // satisfy the D4 compiler by castíng the (longint) position to a cardinal
+  while Cardinal(FStream.Position) < ParentBody do
+  begin
+    Child := nil;
+    InitChunk(Child);
+    Child.Position := FStream.Position;
+    ReadHeader(Child.Tag, Child.Size);
+    // Validate the child chunk...
+    // First, is it a valid header?
+    case Child.Tag of
+      XDATA_APPNAME, 
+	  XDATA_STRING, 
+	  XDATA_FLOAT, 
+	  XDATA_DOUBLE, 
+	  XDATA_SHORT,
+      XDATA_LONG, 
+	  XDATA_VOID, 
+	  XDATA_GROUP, 
+	  XDATA_RFU6, 
+	  XDATA_RFU5, 
+	  XDATA_RFU4,
+      XDATA_RFU3, 
+	  XDATA_RFU2, 
+	  XDATA_RFU1:
+        begin
+          // second, does the size fit inside the XDATA_ENTRY chunk?
+          if (Child.Position + Child.Size) <= ParentBody then
+          begin
+            // chances are its a good subchunk, so add it in
+            AddChild(Parent, Child);
+            ReadXDataEntryChildren(Child);
+          end
+          else
+            ReleaseChunk(Child);
+        end
+    else // must not be a valid chunk, seek to the end of the parent then
+      begin
+        ReleaseChunk(Child);
+        FStream.Position := ParentBody;
+      end;
+    end;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ReleaseNodeList;
+
+var
+  Next: PNodeList;
+
+begin
+  while assigned(FNodeList) do
+  begin
+    Next := FNodeList.Next;
+    Dispose(FNodeList);
+    FNodeList := Next;
+  end;
+end;
+
+procedure TFile3DS.ReleaseStream;
+begin
+  if FOwnStream then
+    FreeAndNil(FStream)
+  else
+    FStream := nil;
+  FOwnStream := False;
+end;
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.CreateDatabase;
+
+begin
+  with FDatabase do
+  begin
+    InitChunk(TopChunk);
+    FStream.Position := 0;
+    ReadHeader(TopChunk.Tag, TopChunk.Size);
+
+    // test header to determine whether it is a top level chunk type
+    if (TopChunk.Tag = M3DMAGIC) or (TopChunk.Tag = CMAGIC) or
+      (TopChunk.Tag = MLIBMAGIC) then
+    begin
+      // gw: set needed max value for ProgressBar
+      if assigned(FOnLoadProgress) then
+        FOnLoadProgress(0, FStream.Size);
+      // read database structure
+      ReadChildren(TopChunk);
+      ParseDatabase;
+      AssignParentNames;
+      ReleaseNodeList;
+    end;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.InitDatabase;
+
+begin
+  with FDatabase do
+  begin
+    TopChunk := nil;
+    ObjListDirty := True;
+    MatListDirty := True;
+    NodeListDirty := True;
+    ObjList := nil;
+    MatList := nil;
+    NodeList := nil;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ClearLists;
+
+begin
+  FMaterialList.ClearList;
+  FObjectList.ClearLists;
+  FKeyFramer.ClearLists;
+  ReleaseDatabase;
+end;
+
+procedure TFile3DS.LoadFromFile(const FileName: String);
+begin
+  ClearLists;
+  ReleaseStream;
+  FFileName := FileName;
+  FStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+  FOwnStream := True;
+  InitDatabase;
+  CreateDatabase;
+end;
+
+procedure TFile3DS.LoadFromStream(const aStream: TStream);
+begin
+  ReleaseStream;
+  ClearLists;
+  FFileName := '';
+  FStream := aStream;
+  InitDatabase;
+  CreateDatabase;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetAtmosphereData: TAtmosphere3DS;
+
+begin
+  Result := GetAtmosphere(Self, FDatabase);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetBackgroundData: TBackground3DS;
+
+begin
+  Result := GetBackground(Self, FDatabase);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetDatabaseType: TDBType3DS;
+
+begin
+  case FDatabase.TopChunk.Tag of
+    M3DMAGIC:
+      Result := dbMeshFile;
+    CMAGIC:
+      Result := dbProjectFile;
+    MLIBMAGIC:
+      Result := dbMaterialFile;
+  else
+    Result := dbUnknown;
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetMeshSettings: TMeshSet3DS;
+
+begin
+  Result := GetMeshSet(Self, FDatabase);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetViewportData: TViewport3DS;
+
+begin
+  Result := GetViewport(Self, FDatabase);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ReadChildren(Parent: PChunk3DS);
+
+var
+  ParentBody: Integer;
+  Child: PChunk3DS;
+
+begin
+  SeekChild(Parent);
+  ParentBody := Parent.Position + Parent.Size;
+  while FStream.Position < ParentBody do
+  begin
+    Child := nil;
+    InitChunk(Child);
+    // gw: set ProgressBar current position
+    if assigned(FOnLoadProgress) then
+      FOnLoadProgress(FStream.Position, 0);
+
+    Child.Position := FStream.Position;
+    ReadHeader(Child.Tag, Child.Size);
+    AddChild(Parent, Child);
+    if Child.Tag = XDATA_ENTRY then
+      ReadXDataEntryChildren(Child)
+    else
+      ReadChildren(Child);
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ReleaseDatabase;
+
+begin
+  with FDatabase do
+  begin
+    if assigned(TopChunk) then
+      ReleaseChunk(TopChunk);
+    if assigned(ObjList) then
+      ReleaseChunkList(ObjList);
+    if assigned(MatList) then
+      ReleaseChunkList(MatList);
+    if assigned(NodeList) then
+      ReleaseChunkList(NodeList);
+  end;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.InitChunkData(Chunk: PChunk3DS): Pointer;
+
+begin
+  case Chunk.Tag of
+    COLOR_F:
+      Chunk.Data.ColorF := AllocMem(SizeOf(TColorF));
+    LIN_COLOR_F:
+      Chunk.Data.LinColorF := AllocMem(SizeOf(TLinColorF));
+    COLOR_24:
+      Chunk.Data.Color24 := AllocMem(SizeOf(TColor24));
+    LIN_COLOR_24:
+      Chunk.Data.LinColor24 := AllocMem(SizeOf(TLinColor24));
+    INT_PERCENTAGE:
+      Chunk.Data.IntPercentage := AllocMem(SizeOf(TIntPercentage));
+    FLOAT_PERCENTAGE:
+      Chunk.Data.FloatPercentage := AllocMem(SizeOf(TFloatPercentage));
+    MAT_MAPNAME:
+      Chunk.Data.MatMapname := nil; // AllocMem(SizeOf(TMatMapname));
+    M3D_VERSION:
+      Chunk.Data.M3dVersion := AllocMem(SizeOf(TM3dVersion));
+    MESH_VERSION:
+      Chunk.Data.MeshVersion := AllocMem(SizeOf(TMeshVersion));
+    MASTER_SCALE:
+      Chunk.Data.MasterScale := AllocMem(SizeOf(TMasterScale));
+    LO_SHADOW_BIAS:
+      Chunk.Data.LoShadowBias := AllocMem(SizeOf(TLoShadowBias));
+    SHADOW_FILTER:
+      Chunk.Data.ShadowFilter := AllocMem(SizeOf(TShadowFilter));
+    SHADOW_RANGE:
+      Chunk.Data.ShadowRange := AllocMem(SizeOf(TShadowRange));
+    HI_SHADOW_BIAS:
+      Chunk.Data.HiShadowBias := AllocMem(SizeOf(THiShadowBias));
+    RAY_BIAS:
+      Chunk.Data.RayBias := AllocMem(SizeOf(TRayBias));
+    SHADOW_MAP_SIZE:
+      Chunk.Data.ShadowMapSize := AllocMem(SizeOf(TShadowMapSize));
+    SHADOW_SAMPLES:
+      Chunk.Data.ShadowSamples := AllocMem(SizeOf(TShadowSamples));
+    O_CONSTS:
+      Chunk.Data.OConsts := AllocMem(SizeOf(TOConsts));
+    BIT_MAP:
+      Chunk.Data.BitMapName := nil; // AllocMem(SizeOf(TBitMapName));
+    V_GRADIENT:
+      Chunk.Data.VGradient := AllocMem(SizeOf(TVGradient));
+    FOG:
+      Chunk.Data.FOG := AllocMem(SizeOf(TFog));
+    LAYER_FOG:
+      Chunk.Data.LayerFog := AllocMem(SizeOf(TLayerFog));
+    DISTANCE_CUE:
+      Chunk.Data.DistanceCue := AllocMem(SizeOf(TDistanceCue));
+    VIEW_TOP, 
+	VIEW_BOTTOM, 
+	VIEW_LEFT, 
+	VIEW_RIGHT, 
+	VIEW_FRONT, 
+	VIEW_BACK:
+      Chunk.Data.ViewStandard := AllocMem(SizeOf(TViewStandard));
+    VIEW_USER:
+      Chunk.Data.ViewUser := AllocMem(SizeOf(TViewUser));
+    VIEW_CAMERA:
+      Chunk.Data.ViewCamera := nil; // AllocMem(SizeOf(TViewCamera));
+    MAT_NAME:
+      Chunk.Data.MatName := nil; // AllocMem(SizeOf(TMatName));
+    MAT_SHADING:
+      Chunk.Data.MatShading := AllocMem(SizeOf(TMatShading));
+    MAT_ACUBIC:
+      Chunk.Data.MatAcubic := AllocMem(SizeOf(TMatAcubic));
+    MAT_SXP_TEXT_DATA, 
+	MAT_SXP_TEXT2_DATA, 
+	MAT_SXP_OPAC_DATA, 
+	MAT_SXP_BUMP_DATA,
+    MAT_SXP_SPEC_DATA, 
+	MAT_SXP_SHIN_DATA, 
+	MAT_SXP_SELFI_DATA,
+    MAT_SXP_TEXT_MASKDATA, 
+	MAT_SXP_TEXT2_MASKDATA, 
+	MAT_SXP_OPAC_MASKDATA,
+    MAT_SXP_BUMP_MASKDATA, 
+	MAT_SXP_SPEC_MASKDATA, 
+	MAT_SXP_SHIN_MASKDATA,
+    MAT_SXP_SELFI_MASKDATA, 
+	MAT_SXP_REFL_MASKDATA, 
+	PROC_DATA:
+      Chunk.Data.IpasData := AllocMem(SizeOf(TIpasData));
+    MAT_WIRESIZE:
+      Chunk.Data.MatWireSize := AllocMem(SizeOf(TMatWireSize));
+    MAT_MAP_TILING:
+      Chunk.Data.MatMapTiling := AllocMem(SizeOf(TMatMapTiling));
+    MAT_MAP_TEXBLUR:
+      Chunk.Data.MatMapTexblur := AllocMem(SizeOf(TMatMapTexblur));
+    MAT_MAP_USCALE:
+      Chunk.Data.MatMapUScale := AllocMem(SizeOf(TMatMapUScale));
+    MAT_MAP_VSCALE:
+      Chunk.Data.MatMapVScale := AllocMem(SizeOf(TMatMapVScale));
+    MAT_MAP_UOFFSET:
+      Chunk.Data.MatMapUOffset := AllocMem(SizeOf(TMatMapUOffset));
+    MAT_MAP_VOFFSET:
+      Chunk.Data.MatMapVOffset := AllocMem(SizeOf(TMatMapVOffset));
+    MAT_MAP_ANG:
+      Chunk.Data.MatMapAng := AllocMem(SizeOf(TMatMapAng));
+    MAT_MAP_COL1:
+      Chunk.Data.MatMapCol1 := AllocMem(SizeOf(TMatMapCol1));
+    MAT_MAP_COL2:
+      Chunk.Data.MatMapCol2 := AllocMem(SizeOf(TMatMapCol2));
+    MAT_MAP_RCOL:
+      Chunk.Data.MatMapRCol := AllocMem(SizeOf(TMatMapRCol));
+    MAT_MAP_GCOL:
+      Chunk.Data.MatMapGCol := AllocMem(SizeOf(TMatMapGCol));
+    MAT_MAP_BCOL:
+      Chunk.Data.MatMapBCol := AllocMem(SizeOf(TMatMapBCol));
+    MAT_BUMP_PERCENT:
+      Chunk.Data.MatBumpPercent := AllocMem(SizeOf(TMatBumpPercent));
+    NAMED_OBJECT:
+      Chunk.Data.NamedObject := nil; // AllocMem(SizeOf(TNamedObject));
+    POINT_ARRAY:
+      Chunk.Data.PointArray := AllocMem(SizeOf(TPointArray));
+    POINT_FLAG_ARRAY:
+      Chunk.Data.PointFlagArray := AllocMem(SizeOf(TPointFlagArray));
+    FACE_ARRAY:
+      Chunk.Data.FaceArray := AllocMem(SizeOf(TFaceArray));
+    MSH_MAT_GROUP:
+      Chunk.Data.MshMatGroup := AllocMem(SizeOf(TMshMatGroup));
+    MSH_BOXMAP:
+      Chunk.Data.MshBoxmap := AllocMem(SizeOf(TMshBoxmap));
+    SMOOTH_GROUP:
+      Chunk.Data.SmoothGroup := AllocMem(SizeOf(TSmoothGroup));
+    TEX_VERTS:
+      Chunk.Data.TexVerts := AllocMem(SizeOf(TTexVerts));
+    MESH_MATRIX:
+      Chunk.Data.MeshMatrix := AllocMem(SizeOf(TMeshMatrix));
+    MESH_COLOR:
+      Chunk.Data.MeshColor := AllocMem(SizeOf(TMeshColor));
+    MESH_TEXTURE_INFO:
+      Chunk.Data.MeshTextureInfo := AllocMem(SizeOf(TMeshTextureInfo));
+    PROC_NAME:
+      Chunk.Data.ProcName := nil; // AllocMem(SizeOf(TProcName));
+    N_DIRECT_LIGHT:
+      Chunk.Data.NDirectLight := AllocMem(SizeOf(TNDirectLight));
+    DL_EXCLUDE:
+      Chunk.Data.DlExclude := nil; // AllocMem(SizeOf(TDlExclude));
+    DL_INNER_RANGE:
+      Chunk.Data.DlInnerRange := AllocMem(SizeOf(TDlInnerRange));
+    DL_OUTER_RANGE:
+      Chunk.Data.DlOuterRange := AllocMem(SizeOf(TDlOuterRange));
+    DL_MULTIPLIER:
+      Chunk.Data.DlMultiplier := AllocMem(SizeOf(TDlMultiplier));
+    DL_SPOTLIGHT:
+      Chunk.Data.DlSpotlight := AllocMem(SizeOf(TDlSpotlight));
+    DL_LOCAL_SHADOW2:
+      Chunk.Data.DlLocalShadow2 := AllocMem(SizeOf(TDlLocalShadow2));
+    DL_SPOT_ROLL:
+      Chunk.Data.DlSpotRoll := AllocMem(SizeOf(TDlSpotRoll));
+    DL_SPOT_ASPECT:
+      Chunk.Data.DlSpotAspect := AllocMem(SizeOf(TDlSpotAspect));
+    DL_SPOT_PROJECTOR:
+      Chunk.Data.DlSpotProjector := nil; // AllocMem(SizeOf(TDlSpotProjector));
+    DL_RAY_BIAS:
+      Chunk.Data.DlRayBias := AllocMem(SizeOf(TDlRayBias));
+    N_CAMERA:
+      Chunk.Data.NCamera := AllocMem(SizeOf(TNCamera));
+    CAM_RANGES:
+      Chunk.Data.CamRanges := AllocMem(SizeOf(TCamRanges));
+    VIEWPORT_LAYOUT:
+      Chunk.Data.ViewportLayout := AllocMem(SizeOf(TViewportLayout));
+    VIEWPORT_SIZE:
+      Chunk.Data.ViewportSize := AllocMem(SizeOf(TViewportSize));
+    VIEWPORT_DATA_3, 
+	VIEWPORT_DATA:
+      Chunk.Data.ViewportData := AllocMem(SizeOf(TViewportData));
+    XDATA_ENTRY:
+      Chunk.Data.XDataEntry := AllocMem(SizeOf(TXDataEntry));
+    XDATA_APPNAME:
+      Chunk.Data.XDataAppName := nil; // AllocMem(SizeOf(TXDataAppName));
+    XDATA_STRING:
+      Chunk.Data.XDataString := nil; // AllocMem(SizeOf(TXDataString));
+    KFHDR:
+      Chunk.Data.KFHDR := AllocMem(SizeOf(TKFHdr));
+    KFSEG:
+      Chunk.Data.KFSEG := AllocMem(SizeOf(TKFSeg));
+    KFCURTIME:
+      Chunk.Data.KFCURTIME := AllocMem(SizeOf(TKFCurtime));
+    NODE_ID:
+      Chunk.Data.KFID := AllocMem(SizeOf(TKFId));
+    NODE_HDR:
+      Chunk.Data.NodeHdr := AllocMem(SizeOf(TNodeHdr));
+    PIVOT:
+      Chunk.Data.PIVOT := AllocMem(SizeOf(TPivot));
+    INSTANCE_NAME, PARENT_NAME:
+      Chunk.Data.InstanceName := nil; // AllocMem(SizeOf(TInstanceName));
+    MORPH_SMOOTH:
+      Chunk.Data.MorphSmooth := AllocMem(SizeOf(TMorphSmooth));
+    BOUNDBOX:
+      Chunk.Data.BOUNDBOX := AllocMem(SizeOf(TBoundBox));
+    POS_TRACK_TAG:
+      Chunk.Data.PosTrackTag := AllocMem(SizeOf(TPosTrackTag));
+    COL_TRACK_TAG:
+      Chunk.Data.ColTrackTag := AllocMem(SizeOf(TColTrackTag));
+    ROT_TRACK_TAG:
+      Chunk.Data.RotTrackTag := AllocMem(SizeOf(TRotTrackTag));
+    SCL_TRACK_TAG:
+      Chunk.Data.ScaleTrackTag := AllocMem(SizeOf(TScaleTrackTag));
+    MORPH_TRACK_TAG:
+      Chunk.Data.MorphTrackTag := AllocMem(SizeOf(TMorphTrackTag));
+    FOV_TRACK_TAG:
+      Chunk.Data.FovTrackTag := AllocMem(SizeOf(TFovTrackTag));
+    ROLL_TRACK_TAG:
+      Chunk.Data.RollTrackTag := AllocMem(SizeOf(TRollTrackTag));
+    HOT_TRACK_TAG:
+      Chunk.Data.HotTrackTag := AllocMem(SizeOf(THotTrackTag));
+    FALL_TRACK_TAG:
+      Chunk.Data.FallTrackTag := AllocMem(SizeOf(TFallTrackTag));
+    HIDE_TRACK_TAG:
+      Chunk.Data.HideTrackTag := AllocMem(SizeOf(THideTrackTag));
+    M3DMAGIC, // Chunks who consist entirely of children
+    MLIBMAGIC, 
+	MDATA, 
+	AMBIENT_LIGHT, 
+	SOLID_BGND, 
+	DEFAULT_VIEW, 
+	MAT_ENTRY,
+    MAT_AMBIENT, 
+	MAT_DIFFUSE, 
+	MAT_SPECULAR, 
+	MAT_SHININESS, 
+	MAT_SHIN2PCT,
+    MAT_SHIN3PCT, 
+	MAT_TRANSPARENCY, 
+	MAT_XPFALL, 
+	MAT_REFBLUR, 
+	MAT_SELF_ILPCT,
+    MAT_TEXMAP, 
+	MAT_TEXMASK, 
+	MAT_TEX2MAP, 
+	MAT_TEX2MASK, 
+	MAT_OPACMAP,
+    MAT_OPACMASK, 
+	MAT_REFLMAP, 
+	MAT_REFLMASK, 
+	MAT_BUMPMAP, 
+	MAT_BUMPMASK,
+    MAT_SPECMAP, 
+	MAT_SPECMASK, 
+	MAT_SHINMAP, 
+	MAT_SHINMASK, 
+	MAT_SELFIMAP,
+    MAT_SELFIMASK, 
+	N_TRI_OBJECT, 
+	KFDATA, 
+	AMBIENT_NODE_TAG, 
+	OBJECT_NODE_TAG,
+    CAMERA_NODE_TAG, 
+	TARGET_NODE_TAG, 
+	LIGHT_NODE_TAG, 
+	SPOTLIGHT_NODE_TAG,
+    L_TARGET_NODE_TAG, 
+	CMAGIC, 
+	XDATA_SECTION, 
+	XDATA_GROUP:
+      Chunk.Data.Dummy := nil;
+  else // A truely hideous thing to do but it helps with unknown chunks
+    // Don't mess with dataless chunks
+    if Chunk.Size > 6 then
+      Chunk.Data.Dummy := AllocMem(Chunk.Size - 6)
+    else
+      Chunk.Data.Dummy := nil;
+  end; // end of case
+  Result := Chunk.Data.Dummy; // returns the pointer should someone want it
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteByte(AValue: Byte);
+
+begin
+  FStream.WriteBuffer(AValue, 1);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadByte: Byte;
+
+begin
+  FStream.ReadBuffer(Result, 1);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteShort(AValue: SmallInt);
+
+begin
+  FStream.WriteBuffer(AValue, SizeOf(AValue));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadShort: SmallInt;
+
+begin
+  FStream.ReadBuffer(Result, SizeOf(Result));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadCardinal: Cardinal;
+
+begin
+  FStream.ReadBuffer(Result, SizeOf(Result));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadDouble: Double;
+
+begin
+  FStream.ReadBuffer(Result, SizeOf(Result));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadInteger: Integer;
+
+begin
+  FStream.ReadBuffer(Result, SizeOf(Result));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadSingle: Single;
+
+begin
+  FStream.ReadBuffer(Result, SizeOf(Result));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadWord: Word;
+
+begin
+  FStream.ReadBuffer(Result, SizeOf(Result));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteCardinal(AValue: Cardinal);
+
+begin
+  FStream.WriteBuffer(AValue, SizeOf(AValue));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteDouble(AValue: Double);
+
+begin
+  FStream.WriteBuffer(AValue, SizeOf(AValue));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteInteger(AValue: Integer);
+
+begin
+  FStream.WriteBuffer(AValue, SizeOf(AValue));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteSingle(AValue: Single);
+
+begin
+  FStream.WriteBuffer(AValue, SizeOf(AValue));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteWord(AValue: Word);
+
+begin
+  FStream.WriteBuffer(AValue, SizeOf(AValue));
+end;
+
+// WriteData
+//
+procedure TFile3DS.WriteData(Size: Integer; Data: Pointer);
+begin
+  if assigned(Data) then
+    FStream.WriteBuffer(Data^, Size);
+end;
+
+// ReadData
+//
+procedure TFile3DS.ReadData(Size: Integer; Data: Pointer);
+begin
+  FStream.ReadBuffer(Data^, Size);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.Skip(AValue: Integer);
+
+begin
+  FStream.Seek(soFromCurrent, AValue);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteString(const AValue: String3DS);
+
+begin
+  WriteData(Length(AValue), @AValue[1]);
+  WriteByte(0); // Write a null on the end of the string
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteFixedString(const AValue: String3DS; Len: Integer);
+
+var
+  I: Integer;
+
+begin
+  // len is the length of the target string space including null
+  WriteString(AValue); // 1 null byte will also be written
+  for I := 1 to Len - Length(AValue) - 1 do
+    WriteByte(0); // fill the remaining space with nulls
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadString: PChar3DS;
+var
+  Len, LB: Integer;
+  Buffer: String3DS;
+begin
+  Len := 0;
+  LB := 0;
+  repeat
+    if Len >= LB then
+    begin
+      Inc(LB, 50);
+      SetLength(Buffer, LB);
+    end;
+    Inc(Len);
+    FStream.Read(Buffer[Len], 1);
+  until Buffer[Len] = #0;
+  Result := AllocMem(Len);
+  Move(Buffer[1], Result^, Len);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteHeader(ChunkType: Word; ChunkSize: Cardinal);
+
+begin
+  WriteWord(ChunkType);
+  WriteCardinal(ChunkSize);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ReadHeader(var ChunkType: Word; var ChunkSize: Cardinal);
+
+begin
+  ChunkType := ReadWord;
+  ChunkSize := ReadCardinal;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.FinishHeader(StartPos, EndPos: Cardinal);
+
+begin
+  FStream.Position := StartPos + 2;
+  WriteCardinal(EndPos - StartPos);
+  FStream.Position := EndPos;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WritePoint(const P: TPoint3DS);
+
+begin
+  WriteSingle(P.X);
+  WriteSingle(P.Y);
+  WriteSingle(P.Z);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadPoint: TPoint3DS;
+
+begin
+  Result := DefPoint3DS;
+  FStream.ReadBuffer(Result, SizeOf(Result));
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteTexVertex(const T: TTexVert3DS);
+
+begin
+  WriteSingle(T.U);
+  WriteSingle(T.V);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadTexVert: TTexVert3DS;
+
+begin
+  Result := DefTextVert3DS;
+  Result.U := ReadSingle;
+  Result.V := ReadSingle;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteFace(const F: TFace3DS);
+
+begin
+  WriteWord(F.v1);
+  WriteWord(F.v2);
+  WriteWord(F.v3);
+  WriteWord(F.flag);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadFace: TFace3DS;
+
+begin
+  Result := DefFace3DS;
+  Result.v1 := ReadWord;
+  Result.v2 := ReadWord;
+  Result.v3 := ReadWord;
+  Result.flag := ReadWord;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteTrackHeader(const T: TTrackHeader3DS);
+
+begin
+  WriteWord(T.Flags);
+  WriteCardinal(T.nu1);
+  WriteCardinal(T.nu2);
+  WriteCardinal(T.KeyCount);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadTrackHeader: TTrackHeader3DS;
+
+begin
+  Result := DefTrackHeader3DS;
+  Result.Flags := ReadWord;
+  Result.nu1 := ReadCardinal;
+  Result.nu2 := ReadCardinal;
+  Result.KeyCount := ReadCardinal;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.WriteKeyHeader(const K: TKeyHeader3DS);
+
+begin
+  WriteCardinal(K.time);
+  WriteWord(K.rflags);
+  if (K.rflags and KeyUsesTension3DS) > 0 then
+    WriteSingle(K.tension);
+  if (K.rflags and KeyUsesCont3DS) > 0 then
+    WriteSingle(K.continuity);
+  if (K.rflags and KeyUsesBias3DS) > 0 then
+    WriteSingle(K.bias);
+  if (K.rflags and KeyUsesEaseTo3DS) > 0 then
+    WriteSingle(K.easeto);
+  if (K.rflags and KeyUsesEaseFrom3DS) > 0 then
+    WriteSingle(K.easefrom);
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.ReadKeyHeader: TKeyHeader3DS;
+
+begin
+  Result := DefKeyHeader3DS;
+  Result.time := ReadCardinal;
+  Result.rflags := ReadWord;
+  if (Result.rflags and KeyUsesTension3DS) > 0 then
+    Result.tension := ReadSingle;
+  if (Result.rflags and KeyUsesCont3DS) > 0 then
+    Result.continuity := ReadSingle;
+  if (Result.rflags and KeyUsesBias3DS) > 0 then
+    Result.bias := ReadSingle;
+  if (Result.rflags and KeyUsesEaseTo3DS) > 0 then
+    Result.easeto := ReadSingle;
+  if (Result.rflags and KeyUsesEaseFrom3DS) > 0 then
+    Result.easefrom := ReadSingle;
+end;
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.ReadChunkData(Chunk: PChunk3DS);
+
+// Reads the data out of the chunk detailed in Chunk and places a pointer to
+// the data into the PChunk3DS structure, it will also return that pointer.
+
+var
+  I: Integer;
+
+begin
+  if Chunk.Data.Dummy = nil then // don't try to read the data if its already been read
+  begin
+    // seek to the beginning of the Chunk's data (harmless if the Chunk has no data)
+    FStream.Position := Chunk.Position + 6;
+    case Chunk.Tag of
+      COLOR_F:
+        begin
+          Chunk.Data.ColorF := AllocMem(SizeOf(TColorF));  // allocate the memory to hold the data
+          with Chunk.Data.ColorF^ do
+          begin
+            Red := ReadSingle; // Read the data out of the file
+            Green := ReadSingle;
+            Blue := ReadSingle;
+          end;
+        end;
+      LIN_COLOR_F:
+        begin
+          Chunk.Data.LinColorF := AllocMem(SizeOf(TLinColorF));
+          with Chunk.Data.LinColorF^ do
+          begin
+            Red := ReadSingle;
+            Green := ReadSingle;
+            Blue := ReadSingle;
+          end;
+        end;
+      COLOR_24:
+        begin
+          Chunk.Data.Color24 := AllocMem(SizeOf(TColor24));
+          with Chunk.Data.Color24^ do
+          begin
+            Red := ReadByte;
+            Green := ReadByte;
+            Blue := ReadByte;
+          end;
+        end;
+      LIN_COLOR_24:
+        begin
+          Chunk.Data.LinColor24 := AllocMem(SizeOf(TLinColor24));
+          with Chunk.Data.LinColor24^ do
+          begin
+            Red := ReadByte;
+            Green := ReadByte;
+            Blue := ReadByte;
+          end;
+        end;
+      INT_PERCENTAGE:
+        begin
+          Chunk.Data.IntPercentage := AllocMem(SizeOf(TIntPercentage));
+          Chunk.Data.IntPercentage^ := ReadShort;
+        end;
+      FLOAT_PERCENTAGE:
+        begin
+          Chunk.Data.FloatPercentage := AllocMem(SizeOf(TFloatPercentage));
+          Chunk.Data.FloatPercentage^ := ReadSingle;
+        end;
+      MAT_MAPNAME:
+        begin
+          // Chunk.Data.MatMapname := AllocMem(SizeOf(TMatMapname));
+          Chunk.Data.MatMapname := ReadString;
+        end;
+      M3D_VERSION:
+        begin
+          Chunk.Data.M3dVersion := AllocMem(SizeOf(TM3dVersion));
+          Chunk.Data.M3dVersion^ := ReadInteger;
+        end;
+      MESH_VERSION:
+        begin
+          Chunk.Data.MeshVersion := AllocMem(SizeOf(TMeshVersion));
+          Chunk.Data.MeshVersion^ := ReadInteger;
+        end;
+      MASTER_SCALE:
+        begin
+          Chunk.Data.MasterScale := AllocMem(SizeOf(TMasterScale));
+          Chunk.Data.MasterScale^ := ReadSingle;
+        end;
+      LO_SHADOW_BIAS:
+        begin
+          Chunk.Data.LoShadowBias := AllocMem(SizeOf(TLoShadowBias));
+          Chunk.Data.LoShadowBias^ := ReadSingle;
+        end;
+      SHADOW_FILTER:
+        begin
+          Chunk.Data.ShadowFilter := AllocMem(SizeOf(TShadowFilter));
+          Chunk.Data.ShadowFilter^ := ReadSingle;
+        end;
+      SHADOW_RANGE:
+        begin
+          Chunk.Data.ShadowRange := AllocMem(SizeOf(TShadowRange));
+          Chunk.Data.ShadowRange^ := ReadInteger;
+        end;
+      HI_SHADOW_BIAS:
+        begin
+          Chunk.Data.HiShadowBias := AllocMem(SizeOf(THiShadowBias));
+          Chunk.Data.HiShadowBias^ := ReadSingle;
+        end;
+      RAY_BIAS:
+        begin
+          Chunk.Data.RayBias := AllocMem(SizeOf(TRayBias));
+          Chunk.Data.RayBias^ := ReadSingle;
+        end;
+      SHADOW_MAP_SIZE:
+        begin
+          Chunk.Data.ShadowMapSize := AllocMem(SizeOf(TShadowMapSize));
+          Chunk.Data.ShadowMapSize^ := ReadShort;
+        end;
+      SHADOW_SAMPLES:
+        begin
+          Chunk.Data.ShadowSamples := AllocMem(SizeOf(TShadowSamples));
+          Chunk.Data.ShadowSamples^ := ReadShort;
+        end;
+      O_CONSTS:
+        begin
+          Chunk.Data.OConsts := AllocMem(SizeOf(TOConsts));
+          Chunk.Data.OConsts^ := ReadPoint;
+        end;
+      BIT_MAP:
+        begin
+          // Chunk.Data.BitMapName := AllocMem(SizeOf(TBitMapName));
+          Chunk.Data.BitMapName := ReadString;
+        end;
+      V_GRADIENT:
+        begin
+          Chunk.Data.VGradient := AllocMem(SizeOf(TVGradient));
+          Chunk.Data.VGradient^ := ReadSingle;
+        end;
+      FOG:
+        begin
+          Chunk.Data.FOG := AllocMem(SizeOf(TFog));
+          with Chunk.Data.FOG^ do
+          begin
+            NearPlaneDist := ReadSingle;
+            NearPlaneDensity := ReadSingle;
+            FarPlaneDist := ReadSingle;
+            FarPlaneDensity := ReadSingle;
+          end;
+        end;
+      LAYER_FOG:
+        begin
+          Chunk.Data.LayerFog := AllocMem(SizeOf(TLayerFog));
+          with Chunk.Data.LayerFog^ do
+          begin
+            ZMin := ReadSingle;
+            ZMax := ReadSingle;
+            Density := ReadSingle;
+            AType := ReadCardinal;
+          end;
+        end;
+      DISTANCE_CUE:
+        begin
+          Chunk.Data.DistanceCue := AllocMem(SizeOf(TDistanceCue));
+          with Chunk.Data.DistanceCue^ do
+          begin
+            NearPlaneDist := ReadSingle;
+            NearPlaneDimming := ReadSingle;
+            FarPlaneDist := ReadSingle;
+            FarPlaneDimming := ReadSingle;
+          end;
+        end;
+      VIEW_TOP, 
+	  VIEW_BOTTOM, 
+	  VIEW_LEFT, 
+	  VIEW_RIGHT, 
+	  VIEW_FRONT, 
+	  VIEW_BACK:
+        begin
+          Chunk.Data.ViewStandard := AllocMem(SizeOf(TViewStandard));
+          with Chunk.Data.ViewStandard^ do
+          begin
+            ViewWidth := ReadSingle;
+            ViewTargetCoord := ReadPoint;
+          end;
+        end;
+      VIEW_USER:
+        begin
+          Chunk.Data.ViewUser := AllocMem(SizeOf(TViewUser));
+          with Chunk.Data.ViewUser^ do
+          begin
+            ViewWidth := ReadSingle;
+            XYViewAngle := ReadSingle;
+            YZViewAngle := ReadSingle;
+            BankAngle := ReadSingle;
+            ViewTargetCoord := ReadPoint;
+          end;
+        end;
+      VIEW_CAMERA:
+        begin
+          // Chunk.Data.ViewCamera := AllocMem(SizeOf(TViewCamera));
+          Chunk.Data.ViewCamera := ReadString;
+        end;
+      MAT_NAME:
+        begin
+          // Chunk.Data.MatName := AllocMem(SizeOf(TMatName));
+          Chunk.Data.MatName := ReadString;
+        end;
+      MAT_SHADING:
+        begin
+          Chunk.Data.MatShading := AllocMem(SizeOf(TMatShading));
+          FStream.Position := Chunk.Position + 6;
+          Chunk.Data.MatShading^ := ReadShort;
+        end;
+      MAT_ACUBIC:
+        begin
+          Chunk.Data.MatAcubic := AllocMem(SizeOf(TMatAcubic));
+          with Chunk.Data.MatAcubic^ do
+          begin
+            ShadeLevel := ReadByte;
+            AntiAlias := ReadByte;
+            Flags := ReadShort;
+            MapSize := ReadCardinal;
+            FrameInterval := ReadCardinal;
+          end;
+        end;
+      MAT_SXP_TEXT_DATA, 
+	  MAT_SXP_TEXT2_DATA, 
+	  MAT_SXP_OPAC_DATA,
+      MAT_SXP_BUMP_DATA, 
+	  MAT_SXP_SPEC_DATA, 
+	  MAT_SXP_SHIN_DATA,
+      MAT_SXP_SELFI_DATA, 
+	  MAT_SXP_TEXT_MASKDATA, 
+	  MAT_SXP_TEXT2_MASKDATA,
+      MAT_SXP_OPAC_MASKDATA, 
+	  MAT_SXP_BUMP_MASKDATA, 
+	  MAT_SXP_SPEC_MASKDATA,
+      MAT_SXP_SHIN_MASKDATA, 
+	  MAT_SXP_SELFI_MASKDATA, 
+	  MAT_SXP_REFL_MASKDATA,
+        PROC_DATA:
+        begin
+          Chunk.Data.IpasData := AllocMem(SizeOf(TIpasData));
+          with Chunk.Data.IpasData^ do
+          begin
+            Size := Chunk.Size - 6;
+            Data := AllocMem(Size);
+            ReadData(Size, Data);
+          end;
+        end;
+      MAT_WIRESIZE:
+        begin
+          Chunk.Data.MatWireSize := AllocMem(SizeOf(TMatWireSize));
+          Chunk.Data.MatWireSize^ := ReadSingle;
+        end;
+      MAT_MAP_TILING:
+        begin
+          Chunk.Data.MatMapTiling := AllocMem(SizeOf(TMatMapTiling));
+          Chunk.Data.MatMapTiling^ := ReadWord;
+        end;
+      MAT_MAP_TEXBLUR:
+        begin
+          Chunk.Data.MatMapTexblur := AllocMem(SizeOf(TMatMapTexblur));
+          Chunk.Data.MatMapTexblur^ := ReadSingle;
+        end;
+      MAT_MAP_USCALE:
+        begin
+          Chunk.Data.MatMapUScale := AllocMem(SizeOf(TMatMapUScale));
+          Chunk.Data.MatMapUScale^ := ReadSingle;
+        end;
+      MAT_MAP_VSCALE:
+        begin
+          Chunk.Data.MatMapVScale := AllocMem(SizeOf(TMatMapVScale));
+          Chunk.Data.MatMapVScale^ := ReadSingle;
+        end;
+      MAT_MAP_UOFFSET:
+        begin
+          Chunk.Data.MatMapUOffset := AllocMem(SizeOf(TMatMapUOffset));
+          Chunk.Data.MatMapUOffset^ := ReadSingle;
+        end;
+      MAT_MAP_VOFFSET:
+        begin
+          Chunk.Data.MatMapVOffset := AllocMem(SizeOf(TMatMapVOffset));
+          Chunk.Data.MatMapVOffset^ := ReadSingle;
+        end;
+      MAT_MAP_ANG:
+        begin
+          Chunk.Data.MatMapAng := AllocMem(SizeOf(TMatMapAng));
+          Chunk.Data.MatMapAng^ := ReadSingle;
+        end;
+      MAT_MAP_COL1:
+        begin
+          Chunk.Data.MatMapCol1 := AllocMem(SizeOf(TMatMapCol1));
+          with Chunk.Data.MatMapCol1^ do
+          begin
+            Red := ReadByte;
+            Green := ReadByte;
+            Blue := ReadByte;
+          end;
+        end;
+      MAT_MAP_COL2:
+        begin
+          Chunk.Data.MatMapCol2 := AllocMem(SizeOf(TMatMapCol2));
+          with Chunk.Data.MatMapCol2^ do
+          begin
+            Red := ReadByte;
+            Green := ReadByte;
+            Blue := ReadByte;
+          end;
+        end;
+      MAT_MAP_RCOL:
+        begin
+          Chunk.Data.MatMapRCol := AllocMem(SizeOf(TMatMapRCol));
+          with Chunk.Data.MatMapRCol^ do
+          begin
+            Red := ReadByte;
+            Green := ReadByte;
+            Blue := ReadByte;
+          end;
+        end;
+      MAT_MAP_GCOL:
+        begin
+          Chunk.Data.MatMapGCol := AllocMem(SizeOf(TMatMapGCol));
+          with Chunk.Data.MatMapGCol^ do
+          begin
+            Red := ReadByte;
+            Green := ReadByte;
+            Blue := ReadByte;
+          end;
+        end;
+      MAT_MAP_BCOL:
+        begin
+          Chunk.Data.MatMapBCol := AllocMem(SizeOf(TMatMapBCol));
+          with Chunk.Data.MatMapBCol^ do
+          begin
+            Red := ReadByte;
+            Green := ReadByte;
+            Blue := ReadByte;
+          end;
+        end;
+      MAT_BUMP_PERCENT:
+        begin
+          Chunk.Data.MatBumpPercent := AllocMem(SizeOf(TMatBumpPercent));
+          Chunk.Data.MatBumpPercent^ := ReadShort;
+        end;
+      NAMED_OBJECT:
+        begin
+          // Chunk.Data.NamedObject := AllocMem(SizeOf(TNamedObject));
+          Chunk.Data.NamedObject := ReadString;
+        end;
+      POINT_ARRAY:
+        begin
+          Chunk.Data.PointArray := AllocMem(SizeOf(TPointArray));
+          with Chunk.Data.PointArray^ do
+          begin
+            Vertices := ReadWord;
+            PointList := AllocMem(Vertices * SizeOf(TPoint3DS));
+            // for I := 0 to Vertices - 1 do PointList[I] := ReadPoint;
+            ReadData(Vertices * SizeOf(TPoint3DS), PointList);
+          end;
+        end;
+      POINT_FLAG_ARRAY:
+        begin
+          Chunk.Data.PointFlagArray := AllocMem(SizeOf(TPointFlagArray));
+          with Chunk.Data.PointFlagArray^ do
+          begin
+            Flags := ReadWord;
+            FlagList := AllocMem(Flags * SizeOf(SmallInt));
+            // for I := 0 to Flags - 1 do FlagList[I] := ReadShort;
+            ReadData(Flags * SizeOf(SmallInt), FlagList);
+          end;
+        end;
+      FACE_ARRAY:
+        begin
+          Chunk.Data.FaceArray := AllocMem(SizeOf(TFaceArray));
+          with Chunk.Data.FaceArray^ do
+          begin
+            Faces := ReadWord;
+            FaceList := AllocMem(Faces * SizeOf(TFace3DS));
+            // for I := 0 to Faces - 1 do FaceList[I] := ReadFace;
+            ReadData(Faces * SizeOf(TFace3DS), FaceList);
+          end;
+        end;
+      MSH_MAT_GROUP:
+        begin
+          Chunk.Data.MshMatGroup := AllocMem(SizeOf(TMshMatGroup));
+          with Chunk.Data.MshMatGroup^ do
+          begin
+            MatNameStr := AnsiString(StrPasFree(ReadString));
+            Faces := ReadWord;
+            if Faces > 0 then
+            begin
+              FaceList := AllocMem(Faces * SizeOf(Word));
+              // for I := 0 to Faces - 1 do FaceList[I] := ReadWord;
+              ReadData(Faces * SizeOf(Word), FaceList);
+            end
+            else
+              FaceList := nil;
+          end;
+        end;
+      MSH_BOXMAP:
+        begin
+          Chunk.Data.MshBoxmap := AllocMem(SizeOf(TMshBoxmap));
+          for I := 0 to 5 do
+            Chunk.Data.MshBoxmap[I] := ReadString;
+        end;
+      SMOOTH_GROUP:
+        begin
+          Chunk.Data.SmoothGroup := AllocMem(SizeOf(TSmoothGroup));
+          with Chunk.Data.SmoothGroup^ do
+          begin
+            Groups := (Chunk.Size - 6) div 4;
+            GroupList := AllocMem(Groups * SizeOf(Cardinal));
+            // for I := 0 to Groups - 1 do GroupList[I] := ReadCardinal;
+            ReadData(Groups * SizeOf(Cardinal), GroupList);
+          end;
+        end;
+      TEX_VERTS:
+        begin
+          Chunk.Data.TexVerts := AllocMem(SizeOf(TTexVerts));
+          with Chunk.Data.TexVerts^ do
+          begin
+            NumCoords := ReadWord;
+            TextVertList := AllocMem(NumCoords * SizeOf(TTexVert3DS));
+            // for I := 0 to NumCoords - 1 do TextVertList[I] := ReadTexVert;
+            ReadData(NumCoords * SizeOf(TTexVert3DS), TextVertList);
+          end;
+        end;
+      MESH_MATRIX:
+        begin
+          Chunk.Data.MeshMatrix := AllocMem(SizeOf(TMeshMatrix));
+          for I := 0 to 11 do
+            Chunk.Data.MeshMatrix[I] := ReadSingle;
+        end;
+      MESH_COLOR:
+        begin
+          Chunk.Data.MeshColor := AllocMem(SizeOf(TMeshColor));
+          Chunk.Data.MeshColor^ := ReadByte;
+        end;
+      MESH_TEXTURE_INFO:
+        begin
+          Chunk.Data.MeshTextureInfo := AllocMem(SizeOf(TMeshTextureInfo));
+          with Chunk.Data.MeshTextureInfo^ do
+          begin
+            MapType := ReadWord;
+            XTiling := ReadSingle;
+            YTiling := ReadSingle;
+            IconPos := ReadPoint();
+            IconScaling := ReadSingle;
+            for I := 0 to 11 do
+              XMatrix[I] := ReadSingle;
+            IconWidth := ReadSingle;
+            IconHeight := ReadSingle;
+            CylIconHeight := ReadSingle;
+          end;
+        end;
+      PROC_NAME:
+        begin
+          // Chunk.Data.ProcName := AllocMem(SizeOf(TProcName));
+          Chunk.Data.ProcName := ReadString;
+        end;
+      N_DIRECT_LIGHT:
+        begin
+          Chunk.Data.NDirectLight := AllocMem(SizeOf(TNDirectLight));
+          Chunk.Data.NDirectLight^ := ReadPoint;
+        end;
+      DL_EXCLUDE:
+        begin
+          // Chunk.Data.DlExclude := AllocMem(SizeOf(TDlExclude));
+          Chunk.Data.DlExclude := ReadString;
+        end;
+      DL_INNER_RANGE:
+        begin
+          Chunk.Data.DlInnerRange := AllocMem(SizeOf(TDlInnerRange));
+          Chunk.Data.DlInnerRange^ := ReadSingle;
+        end;
+      DL_OUTER_RANGE:
+        begin
+          Chunk.Data.DlOuterRange := AllocMem(SizeOf(TDlOuterRange));
+          Chunk.Data.DlOuterRange^ := ReadSingle;
+        end;
+      DL_MULTIPLIER:
+        begin
+          Chunk.Data.DlMultiplier := AllocMem(SizeOf(TDlMultiplier));
+          Chunk.Data.DlMultiplier^ := ReadSingle;
+        end;
+      DL_SPOTLIGHT:
+        begin
+          Chunk.Data.DlSpotlight := AllocMem(SizeOf(TDlSpotlight));
+          with Chunk.Data.DlSpotlight^ do
+          begin
+            SpotlightTarg := ReadPoint;
+            HotspotAngle := ReadSingle;
+            FalloffAngle := ReadSingle;
+          end;
+        end;
+      DL_LOCAL_SHADOW2:
+        begin
+          Chunk.Data.DlLocalShadow2 := AllocMem(SizeOf(TDlLocalShadow2));
+          with Chunk.Data.DlLocalShadow2^ do
+          begin
+            LocalShadowBias := ReadSingle;
+            LocalShadowFilter := ReadSingle;
+            LocalShadowMapSize := ReadShort;
+          end;
+        end;
+      DL_SPOT_ROLL:
+        begin
+          Chunk.Data.DlSpotRoll := AllocMem(SizeOf(TDlSpotRoll));
+          Chunk.Data.DlSpotRoll^ := ReadSingle;
+        end;
+      DL_SPOT_ASPECT:
+        begin
+          Chunk.Data.DlSpotAspect := AllocMem(SizeOf(TDlSpotAspect));
+          Chunk.Data.DlSpotAspect^ := ReadSingle;
+        end;
+      DL_SPOT_PROJECTOR:
+        begin
+          // Chunk.Data.DlSpotProjector := AllocMem(SizeOf(TDlSpotProjector));
+          Chunk.Data.DlSpotProjector := ReadString;
+        end;
+      DL_RAY_BIAS:
+        begin
+          Chunk.Data.DlRayBias := AllocMem(SizeOf(TDlRayBias));
+          Chunk.Data.DlRayBias^ := ReadSingle;
+        end;
+      N_CAMERA:
+        begin
+          Chunk.Data.NCamera := AllocMem(SizeOf(TNCamera));
+          with Chunk.Data.NCamera^ do
+          begin
+            CameraPos := ReadPoint;
+            TargetPos := ReadPoint;
+            CameraBank := ReadSingle;
+            CameraFocalLength := ReadSingle;
+          end;
+        end;
+      CAM_RANGES:
+        begin
+          Chunk.Data.CamRanges := AllocMem(SizeOf(TCamRanges));
+          with Chunk.Data.CamRanges^ do
+          begin
+            NearPlane := ReadSingle;
+            FarPlane := ReadSingle;
+          end;
+        end;
+      VIEWPORT_LAYOUT:
+        begin
+          Chunk.Data.ViewportLayout := AllocMem(SizeOf(TViewportLayout));
+          with Chunk.Data.ViewportLayout^ do
+          begin
+            Form := ReadShort;
+            Top := ReadShort;
+            Ready := ReadShort;
+            WState := ReadShort;
+            SwapWS := ReadShort;
+            SwapPort := ReadShort;
+            SwapCur := ReadShort;
+          end;
+        end;
+      VIEWPORT_SIZE:
+        begin
+          Chunk.Data.ViewportSize := AllocMem(SizeOf(TViewportSize));
+          with Chunk.Data.ViewportSize^ do
+          begin
+            XPos := ReadWord;
+            YPos := ReadWord;
+            Width := ReadWord;
+            Height := ReadWord;
+          end;
+        end;
+      VIEWPORT_DATA_3, 
+	  VIEWPORT_DATA:
+        begin
+          Chunk.Data.ViewportData := AllocMem(SizeOf(TViewportData));
+          with Chunk.Data.ViewportData^ do
+          begin
+            Flags := ReadShort;
+            AxisLockout := ReadShort;
+            WinXPos := ReadShort;
+            WinYPos := ReadShort;
+            WinWidth := ReadShort;
+            WinHeight := ReadShort;
+            View := ReadShort;
+            ZoomFactor := ReadSingle;
+            Center := ReadPoint;
+            HorizAng := ReadSingle;
+            VertAng := ReadSingle;
+            CamNameStr := AnsiString(StrPasFree(ReadString));
+          end;
+        end;
+      XDATA_ENTRY:
+        begin
+          InitChunkData(Chunk);
+          with Chunk.Data.XDataEntry^ do
+          begin
+            Size := (Chunk.Size) - 6;
+            Data := AllocMem(Size);
+            ReadData(Size, Data);
+          end;
+        end;
+      XDATA_APPNAME:
+        begin
+          Chunk.Data.XDataAppName := ReadString;
+        end;
+      XDATA_STRING:
+        begin
+          Chunk.Data.XDataString := ReadString;
+        end;
+      KFHDR:
+        begin
+          Chunk.Data.KFHDR := AllocMem(SizeOf(TKFHdr));
+          with Chunk.Data.KFHDR^ do
+          begin
+            Revision := ReadShort;
+            FileName := StrPasFree(ReadString);
+            AnimLength := ReadInteger;
+          end;
+        end;
+      KFSEG:
+        begin
+          Chunk.Data.KFSEG := AllocMem(SizeOf(TKFSeg));
+          with Chunk.Data.KFSEG^ do
+          begin
+            First := ReadInteger;
+            Last := ReadInteger;
+          end;
+        end;
+      KFCURTIME:
+        begin
+          Chunk.Data.KFCURTIME := AllocMem(SizeOf(TKFCurtime));
+          Chunk.Data.KFCURTIME^ := ReadInteger;
+        end;
+      NODE_ID:
+        begin
+          Chunk.Data.KFID := AllocMem(SizeOf(TKFId));
+          Chunk.Data.KFID^ := ReadShort;
+        end;
+      NODE_HDR:
+        begin
+          Chunk.Data.NodeHdr := AllocMem(SizeOf(TNodeHdr));
+          with Chunk.Data.NodeHdr^ do
+          begin
+            ObjNameStr := StrPasFree(ReadString);
+            Flags1 := ReadWord;
+            Flags2 := ReadWord;
+            ParentIndex := ReadShort;
+          end;
+        end;
+      PIVOT:
+        begin
+          Chunk.Data.PIVOT := AllocMem(SizeOf(TPivot));
+          Chunk.Data.PIVOT^ := ReadPoint;
+        end;
+      INSTANCE_NAME:
+        begin
+          Chunk.Data.InstanceName := ReadString;
+        end;
+      PARENT_NAME:
+        ; // do nothing
+      MORPH_SMOOTH:
+        begin
+          Chunk.Data.MorphSmooth := AllocMem(SizeOf(TMorphSmooth));
+          Chunk.Data.MorphSmooth^ := ReadSingle;
+        end;
+      BOUNDBOX:
+        begin
+          Chunk.Data.BOUNDBOX := AllocMem(SizeOf(TBoundBox));
+          with Chunk.Data.BOUNDBOX^ do
+          begin
+            Min := ReadPoint;
+            Max := ReadPoint;
+          end;
+        end;
+      POS_TRACK_TAG:
+        begin
+          Chunk.Data.PosTrackTag := AllocMem(SizeOf(TPosTrackTag));
+          with Chunk.Data.PosTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            PositionList := AllocMem(TrackHdr.KeyCount * SizeOf(TPoint3DS));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              PositionList[I] := ReadPoint;
+            end;
+          end;
+        end;
+      COL_TRACK_TAG:
+        begin
+          Chunk.Data.ColTrackTag := AllocMem(SizeOf(TColTrackTag));
+          with Chunk.Data.ColTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            ColorList := AllocMem(TrackHdr.KeyCount * SizeOf(TFColor3DS));
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              ColorList[I].R := ReadSingle;
+              ColorList[I].G := ReadSingle;
+              ColorList[I].B := ReadSingle;
+            end;
+          end;
+        end;
+      ROT_TRACK_TAG:
+        begin
+          Chunk.Data.RotTrackTag := AllocMem(SizeOf(TRotTrackTag));
+          with Chunk.Data.RotTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            RotationList := AllocMem(TrackHdr.KeyCount * SizeOf(TKFrotkey3DS));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              RotationList[I].Angle := ReadSingle;
+              RotationList[I].X := ReadSingle;
+              RotationList[I].Y := ReadSingle;
+              RotationList[I].Z := ReadSingle;
+            end;
+          end;
+        end;
+      SCL_TRACK_TAG:
+        begin
+          Chunk.Data.ScaleTrackTag := AllocMem(SizeOf(TScaleTrackTag));
+          with Chunk.Data.ScaleTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            ScaleList := AllocMem(TrackHdr.KeyCount * SizeOf(TPoint3DS));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              ScaleList[I].X := ReadSingle;
+              ScaleList[I].Y := ReadSingle;
+              ScaleList[I].Z := ReadSingle;
+            end;
+          end;
+        end;
+      MORPH_TRACK_TAG:
+        begin
+          Chunk.Data.MorphTrackTag := AllocMem(SizeOf(TMorphTrackTag));
+          with Chunk.Data.MorphTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            MorphList := AllocMem(TrackHdr.KeyCount * SizeOf(TKFmorphKey3DS));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              MorphList[I] := StrPasFree(ReadString);
+            end;
+          end;
+        end;
+      FOV_TRACK_TAG:
+        begin
+          Chunk.Data.FovTrackTag := AllocMem(SizeOf(TFovTrackTag));
+          with Chunk.Data.FovTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            FOVAngleList := AllocMem(TrackHdr.KeyCount * SizeOf(Single));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              FOVAngleList[I] := ReadSingle;
+            end;
+          end;
+        end;
+      ROLL_TRACK_TAG:
+        begin
+          Chunk.Data.RollTrackTag := AllocMem(SizeOf(TRollTrackTag));
+          with Chunk.Data.RollTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            RollAngleList := AllocMem(TrackHdr.KeyCount * SizeOf(Single));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              RollAngleList[I] := ReadSingle;
+            end;
+          end;
+        end;
+      HOT_TRACK_TAG:
+        begin
+          Chunk.Data.HotTrackTag := AllocMem(SizeOf(THotTrackTag));
+          with Chunk.Data.HotTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            HotspotAngleList := AllocMem(TrackHdr.KeyCount * SizeOf(Single));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              HotspotAngleList[I] := ReadSingle;
+            end;
+          end;
+        end;
+      FALL_TRACK_TAG:
+        begin
+          Chunk.Data.FallTrackTag := AllocMem(SizeOf(TFallTrackTag));
+          with Chunk.Data.FallTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            FalloffAngleList := AllocMem(TrackHdr.KeyCount * SizeOf(Single));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+            begin
+              KeyHdrList[I] := ReadKeyHeader;
+              FalloffAngleList[I] := ReadSingle;
+            end;
+          end;
+        end;
+      HIDE_TRACK_TAG:
+        begin
+          Chunk.Data.HideTrackTag := AllocMem(SizeOf(THideTrackTag));
+          with Chunk.Data.HideTrackTag^ do
+          begin
+            TrackHdr := ReadTrackHeader;
+            KeyHdrList := AllocMem(TrackHdr.KeyCount * SizeOf(TKeyHeader3DS));
+            for I := 0 to TrackHdr.KeyCount - 1 do
+              KeyHdrList[I] := ReadKeyHeader;
+          end;
+        end;
+      M3DMAGIC, // Chunks that do not contain data, or only contain children
+      MLIBMAGIC, 
+	  MDATA, 
+	  AMBIENT_LIGHT, 
+	  SOLID_BGND, 
+	  DEFAULT_VIEW, 
+	  MAT_ENTRY,
+      MAT_AMBIENT, 
+	  MAT_DIFFUSE, 
+	  MAT_SPECULAR, 
+	  MAT_SHININESS, 
+	  MAT_SHIN2PCT,
+      MAT_SHIN3PCT, 
+	  MAT_TRANSPARENCY, 
+	  MAT_XPFALL, 
+	  MAT_REFBLUR, 
+	  MAT_SELF_ILPCT,
+      MAT_TEXMAP, 
+	  MAT_TEXMASK, 
+	  MAT_TEX2MAP, 
+	  MAT_TEX2MASK, 
+	  MAT_OPACMAP,
+      MAT_OPACMASK, 
+	  MAT_REFLMAP, 
+	  MAT_REFLMASK, 
+	  MAT_BUMPMAP, 
+	  MAT_BUMPMASK,
+      MAT_SPECMAP, 
+	  MAT_SPECMASK, 
+	  MAT_SHINMAP, 
+	  MAT_SHINMASK, 
+	  MAT_SELFIMAP,
+      MAT_SELFIMASK, 
+	  N_TRI_OBJECT, 
+	  KFDATA, 
+	  AMBIENT_NODE_TAG, 
+	  OBJECT_NODE_TAG,
+      CAMERA_NODE_TAG, 
+	  TARGET_NODE_TAG, 
+	  LIGHT_NODE_TAG, 
+	  SPOTLIGHT_NODE_TAG,
+      L_TARGET_NODE_TAG, 
+	  CMAGIC, 
+	  XDATA_SECTION, 
+	  XDATA_GROUP:
+        ; // do nothing
+    else // a truely hideous thing to do, but it helps with unknown chunks
+      if Chunk.Size > 6 then // don't mess with dataless chunks
+      begin
+        Chunk.Data.Dummy := AllocMem(Chunk.Size - 6);
+        ReadData(Chunk.Size - 6, Chunk.Data.Dummy);
+      end;
+    end; // end of case
+  end;
+end;
+
+//---------------------------------------------------------------------------------------------------------------------
+
+procedure TFile3DS.SeekChild(Chunk: PChunk3DS);
+
+// Function skips to next Chunk on disk by seeking the next file position
+
+var
+  Offset: Integer;
+begin
+  Offset := 0;
+  case Chunk.Tag of
+    M3DMAGIC, 
+    SMAGIC, 
+    LMAGIC, 
+    MATMAGIC, 
+    MLIBMAGIC, 
+    MDATA, 
+    AMBIENT_LIGHT, 
+    SOLID_BGND, 
+    DEFAULT_VIEW, 
+    MAT_ENTRY, 
+    MAT_AMBIENT, 
+    MAT_DIFFUSE, 
+    MAT_SPECULAR, 
+    MAT_SHININESS, 
+    MAT_SHIN2PCT, 
+    MAT_SHIN3PCT, 
+    MAT_TRANSPARENCY, 
+    MAT_XPFALL, 
+    MAT_REFBLUR, 
+    MAT_SELF_ILPCT, 
+    MAT_TEXMAP, 
+    MAT_TEXMASK, 
+    MAT_TEX2MAP, 
+    MAT_TEX2MASK, 
+    MAT_OPACMAP, 
+    MAT_OPACMASK, 
+    MAT_REFLMAP, 
+    MAT_REFLMASK, 
+    MAT_BUMPMAP, 
+    MAT_BUMPMASK, 
+    MAT_SPECMAP, 
+    MAT_SPECMASK, 
+    MAT_SHINMAP, 
+    MAT_SHINMASK, 
+    MAT_SELFIMAP, 
+    MAT_SELFIMASK, 
+    N_TRI_OBJECT, 
+    XDATA_SECTION, 
+    XDATA_ENTRY, 
+    KFDATA, 
+    OBJECT_NODE_TAG, 
+    CAMERA_NODE_TAG, 
+    TARGET_NODE_TAG, 
+    LIGHT_NODE_TAG, 
+    SPOTLIGHT_NODE_TAG, 
+    L_TARGET_NODE_TAG, 
+    AMBIENT_NODE_TAG, 
+    CMAGIC :
+      ; // do nothing
+    M3D_VERSION:
+      Offset := SizeOf(Integer);
+    COLOR_F:
+      Offset := 3 * SizeOf(Single);
+    COLOR_24:
+      Offset := 3 * SizeOf(Byte);
+    INT_PERCENTAGE:
+      Offset := SizeOf(SmallInt);
+    FLOAT_PERCENTAGE:
+      Offset := SizeOf(Single);
+    MAT_MAPNAME:
+      FreeMem(ReadString);
+    MESH_VERSION:
+      Offset := SizeOf(Integer);
+    MASTER_SCALE:
+      Offset := SizeOf(Single);
+    LO_SHADOW_BIAS:
+      Offset := SizeOf(Single);
+    HI_SHADOW_BIAS:
+      Offset := SizeOf(Single);
+    SHADOW_MAP_SIZE:
+      Offset := SizeOf(SmallInt);
+    SHADOW_SAMPLES:
+      Offset := SizeOf(SmallInt);
+    O_CONSTS:
+      Offset := 12;
+    V_GRADIENT:
+      Offset := SizeOf(Single);
+    NAMED_OBJECT:
+      FreeMem(ReadString);
+    BIT_MAP:
+      FreeMem(ReadString);
+    FOG:
+      Offset := 4 * SizeOf(Single);
+    LAYER_FOG:
+      Offset := 3 * SizeOf(Single) + SizeOf(Integer);
+    DISTANCE_CUE:
+      Offset := 4 * SizeOf(Single);
+    N_DIRECT_LIGHT:
+      Offset := 12;
+    DL_SPOTLIGHT:
+      Offset := 12 + 2 * SizeOf(Single);
+    N_CAMERA:
+      Offset := 24 + 2 * SizeOf(Single);
+    VIEWPORT_LAYOUT:
+      Offset := 7 * SizeOf(SmallInt);
+    VIEW_TOP,
+    VIEW_BOTTOM,
+    VIEW_LEFT,
+    VIEW_RIGHT,
+    VIEW_FRONT,
+    VIEW_BACK:
+      Offset := 12 + SizeOf(Single);
+    VIEW_USER:
+      Offset := 12 + 4 * SizeOf(Single);
+    VIEW_CAMERA:
+      FreeMem(ReadString);
+    MAT_NAME:
+      FreeMem(ReadString);
+    MAT_ACUBIC:
+      Offset := 2 * SizeOf(Byte) + 2 * SizeOf(Integer) + SizeOf(SmallInt);
+    POINT_ARRAY,
+    POINT_FLAG_ARRAY:
+      Offset := Chunk.Size - 6;
+    FACE_ARRAY:
+      Offset := ReadWord * SizeOf(SmallInt) * 4;
+    MSH_MAT_GROUP:
+      Offset := Chunk.Size - 6;
+    SMOOTH_GROUP:
+      Offset := Chunk.Size - 6;
+    TEX_VERTS:
+      Offset := Chunk.Size - 6;
+    MESH_MATRIX:
+      Offset := 12 * SizeOf(Single);
+    MESH_TEXTURE_INFO:
+      Offset := Chunk.Size - 6;
+    PROC_NAME:
+      FreeMem(ReadString);
+    DL_LOCAL_SHADOW2:
+      Offset := 2 * SizeOf(Single) + SizeOf(SmallInt);
+    KFHDR:
+      begin
+        ReadShort;
+        FreeMem(ReadString);
+        ReadInteger;
+      end;
+    KFSEG:
+      Offset := 2 * SizeOf(Integer);
+    KFCURTIME:
+      Offset := SizeOf(Integer);
+    NODE_HDR:
+      begin
+        FreeMem(ReadString);
+        Offset := 2 * SizeOf(SmallInt) + SizeOf(SmallInt);
+      end;
+    NODE_ID:
+      Offset := SizeOf(SmallInt);
+    PIVOT:
+      Offset := 12;
+    INSTANCE_NAME:
+      FreeMem(ReadString);
+    MORPH_SMOOTH:
+      Offset := SizeOf(Single);
+    BOUNDBOX:
+      Offset := 24;
+    VPDATA:
+      Offset := SizeOf(Integer);
+  else
+    Offset := Chunk.Size - 6;
+  end;
+  FStream.Seek(Offset, soFromCurrent);
+end;
+
+//---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetDatabaseRelease: TReleaseLevel;
+
+begin
+  Result := Formatx.m3DSUtils.GetDatabaseRelease(Self, FDatabase);
+end;
+
+//---------------------------------------------------------------------------------------------------------------------
+
+function TFile3DS.GetMeshRelease: TReleaseLevel;
+
+begin
+  Result := Formatx.m3DSUtils.GetMeshRelease(Self, FDatabase);
+end;
+
+//---------------------------------------------------------------------------------------------------------------------
+
+end.

Some files were not shown because too many files changed in this diff