GLScene 2 rokov pred
rodič
commit
1d5f50812a
1 zmenil súbory, kde vykonal 0 pridanie a 6263 odobranie
  1. 0 6263
      Source/GLS.IntellectObjects.pas

+ 0 - 6263
Source/GLS.IntellectObjects.pas

@@ -1,6263 +0,0 @@
-//
-// The graphics rendering engine GLScene http://glscene.org
-//
-unit GLS.IntellectObjects;
-
-(* Intellectual objects *)
-
-interface
-
-{$I GLScene.inc}
-
-uses
-  Winapi.OpenGL,
-  Winapi.OpenGLext,
-  System.Classes,
-  System.SysUtils,
-  System.Types,
-  System.Math,
-  VCL.Consts,
-
-  GLS.OpenGLTokens,
-  GLS.Scene,
-  GLS.VectorGeometry,
-  GLS.VectorTypes,
-  GLS.VectorTypesExt,
-  GLS.VectorLists,
-  GLS.PersistentClasses,
-  GLS.Silhouette,
-  GLS.Strings,
-  GLS.Texture,
-  GLS.Material,
-  GLS.Mesh,
-  GLS.Logger,
-  GLS.Octree,
-  GLS.GeometryBB,
-  GLS.ApplicationFileIO,
-  GLS.Context,
-  GLS.Color,
-  GLS.PipelineTransformation,
-  GLS.Selection,
-  GLS.RenderContextInfo,
-  GLS.Coordinates,
-  GLS.BaseClasses,
-  GLS.TextureFormat,
-  GLS.VectorFileObjects;
-
-type
-
-  TGLMeshAutoCentering = (macCenterX, macCenterY, macCenterZ, macUseBarycenter, macRestorePosition);
-  TGLMeshAutoCenterings = set of TGLMeshAutoCentering;
-  TGLMeshObjectMode = (momTriangles, momTriangleStrip, momFaceGroups);
-
-
-
-
-
-var
-  vGLIntellectObjectsAllocateSences: Boolean = True;
-  // Flag to avoid loading scences (useful for IDE Extentions or scene editors)
-  vGLIntellectObjectsEnableScenceByDefault: Boolean = True;
-
-// ------------------------------------------------------------------
-implementation
-// ------------------------------------------------------------------
-
-var
-  vVectorFileFormats: TGLVectorFileFormatsList;
-  vNextRenderGroupID: Integer = 1;
-
-const
-  cAAFHeader: AnsiString = 'AAF';
-
-function GetVectorFileFormats: TGLVectorFileFormatsList;
-begin
-  if not Assigned(vVectorFileFormats) then
-    vVectorFileFormats := TGLVectorFileFormatsList.Create;
-  Result := vVectorFileFormats;
-end;
-
-function VectorFileFormatsFilter: string;
-var
-  f: string;
-begin
-  GetVectorFileFormats.BuildFilterStrings(TGLVectorFile, Result, f);
-end;
-
-function VectorFileFormatsSaveFilter: string;
-var
-  f: string;
-begin
-  GetVectorFileFormats.BuildFilterStrings(TGLVectorFile, Result, f, False, True);
-end;
-
-procedure RegisterVectorFileFormat(const aExtension, aDescription: string; AClass: TGLVectorFileClass);
-begin
-  RegisterClass(AClass);
-  GetVectorFileFormats.Add(aExtension, aDescription, 0, AClass);
-end;
-
-procedure UnregisterVectorFileClass(AClass: TGLVectorFileClass);
-begin
-  if Assigned(vVectorFileFormats) then
-    vVectorFileFormats.Remove(AClass);
-end;
-
-function VectorFileFormatExtensionByIndex(Index: Integer): string;
-begin
-  Result := GetVectorFileFormats.FindExtByIndex(index);
-end;
-
-// ------------------
-// ------------------ TGLVectorFileFormatsList ------------------
-// ------------------
-
-destructor TGLVectorFileFormatsList.Destroy;
-begin
-  Clean;
-  inherited;
-end;
-
-procedure TGLVectorFileFormatsList.Add(const Ext, Desc: string; DescID: Integer; AClass: TGLVectorFileClass);
-var
-  newRec: TGLVectorFileFormat;
-begin
-  newRec := TGLVectorFileFormat.Create;
-  with newRec do
-  begin
-    Extension := AnsiLowerCase(Ext);
-    VectorFileClass := AClass;
-    Description := Desc;
-    DescResID := DescID;
-  end;
-  inherited Add(newRec);
-end;
-
-function TGLVectorFileFormatsList.FindExt(Ext: string): TGLVectorFileClass;
-var
-  i: Integer;
-begin
-  Ext := AnsiLowerCase(Ext);
-  for i := Count - 1 downto 0 do
-    with TGLVectorFileFormat(Items[i]) do
-    begin
-      if Extension = Ext then
-      begin
-        Result := VectorFileClass;
-        Exit;
-      end;
-    end;
-  Result := nil;
-end;
-
-function TGLVectorFileFormatsList.FindFromFileName(const filename: string): TGLVectorFileClass;
-var
-  Ext: string;
-begin
-  Ext := ExtractFileExt(filename);
-  System.Delete(Ext, 1, 1);
-  Result := FindExt(Ext);
-  if not Assigned(Result) then
-    raise EInvalidVectorFile.CreateFmt(strUnknownExtension, [Ext, 'GLFile' + UpperCase(Ext)]);
-end;
-
-procedure TGLVectorFileFormatsList.Remove(AClass: TGLVectorFileClass);
-var
-  i: Integer;
-begin
-  for i := Count - 1 downto 0 do
-  begin
-    if TGLVectorFileFormat(Items[i]).VectorFileClass.InheritsFrom(AClass) then
-      DeleteAndFree(i);
-  end;
-end;
-
-procedure TGLVectorFileFormatsList.BuildFilterStrings(
-   VectorFileClass: TGLVectorFileClass; out descriptions, filters: string;
-  formatsThatCanBeOpened: Boolean = True; formatsThatCanBeSaved: Boolean = False);
-var
-  k, i: Integer;
-  p: TGLVectorFileFormat;
-begin
-  descriptions := '';
-  filters := '';
-  k := 0;
-  for i := 0 to Count - 1 do
-  begin
-    p := TGLVectorFileFormat(Items[i]);
-    if p.VectorFileClass.InheritsFrom(vectorFileClass) and (p.Extension <> '')
-      and ((formatsThatCanBeOpened and (dfcRead in
-        p.VectorFileClass.Capabilities))
-      or (formatsThatCanBeSaved and (dfcWrite in
-        p.VectorFileClass.Capabilities))) then
-    begin
-      with p do
-      begin
-        if k <> 0 then
-        begin
-          descriptions := descriptions + '|';
-          filters := filters + ';';
-        end;
-        if (Description = '') and (DescResID <> 0) then
-          Description := LoadStr(DescResID);
-        FmtStr(descriptions, '%s%s (*.%s)|*.%2:s', [descriptions, Description, Extension]);
-        filters := filters + '*.' + Extension;
-        Inc(k);
-      end;
-    end;
-  end;
-  if (k > 1) and (not formatsThatCanBeSaved) then
-    FmtStr(descriptions, '%s (%s)|%1:s|%s', [sAllFilter, filters, descriptions]);
-end;
-
-function TGLVectorFileFormatsList.FindExtByIndex(Index: Integer;
-  formatsThatCanBeOpened: Boolean = True;
-  formatsThatCanBeSaved: Boolean = False): string;
-var
-  i: Integer;
-  p: TGLVectorFileFormat;
-begin
-  Result := '';
-  if index > 0 then
-  begin
-    for i := 0 to Count - 1 do
-    begin
-      p := TGLVectorFileFormat(Items[i]);
-      if (formatsThatCanBeOpened and (dfcRead in p.VectorFileClass.Capabilities))
-        or (formatsThatCanBeSaved and (dfcWrite in
-          p.VectorFileClass.Capabilities)) then
-      begin
-        if index = 1 then
-        begin
-          Result := p.Extension;
-          Break;
-        end
-        else
-          Dec(index);
-      end;
-    end;
-  end;
-end;
-
-// ------------------
-// ------------------ TGLBaseMeshObject ------------------
-// ------------------
-
-constructor TGLBaseMeshObject.Create;
-begin
-  FVertices := TGLAffineVectorList.Create;
-  FNormals := TGLAffineVectorList.Create;
-  FVisible := True;
-  inherited Create;
-end;
-
-destructor TGLBaseMeshObject.Destroy;
-begin
-  FNormals.Free;
-  FVertices.Free;
-  inherited;
-end;
-
-procedure TGLBaseMeshObject.Assign(Source: TPersistent);
-begin
-  if Source is TGLBaseMeshObject then
-  begin
-    FName := TGLBaseMeshObject(Source).Name;
-    FVertices.Assign(TGLBaseMeshObject(Source).FVertices);
-    FNormals.Assign(TGLBaseMeshObject(Source).FNormals);
-  end
-  else
-    inherited; // Die!
-end;
-
-procedure TGLBaseMeshObject.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(1); // Archive Version 1, added FVisible
-    WriteString(FName);
-    FVertices.WriteToFiler(writer);
-    FNormals.WriteToFiler(writer);
-    WriteBoolean(FVisible);
-  end;
-end;
-
-procedure TGLBaseMeshObject.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion in [0 .. 1] then
-    with reader do
-    begin
-      FName := ReadString;
-      FVertices.ReadFromFiler(reader);
-      FNormals.ReadFromFiler(reader);
-      if archiveVersion >= 1 then
-        FVisible := ReadBoolean
-      else
-        FVisible := True;
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TGLBaseMeshObject.Clear;
-begin
-  FNormals.Clear;
-  FVertices.Clear;
-end;
-
-procedure TGLBaseMeshObject.ContributeToBarycenter(var currentSum: TAffineVector; var nb: Integer);
-begin
-  AddVector(currentSum, FVertices.Sum);
-  nb := nb + FVertices.Count;
-end;
-
-procedure TGLBaseMeshObject.Translate(const delta: TAffineVector);
-begin
-  FVertices.Translate(delta);
-end;
-
-procedure TGLBaseMeshObject.BuildNormals(vertexIndices: TGLIntegerList; Mode: TGLMeshObjectMode;
-  normalIndices: TGLIntegerList = nil);
-var
-  i, base: Integer;
-  n: TAffineVector;
-  newNormals: TGLIntegerList;
-
-  function TranslateNewNormal(vertexIndex: Integer; const delta: TAffineVector): Integer;
-  var
-    pv: PAffineVector;
-  begin
-    Result := newNormals[vertexIndex];
-    if Result < base then
-    begin
-      result := Normals.Add(NullVector);
-      newNormals[vertexIndex] := result;
-    end;
-    pv := @Normals.List[Result];
-    AddVector(pv^, delta);
-  end;
-
-begin
-  if not Assigned(normalIndices) then
-  begin
-    // build bijection
-    Normals.Clear;
-    Normals.Count := Vertices.Count;
-    case Mode of
-      momTriangles:
-        begin
-          i := 0;
-          while i <= vertexIndices.Count - 3 do
-            with Normals do
-            begin
-              with Vertices do
-              begin
-                CalcPlaneNormal(Items[vertexIndices[i + 0]],
-                  Items[vertexIndices[i + 1]],
-                  Items[vertexIndices[i + 2]], n);
-              end;
-              with Normals do
-              begin
-                TranslateItem(vertexIndices[i + 0], n);
-                TranslateItem(vertexIndices[i + 1], n);
-                TranslateItem(vertexIndices[i + 2], n);
-              end;
-              Inc(i, 3);
-            end;
-        end;
-      momTriangleStrip:
-        begin
-          i := 0;
-          while i <= vertexIndices.Count - 3 do
-            with Normals do
-            begin
-              with Vertices do
-              begin
-                if (i and 1) = 0 then
-                  CalcPlaneNormal(Items[vertexIndices[i + 0]],
-                    Items[vertexIndices[i + 1]],
-                    Items[vertexIndices[i + 2]], n)
-                else
-                  CalcPlaneNormal(Items[vertexIndices[i + 0]],
-                    Items[vertexIndices[i + 2]],
-                    Items[vertexIndices[i + 1]], n);
-              end;
-              with Normals do
-              begin
-                TranslateItem(vertexIndices[i + 0], n);
-                TranslateItem(vertexIndices[i + 1], n);
-                TranslateItem(vertexIndices[i + 2], n);
-              end;
-              Inc(i, 1);
-            end;
-        end;
-    else
-      Assert(False);
-    end;
-    Normals.Normalize;
-  end
-  else
-  begin
-    // add new normals
-    base := Normals.Count;
-    newNormals := TGLIntegerList.Create;
-    newNormals.AddSerie(-1, 0, Vertices.Count);
-    case Mode of
-      momTriangles:
-        begin
-          i := 0;
-          while i <= vertexIndices.Count - 3 do
-          begin
-            with Vertices do
-            begin
-              CalcPlaneNormal(Items[vertexIndices[i + 0]], Items[vertexIndices[i + 1]],
-			    Items[vertexIndices[i + 2]], n);
-            end;
-            normalIndices.Add(TranslateNewNormal(vertexIndices[i + 0], n));
-            normalIndices.Add(TranslateNewNormal(vertexIndices[i + 1], n));
-            normalIndices.Add(TranslateNewNormal(vertexIndices[i + 2], n));
-            Inc(i, 3);
-          end;
-        end;
-      momTriangleStrip:
-        begin
-          i := 0;
-          while i <= vertexIndices.Count - 3 do
-          begin
-            with Vertices do
-            begin
-              if (i and 1) = 0 then
-                CalcPlaneNormal(Items[vertexIndices[i + 0]],
-                  Items[vertexIndices[i + 1]],
-                  Items[vertexIndices[i + 2]], n)
-              else
-                CalcPlaneNormal(Items[vertexIndices[i + 0]],
-                  Items[vertexIndices[i + 2]],
-                  Items[vertexIndices[i + 1]], n);
-            end;
-            normalIndices.Add(TranslateNewNormal(vertexIndices[i + 0], n));
-            normalIndices.Add(TranslateNewNormal(vertexIndices[i + 1], n));
-            normalIndices.Add(TranslateNewNormal(vertexIndices[i + 2], n));
-            Inc(i, 1);
-          end;
-        end;
-    else
-      Assert(False);
-    end;
-    for i := base to Normals.Count - 1 do
-      NormalizeVector(Normals.List^[i]);
-    newNormals.Free;
-  end;
-end;
-
-procedure TGLBaseMeshObject.GenericOrderedBuildNormals(mode: TGLMeshObjectMode);
-var
-  i: Integer;
-  n: TAffineVector;
-
-begin
-  Normals.Clear;
-  Normals.Count := Vertices.Count;
-  case mode of
-    momTriangles:
-      begin
-        i := 0;
-        while i <= Vertices.Count - 3 do
-          with Normals do
-          begin
-            with Vertices do
-            begin
-              CalcPlaneNormal(Items[i], Items[i + 1], Items[i + 2], n);
-            end;
-            with Normals do
-            begin
-              TranslateItem(i, n);
-              TranslateItem(i + 1, n);
-              TranslateItem(i + 2, n);
-            end;
-            Inc(i, 3);
-          end;
-      end;
-    momTriangleStrip:
-      begin
-        i := 0;
-        while i <= Vertices.Count - 3 do
-          with Normals do
-          begin
-            with Vertices do
-            begin
-              if (i and 1) = 0 then
-                CalcPlaneNormal(Items[i], Items[i + 1], Items[i + 2], n)
-              else
-                CalcPlaneNormal(Items[i], Items[i + 2], Items[i + 1], n);
-            end;
-            with Normals do
-            begin
-              TranslateItem(i, n);
-              TranslateItem(i + 1, n);
-              TranslateItem(i + 2, n);
-            end;
-            Inc(i, 1);
-          end;
-      end
-  else
-    Assert(False);
-  end;
-  Normals.normalize;
-end;
-
-function TGLBaseMeshObject.ExtractTriangles(texCoords: TGLAffineVectorList = nil;
-  normals: TGLAffineVectorList = nil): TGLAffineVectorList;
-begin
-  Result := TGLAffineVectorList.Create;
-  if (Vertices.Count mod 3) = 0 then
-  begin
-    Result.Assign(Vertices);
-    if Assigned(normals) then
-      normals.Assign(Self.Normals);
-  end;
-end;
-
-procedure TGLBaseMeshObject.SetVertices(const val: TGLAffineVectorList);
-begin
-  FVertices.Assign(val);
-end;
-
-procedure TGLBaseMeshObject.SetNormals(const val: TGLAffineVectorList);
-begin
-  FNormals.Assign(val);
-end;
-
-// ------------------
-// ------------------ TGLSkeletonFrame ------------------
-// ------------------
-
-constructor TGLSkeletonFrame.CreateOwned(aOwner: TGLSkeletonFrameList);
-begin
-  FOwner := aOwner;
-  aOwner.Add(Self);
-  Create;
-end;
-
-constructor TGLSkeletonFrame.Create;
-begin
-  inherited Create;
-  FPosition := TGLAffineVectorList.Create;
-  FRotation := TGLAffineVectorList.Create;
-  FQuaternion := TGLQuaternionList.Create;
-  FTransformMode := sftRotation;
-end;
-
-destructor TGLSkeletonFrame.Destroy;
-begin
-  FlushLocalMatrixList;
-  FRotation.Free;
-  FPosition.Free;
-  FQuaternion.Free;
-  inherited Destroy;
-end;
-
-procedure TGLSkeletonFrame.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(1); // Archive Version 1
-    WriteString(FName);
-    FPosition.WriteToFiler(writer);
-    FRotation.WriteToFiler(writer);
-    FQuaternion.WriteToFiler(writer);
-    WriteInteger(Integer(FTransformMode));
-  end;
-end;
-
-procedure TGLSkeletonFrame.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if (archiveVersion = 0) or (archiveVersion = 1) then
-    with reader do
-    begin
-      FName := ReadString;
-      FPosition.ReadFromFiler(reader);
-      FRotation.ReadFromFiler(reader);
-      if (archiveVersion = 1) then
-      begin
-        FQuaternion.ReadFromFiler(reader);
-        FTransformMode := TGLSkeletonFrameTransform(ReadInteger);
-      end;
-    end
-  else
-    RaiseFilerException(archiveVersion);
-  FlushLocalMatrixList;
-end;
-
-procedure TGLSkeletonFrame.SetPosition(const val: TGLAffineVectorList);
-begin
-  FPosition.Assign(val);
-end;
-
-procedure TGLSkeletonFrame.SetRotation(const val: TGLAffineVectorList);
-begin
-  FRotation.Assign(val);
-end;
-
-procedure TGLSkeletonFrame.SetQuaternion(const val: TGLQuaternionList);
-begin
-  FQuaternion.Assign(val);
-end;
-
-function TGLSkeletonFrame.LocalMatrixList: PMatrixArray;
-var
-  i: Integer;
-  s, c: Single;
-  mat, rmat: TGLMatrix;
-  quat: TQuaternion;
-begin
-  if not Assigned(FLocalMatrixList) then
-  begin
-    case FTransformMode of
-      sftRotation:
-        begin
-          FLocalMatrixList := AllocMem(SizeOf(TGLMatrix) * Rotation.Count);
-          for i := 0 to Rotation.Count - 1 do
-          begin
-            if Rotation[i].X <> 0 then
-            begin
-              SinCosine(Rotation[i].X, s, c);
-              mat := CreateRotationMatrixX(s, c);
-            end
-            else
-              mat := IdentityHmgMatrix;
-            if Rotation[i].Y <> 0 then
-            begin
-              SinCosine(Rotation[i].Y, s, c);
-              rmat := CreateRotationMatrixY(s, c);
-              mat := MatrixMultiply(mat, rmat);
-            end;
-            if Rotation[i].Z <> 0 then
-            begin
-              SinCosine(Rotation[i].Z, s, c);
-              rmat := CreateRotationMatrixZ(s, c);
-              mat := MatrixMultiply(mat, rmat);
-            end;
-            mat.W.X := Position[i].X;
-            mat.W.Y := Position[i].Y;
-            mat.W.Z := Position[i].Z;
-            FLocalMatrixList^[i] := mat;
-          end;
-        end;
-      sftQuaternion:
-        begin
-          FLocalMatrixList := AllocMem(SizeOf(TGLMatrix) * Quaternion.Count);
-          for i := 0 to Quaternion.Count - 1 do
-          begin
-            quat := Quaternion[i];
-            mat := QuaternionToMatrix(quat);
-            mat.W.X := Position[i].X;
-            mat.W.Y := Position[i].Y;
-            mat.W.Z := Position[i].Z;
-            mat.W.W := 1;
-            FLocalMatrixList^[i] := mat;
-          end;
-        end;
-    end;
-  end;
-  Result := FLocalMatrixList;
-end;
-
-procedure TGLSkeletonFrame.FlushLocalMatrixList;
-begin
-  if Assigned(FLocalMatrixList) then
-  begin
-    FreeMem(FLocalMatrixList);
-    FLocalMatrixList := nil;
-  end;
-end;
-
-procedure TGLSkeletonFrame.ConvertQuaternionsToRotations(KeepQuaternions: Boolean = True);
-var
-  i: Integer;
-  t: TTransformations;
-  m: TGLMatrix;
-begin
-  Rotation.Clear;
-  for i := 0 to Quaternion.Count - 1 do
-  begin
-    m := QuaternionToMatrix(Quaternion[i]);
-    if MatrixDecompose(m, t) then
-      Rotation.Add(t[ttRotateX], t[ttRotateY], t[ttRotateZ])
-    else
-      Rotation.Add(NullVector);
-  end;
-  if not KeepQuaternions then
-    Quaternion.Clear;
-end;
-
-procedure TGLSkeletonFrame.ConvertRotationsToQuaternions(KeepRotations: Boolean = True);
-var
-  i: Integer;
-  mat, rmat: TGLMatrix;
-  s, c: Single;
-begin
-  Quaternion.Clear;
-  for i := 0 to Rotation.Count - 1 do
-  begin
-    mat := IdentityHmgMatrix;
-    SinCosine(Rotation[i].X, s, c);
-    rmat := CreateRotationMatrixX(s, c);
-    mat := MatrixMultiply(mat, rmat);
-    SinCosine(Rotation[i].Y, s, c);
-    rmat := CreateRotationMatrixY(s, c);
-    mat := MatrixMultiply(mat, rmat);
-    SinCosine(Rotation[i].Z, s, c);
-    rmat := CreateRotationMatrixZ(s, c);
-    mat := MatrixMultiply(mat, rmat);
-    Quaternion.Add(QuaternionFromMatrix(mat));
-  end;
-  if not KeepRotations then
-    Rotation.Clear;
-end;
-
-// ------------------
-// ------------------ TGLSkeletonFrameList ------------------
-// ------------------
-
-constructor TGLSkeletonFrameList.CreateOwned(aOwner: TPersistent);
-begin
-  FOwner := AOwner;
-  Create;
-end;
-
-destructor TGLSkeletonFrameList.Destroy;
-begin
-  Clear;
-  inherited;
-end;
-
-procedure TGLSkeletonFrameList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  i: Integer;
-begin
-  inherited;
-  for i := 0 to Count - 1 do
-    Items[i].FOwner := Self;
-end;
-
-procedure TGLSkeletonFrameList.Clear;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    with Items[i] do
-    begin
-      FOwner := nil;
-      Free;
-    end;
-  inherited;
-end;
-
-function TGLSkeletonFrameList.GetSkeletonFrame(Index: Integer): TGLSkeletonFrame;
-begin
-  Result := TGLSkeletonFrame(List^[Index]);
-end;
-
-procedure TGLSkeletonFrameList.ConvertQuaternionsToRotations(KeepQuaternions: Boolean = True; SetTransformMode: Boolean = True);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    Items[i].ConvertQuaternionsToRotations(KeepQuaternions);
-    if SetTransformMode then
-      Items[i].TransformMode := sftRotation;
-  end;
-end;
-
-procedure TGLSkeletonFrameList.ConvertRotationsToQuaternions(KeepRotations: Boolean = True; SetTransformMode: Boolean = True);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    Items[i].ConvertRotationsToQuaternions(KeepRotations);
-    if SetTransformMode then
-      Items[i].TransformMode := sftQuaternion;
-  end;
-end;
-
-// ------------------
-// ------------------ TGLSkeletonBoneList ------------------
-// ------------------
-
-constructor TGLSkeletonBoneList.CreateOwned(aOwner: TGLSkeleton);
-begin
-  FSkeleton := aOwner;
-  Create;
-end;
-
-constructor TGLSkeletonBoneList.Create;
-begin
-  inherited;
-  FGlobalMatrix := IdentityHmgMatrix;
-end;
-
-destructor TGLSkeletonBoneList.Destroy;
-begin
-  Clean;
-  inherited;
-end;
-
-procedure TGLSkeletonBoneList.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    // nothing, yet
-  end;
-end;
-
-procedure TGLSkeletonBoneList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion, i: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      // nothing, yet
-    end
-  else
-    RaiseFilerException(archiveVersion);
-  for i := 0 to Count - 1 do
-    Items[i].FOwner := Self;
-end;
-
-procedure TGLSkeletonBoneList.AfterObjectCreatedByReader(Sender: TObject);
-begin
-  with (Sender as TGLSkeletonBone) do
-  begin
-    FOwner := Self;
-    FSkeleton := Self.Skeleton;
-  end;
-end;
-
-function TGLSkeletonBoneList.GetSkeletonBone(Index: Integer): TGLSkeletonBone;
-begin
-  Result := TGLSkeletonBone(List^[Index]);
-end;
-
-function TGLSkeletonBoneList.BoneByID(anID: Integer): TGLSkeletonBone;
-var
-  i: Integer;
-begin
-  Result := nil;
-  for i := 0 to Count - 1 do
-  begin
-    Result := Items[i].BoneByID(anID);
-    if Assigned(Result) then
-      Break;
-  end;
-end;
-
-function TGLSkeletonBoneList.BoneByName(const aName: string): TGLSkeletonBone;
-var
-  i: Integer;
-begin
-  Result := nil;
-  for i := 0 to Count - 1 do
-  begin
-    Result := Items[i].BoneByName(aName);
-    if Assigned(Result) then
-      Break;
-  end;
-end;
-
-function TGLSkeletonBoneList.BoneCount: Integer;
-var
-  i: Integer;
-begin
-  Result := 1;
-  for i := 0 to Count - 1 do
-    Inc(Result, Items[i].BoneCount);
-end;
-
-procedure TGLSkeletonBoneList.PrepareGlobalMatrices;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    Items[i].PrepareGlobalMatrices;
-end;
-
-// ------------------
-// ------------------ TGLSkeletonRootBoneList ------------------
-// ------------------
-
-procedure TGLSkeletonRootBoneList.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    // nothing, yet
-  end;
-end;
-
-procedure TGLSkeletonRootBoneList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion, i: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      // nothing, yet
-    end
-  else
-    RaiseFilerException(archiveVersion);
-  for i := 0 to Count - 1 do
-    Items[i].FOwner := Self;
-end;
-
-procedure TGLSkeletonRootBoneList.BuildList(var mrci: TGLRenderContextInfo);
-var
-  i: Integer;
-begin
-  // root node setups and restore OpenGL stuff
-  mrci.GLStates.Disable(stColorMaterial);
-  mrci.GLStates.Disable(stLighting);
-  gl.Color3f(1, 1, 1);
-  // render root-bones
-  for i := 0 to Count - 1 do
-    Items[i].BuildList(mrci);
-end;
-
-// ------------------
-// ------------------ TGLSkeletonBone ------------------
-// ------------------
-
-constructor TGLSkeletonBone.CreateOwned(aOwner: TGLSkeletonBoneList);
-begin
-  FOwner := aOwner;
-  aOwner.Add(Self);
-  FSkeleton := aOwner.Skeleton;
-  Create;
-end;
-
-constructor TGLSkeletonBone.Create;
-begin
-  FColor := $FFFFFFFF; // opaque white
-  inherited;
-end;
-
-destructor TGLSkeletonBone.Destroy;
-begin
-  if Assigned(Owner) then
-    Owner.Remove(Self);
-  inherited Destroy;
-end;
-
-procedure TGLSkeletonBone.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    WriteString(FName);
-    WriteInteger(FBoneID);
-    WriteInteger(Integer(FColor));
-  end;
-end;
-
-procedure TGLSkeletonBone.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion, i: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      FName := ReadString;
-      FBoneID := ReadInteger;
-      FColor := Cardinal(ReadInteger);
-    end
-  else
-    RaiseFilerException(archiveVersion);
-  for i := 0 to Count - 1 do
-    Items[i].FOwner := Self;
-end;
-
-procedure TGLSkeletonBone.BuildList(var mrci: TGLRenderContextInfo);
-
-  procedure IssueColor(Color: Cardinal);
-  begin
-    gl.Color4f(GetRValue(Color) / 255, GetGValue(Color) / 255, GetBValue(Color) / 255, ((Color shr 24) and 255) / 255);
-  end;
-
-var
-  i: Integer;
-begin
-  // point for self
-  mrci.GLStates.PointSize := 5;
-  gl.Begin_(GL_POINTS);
-  IssueColor(Color);
-  gl.Vertex3fv(@GlobalMatrix.W.X);
-  gl.End_;
-  // parent-self bone line
-  if Owner is TGLSkeletonBone then
-  begin
-    gl.Begin_(GL_LINES);
-    gl.Vertex3fv(@TGLSkeletonBone(Owner).GlobalMatrix.W.X);
-    gl.Vertex3fv(@GlobalMatrix.W.X);
-    gl.End_;
-  end;
-  // render sub-bones
-  for i := 0 to Count - 1 do
-    Items[i].BuildList(mrci);
-end;
-
-function TGLSkeletonBone.GetSkeletonBone(Index: Integer): TGLSkeletonBone;
-begin
-  Result := TGLSkeletonBone(List^[Index]);
-end;
-
-procedure TGLSkeletonBone.SetColor(const val: Cardinal);
-begin
-  FColor := val;
-end;
-
-function TGLSkeletonBone.BoneByID(anID: Integer): TGLSkeletonBone;
-begin
-  if BoneID = anID then
-    Result := Self
-  else
-    Result := inherited BoneByID(anID);
-end;
-
-function TGLSkeletonBone.BoneByName(const aName: string): TGLSkeletonBone;
-begin
-  if Name = aName then
-    Result := Self
-  else
-    Result := inherited BoneByName(aName);
-end;
-
-procedure TGLSkeletonBone.Clean;
-begin
-  BoneID := 0;
-  Name := '';
-  inherited;
-end;
-
-procedure TGLSkeletonBone.PrepareGlobalMatrices;
-begin
-  if (Skeleton.FRagDollEnabled) then
-    Exit; // ragdoll
-  FGlobalMatrix :=
-    MatrixMultiply(Skeleton.CurrentFrame.LocalMatrixList^[BoneID],
-    TGLSkeletonBoneList(Owner).FGlobalMatrix);
-  inherited;
-end;
-
-procedure TGLSkeletonBone.SetGlobalMatrix(const Matrix: TGLMatrix); // ragdoll
-begin
-  FGlobalMatrix := Matrix;
-end;
-
-procedure TGLSkeletonBone.SetGlobalMatrixForRagDoll(const RagDollMatrix: TGLMatrix);
-// ragdoll
-begin
-  FGlobalMatrix := MatrixMultiply(RagDollMatrix,
-    Skeleton.Owner.InvAbsoluteMatrix);
-  inherited;
-end;
-
-// ------------------
-// ------------------ TGLSkeletonCollider ------------------
-// ------------------
-
-constructor TGLSkeletonCollider.Create;
-begin
-  inherited;
-  FLocalMatrix := IdentityHmgMatrix;
-  FGlobalMatrix := IdentityHmgMatrix;
-  FAutoUpdate := True;
-end;
-
-constructor TGLSkeletonCollider.CreateOwned(AOwner: TGLSkeletonColliderList);
-begin
-  Create;
-  FOwner := AOwner;
-  if Assigned(FOwner) then
-    FOwner.Add(Self);
-end;
-
-procedure TGLSkeletonCollider.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    if Assigned(FBone) then
-      WriteInteger(FBone.BoneID)
-    else
-      WriteInteger(-1);
-    Write(FLocalMatrix, SizeOf(TGLMatrix));
-  end;
-end;
-
-procedure TGLSkeletonCollider.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      FBoneID := ReadInteger;
-      Read(FLocalMatrix, SizeOf(TGLMatrix));
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TGLSkeletonCollider.AlignCollider;
-var
-  mat: TGLMatrix;
-begin
-  if Assigned(FBone) then
-  begin
-    if Owner.Owner is TGLSkeleton then
-      if TGLSkeleton(Owner.Owner).Owner is TGLBaseSceneObject then
-        mat := MatrixMultiply(FBone.GlobalMatrix,
-          TGLBaseSceneObject(TGLSkeleton(Owner.Owner).Owner).AbsoluteMatrix)
-      else
-        mat := FBone.GlobalMatrix;
-    MatrixMultiply(FLocalMatrix, mat, FGlobalMatrix);
-  end
-  else
-    FGlobalMatrix := FLocalMatrix;
-end;
-
-procedure TGLSkeletonCollider.SetBone(const val: TGLSkeletonBone);
-begin
-  if val <> FBone then
-    FBone := val;
-end;
-
-procedure TGLSkeletonCollider.SetLocalMatrix(const val: TGLMatrix);
-begin
-  FLocalMatrix := val;
-end;
-
-// ------------------
-// ------------------ TGLSkeletonColliderList ------------------
-// ------------------
-
-constructor TGLSkeletonColliderList.CreateOwned(aOwner: TPersistent);
-begin
-  Create;
-  FOwner := aOwner;
-end;
-
-destructor TGLSkeletonColliderList.Destroy;
-begin
-  Clear;
-  inherited;
-end;
-
-function TGLSkeletonColliderList.GetSkeletonCollider(Index: Integer): TGLSkeletonCollider;
-begin
-  Result := TGLSkeletonCollider(inherited Get(index));
-end;
-
-procedure TGLSkeletonColliderList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  i: Integer;
-begin
-  inherited;
-  for i := 0 to Count - 1 do
-  begin
-    Items[i].FOwner := Self;
-    if (Owner is TGLSkeleton) and (Items[i].FBoneID <> -1) then
-      Items[i].Bone := TGLSkeleton(Owner).BoneByID(Items[i].FBoneID);
-  end;
-end;
-
-procedure TGLSkeletonColliderList.Clear;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    Items[i].FOwner := nil;
-    Items[i].Free;
-  end;
-  inherited;
-end;
-
-procedure TGLSkeletonColliderList.AlignColliders;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    if Items[i].AutoUpdate then
-      Items[i].AlignCollider;
-end;
-
-// ------------------
-// ------------------ TGLSkeleton ------------------
-// ------------------
-
-constructor TGLSkeleton.CreateOwned(AOwner: TGLBaseMesh);
-begin
-  FOwner := aOwner;
-  Create;
-end;
-
-constructor TGLSkeleton.Create;
-begin
-  inherited Create;
-  FRootBones := TGLSkeletonRootBoneList.CreateOwned(Self);
-  FFrames := TGLSkeletonFrameList.CreateOwned(Self);
-  FColliders := TGLSkeletonColliderList.CreateOwned(Self);
-end;
-
-destructor TGLSkeleton.Destroy;
-begin
-  FlushBoneByIDCache;
-  FCurrentFrame.Free;
-  FFrames.Free;
-  FRootBones.Free;
-  FColliders.Free;
-  inherited Destroy;
-end;
-
-procedure TGLSkeleton.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    if FColliders.Count > 0 then
-      WriteInteger(1) // Archive Version 1 : with colliders
-    else
-      WriteInteger(0); // Archive Version 0
-    FRootBones.WriteToFiler(writer);
-    FFrames.WriteToFiler(writer);
-    if FColliders.Count > 0 then
-      FColliders.WriteToFiler(writer);
-  end;
-end;
-
-procedure TGLSkeleton.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if (archiveVersion = 0) or (archiveVersion = 1) then
-    with reader do
-    begin
-      FRootBones.ReadFromFiler(reader);
-      FFrames.ReadFromFiler(reader);
-      if (archiveVersion = 1) then
-        FColliders.ReadFromFiler(reader);
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TGLSkeleton.SetRootBones(const val: TGLSkeletonRootBoneList);
-begin
-  FRootBones.Assign(val);
-end;
-
-procedure TGLSkeleton.SetFrames(const val: TGLSkeletonFrameList);
-begin
-  FFrames.Assign(val);
-end;
-
-function TGLSkeleton.GetCurrentFrame: TGLSkeletonFrame;
-begin
-  if not Assigned(FCurrentFrame) then
-    FCurrentFrame := TGLSkeletonFrame(FFrames.Items[0].CreateClone);
-  Result := FCurrentFrame;
-end;
-
-procedure TGLSkeleton.SetCurrentFrame(val: TGLSkeletonFrame);
-begin
-  if Assigned(FCurrentFrame) then
-    FCurrentFrame.Free;
-  FCurrentFrame := TGLSkeletonFrame(val.CreateClone);
-end;
-
-procedure TGLSkeleton.SetColliders(const val: TGLSkeletonColliderList);
-begin
-  FColliders.Assign(val);
-end;
-
-procedure TGLSkeleton.FlushBoneByIDCache;
-begin
-  FBonesByIDCache.Free;
-  FBonesByIDCache := nil;
-end;
-
-function TGLSkeleton.BoneByID(anID: Integer): TGLSkeletonBone;
-
-  procedure CollectBones(Bone: TGLSkeletonBone);
-  var
-    i: Integer;
-  begin
-    if Bone.BoneID >= FBonesByIDCache.Count then
-      FBonesByIDCache.Count := Bone.BoneID + 1;
-    FBonesByIDCache[Bone.BoneID] := Bone;
-    for i := 0 to Bone.Count - 1 do
-      CollectBones(Bone[i]);
-  end;
-
-var
-  i: Integer;
-begin
-  if not Assigned(FBonesByIDCache) then
-  begin
-    FBonesByIDCache := TList.Create;
-    for i := 0 to RootBones.Count - 1 do
-      CollectBones(RootBones[i]);
-  end;
-  Result := TGLSkeletonBone(FBonesByIDCache[anID])
-end;
-
-function TGLSkeleton.BoneByName(const aName: string): TGLSkeletonBone;
-begin
-  Result := RootBones.BoneByName(aName);
-end;
-
-function TGLSkeleton.BoneCount: Integer;
-begin
-  Result := RootBones.BoneCount;
-end;
-
-procedure TGLSkeleton.MorphTo(frameIndex: Integer);
-begin
-  CurrentFrame := Frames[frameIndex];
-end;
-
-procedure TGLSkeleton.MorphTo(frame: TGLSkeletonFrame);
-begin
-  CurrentFrame := frame;
-end;
-
-procedure TGLSkeleton.Lerp(frameIndex1, frameIndex2: Integer; lerpFactor: Single);
-begin
-  if Assigned(FCurrentFrame) then
-    FCurrentFrame.Free;
-  FCurrentFrame := TGLSkeletonFrame.Create;
-  FCurrentFrame.TransformMode := Frames[frameIndex1].TransformMode;
-  with FCurrentFrame do
-  begin
-    Position.Lerp(Frames[frameIndex1].Position,
-      Frames[frameIndex2].Position, lerpFactor);
-    case TransformMode of
-      sftRotation: Rotation.AngleLerp(Frames[frameIndex1].Rotation,
-          Frames[frameIndex2].Rotation, lerpFactor);
-      sftQuaternion: Quaternion.Lerp(Frames[frameIndex1].Quaternion,
-          Frames[frameIndex2].Quaternion, lerpFactor);
-    end;
-  end;
-end;
-
-procedure TGLSkeleton.BlendedLerps(const lerpInfos: array of TGLBlendedLerpInfo);
-var
-  i, n: Integer;
-  blendPositions: TGLAffineVectorList;
-  blendRotations: TGLAffineVectorList;
-  blendQuaternions: TGLQuaternionList;
-begin
-  n := High(lerpInfos) - Low(lerpInfos) + 1;
-  Assert(n >= 1);
-  i := Low(lerpInfos);
-  if n = 1 then
-  begin
-    // use fast lerp (no blend)
-    with lerpInfos[i] do
-      Lerp(frameIndex1, frameIndex2, lerpFactor);
-  end
-  else
-  begin
-    if Assigned(FCurrentFrame) then
-      FCurrentFrame.Free;
-    FCurrentFrame := TGLSkeletonFrame.Create;
-    FCurrentFrame.TransformMode :=
-      Frames[lerpInfos[i].frameIndex1].TransformMode;
-    with FCurrentFrame do
-    begin
-      blendPositions := TGLAffineVectorList.Create;
-      // lerp first item separately
-      Position.Lerp(Frames[lerpInfos[i].frameIndex1].Position,
-        Frames[lerpInfos[i].frameIndex2].Position,
-        lerpInfos[i].lerpFactor);
-      if lerpInfos[i].weight <> 1 then
-        Position.Scale(lerpInfos[i].weight);
-
-      Inc(i);
-      // combine the other items
-      while i <= High(lerpInfos) do
-      begin
-        if not Assigned(lerpInfos[i].externalPositions) then
-        begin
-          blendPositions.Lerp(Frames[lerpInfos[i].frameIndex1].Position,
-            Frames[lerpInfos[i].frameIndex2].Position,
-            lerpInfos[i].lerpFactor);
-          Position.AngleCombine(blendPositions, 1);
-        end
-        else
-          Position.Combine(lerpInfos[i].externalPositions, 1);
-        Inc(i);
-      end;
-      blendPositions.Free;
-
-      i := Low(lerpInfos);
-      case TransformMode of
-        sftRotation:
-          begin
-            blendRotations := TGLAffineVectorList.Create;
-            // lerp first item separately
-            Rotation.AngleLerp(Frames[lerpInfos[i].frameIndex1].Rotation,
-              Frames[lerpInfos[i].frameIndex2].Rotation,
-              lerpInfos[i].lerpFactor);
-            Inc(i);
-            // combine the other items
-            while i <= High(lerpInfos) do
-            begin
-              if not Assigned(lerpInfos[i].externalRotations) then
-              begin
-                blendRotations.AngleLerp(Frames[lerpInfos[i].frameIndex1].Rotation,
-                  Frames[lerpInfos[i].frameIndex2].Rotation,
-                  lerpInfos[i].lerpFactor);
-                Rotation.AngleCombine(blendRotations, 1);
-              end
-              else
-                Rotation.AngleCombine(lerpInfos[i].externalRotations, 1);
-              Inc(i);
-            end;
-            blendRotations.Free;
-          end;
-
-        sftQuaternion:
-          begin
-            blendQuaternions := TGLQuaternionList.Create;
-            // Initial frame lerp
-            Quaternion.Lerp(Frames[lerpInfos[i].frameIndex1].Quaternion,
-              Frames[lerpInfos[i].frameIndex2].Quaternion,
-              lerpInfos[i].lerpFactor);
-            Inc(i);
-            // Combine the lerped frames together
-            while i <= High(lerpInfos) do
-            begin
-              if not Assigned(lerpInfos[i].externalQuaternions) then
-              begin
-                blendQuaternions.Lerp(Frames[lerpInfos[i].frameIndex1].Quaternion,
-                  Frames[lerpInfos[i].frameIndex2].Quaternion,
-                  lerpInfos[i].lerpFactor);
-                Quaternion.Combine(blendQuaternions, 1);
-              end
-              else
-                Quaternion.Combine(lerpInfos[i].externalQuaternions, 1);
-              Inc(i);
-            end;
-            blendQuaternions.Free;
-          end;
-      end;
-    end;
-  end;
-end;
-
-procedure TGLSkeleton.MakeSkeletalTranslationStatic(startFrame, endFrame: Integer);
-var
-  delta: TAffineVector;
-  i: Integer;
-  f: Single;
-begin
-  if endFrame <= startFrame then
-    Exit;
-  delta := VectorSubtract(Frames[endFrame].Position[0],
-    Frames[startFrame].Position[0]);
-  f := -1 / (endFrame - startFrame);
-  for i := startFrame to endFrame do
-    Frames[i].Position[0] := VectorCombine(Frames[i].Position[0], delta,
-      1, (i - startFrame) * f);
-end;
-
-procedure TGLSkeleton.MakeSkeletalRotationDelta(startFrame, endFrame: Integer);
-var
-  i, j: Integer;
-  v: TAffineVector;
-begin
-  if endFrame <= startFrame then
-    Exit;
-  for i := startFrame to endFrame do
-  begin
-    for j := 0 to Frames[i].Position.Count - 1 do
-    begin
-      Frames[i].Position[j] := NullVector;
-      v := VectorSubtract(Frames[i].Rotation[j],
-        Frames[0].Rotation[j]);
-      if VectorNorm(v) < 1e-6 then
-        Frames[i].Rotation[j] := NullVector
-      else
-        Frames[i].Rotation[j] := v;
-    end;
-  end;
-end;
-
-procedure TGLSkeleton.MorphMesh(normalize: Boolean);
-var
-  i: Integer;
-  mesh: TGLBaseMeshObject;
-begin
-  if Owner.MeshObjects.Count > 0 then
-  begin
-    RootBones.PrepareGlobalMatrices;
-    if Colliders.Count > 0 then
-      Colliders.AlignColliders;
-
-    if FMorphInvisibleParts then
-      for i := 0 to Owner.MeshObjects.Count - 1 do
-      begin
-        mesh := Owner.MeshObjects.Items[i];
-        if (mesh is TGLSkeletonMeshObject) then
-          TGLSkeletonMeshObject(mesh).ApplyCurrentSkeletonFrame(normalize);
-      end
-    else
-      for i := 0 to Owner.MeshObjects.Count - 1 do
-      begin
-        mesh := Owner.MeshObjects.Items[i];
-        if (mesh is TGLSkeletonMeshObject) and mesh.Visible then
-          TGLSkeletonMeshObject(mesh).ApplyCurrentSkeletonFrame(normalize);
-      end
-  end;
-end;
-
-procedure TGLSkeleton.Synchronize(reference: TGLSkeleton);
-begin
-  CurrentFrame.Assign(reference.CurrentFrame);
-  MorphMesh(True);
-end;
-
-procedure TGLSkeleton.Clear;
-begin
-  FlushBoneByIDCache;
-  RootBones.Clean;
-  Frames.Clear;
-  FCurrentFrame.Free;
-  FCurrentFrame := nil;
-  FColliders.Clear;
-end;
-
-procedure TGLSkeleton.StartRagDoll; // ragdoll
-var
-  i: Integer;
-  mesh: TGLBaseMeshObject;
-begin
-  if FRagDollEnabled then
-    Exit
-  else
-    FRagDollEnabled := True;
-
-  if Owner.MeshObjects.Count > 0 then
-  begin
-    for i := 0 to Owner.MeshObjects.Count - 1 do
-    begin
-      mesh := Owner.MeshObjects.Items[i];
-      if mesh is TGLSkeletonMeshObject then
-      begin
-        TGLSkeletonMeshObject(mesh).BackupBoneMatrixInvertedMeshes;
-        TGLSkeletonMeshObject(mesh).PrepareBoneMatrixInvertedMeshes;
-      end;
-    end;
-  end;
-end;
-
-procedure TGLSkeleton.StopRagDoll; // ragdoll
-var
-  i: Integer;
-  mesh: TGLBaseMeshObject;
-begin
-  FRagDollEnabled := False;
-  if Owner.MeshObjects.Count > 0 then
-  begin
-    for i := 0 to Owner.MeshObjects.Count - 1 do
-    begin
-      mesh := Owner.MeshObjects.Items[i];
-      if mesh is TGLSkeletonMeshObject then
-        TGLSkeletonMeshObject(mesh).RestoreBoneMatrixInvertedMeshes;
-    end;
-  end;
-end;
-
-// ------------------
-// ------------------ TGLMeshObject ------------------
-// ------------------
-
-constructor TGLMeshObject.CreateOwned(AOwner: TGLMeshObjectList);
-begin
-  FOwner := AOwner;
-  Create;
-  if Assigned(FOwner) then
-    FOwner.Add(Self);
-end;
-
-constructor TGLMeshObject.Create;
-begin
-  FMode := momTriangles;
-  FTexCoords := TGLAffineVectorList.Create;
-  FLightMapTexCoords := TGLAffineVectorList.Create;
-  FColors := TGLVectorList.Create;
-  FFaceGroups := TGLFaceGroups.CreateOwned(Self);
-  FTexCoordsEx := TList.Create;
-  FTangentsTexCoordIndex := 1;
-  FBinormalsTexCoordIndex := 2;
-
-  FUseVBO := vGLVectorFileObjectsEnableVBOByDefault;
-  inherited;
-end;
-
-destructor TGLMeshObject.Destroy;
-var
-  i: Integer;
-begin
-  FVerticesVBO.Free;
-  FNormalsVBO.Free;
-  FColorsVBO.Free;
-  for i := 0 to high(FTexCoordsVBO) do
-    FTexCoordsVBO[i].Free;
-  FLightmapTexCoordsVBO.Free;
-
-  FFaceGroups.Free;
-  FColors.Free;
-  FTexCoords.Free;
-  FLightMapTexCoords.Free;
-  for i := 0 to FTexCoordsEx.Count - 1 do
-    TGLVectorList(FTexCoordsEx[i]).Free;
-  FTexCoordsEx.Free;
-  if Assigned(FOwner) then
-    FOwner.Remove(Self);
-  inherited;
-end;
-
-procedure TGLMeshObject.Assign(Source: TPersistent);
-var
-  I: Integer;
-begin
-  inherited Assign(Source);
-
-  if Source is TGLMeshObject then
-  begin
-    FTexCoords.Assign(TGLMeshObject(Source).FTexCoords);
-    FLightMapTexCoords.Assign(TGLMeshObject(Source).FLightMapTexCoords);
-    FColors.Assign(TGLMeshObject(Source).FColors);
-    FFaceGroups.Assign(TGLMeshObject(Source).FFaceGroups);
-    FMode := TGLMeshObject(Source).FMode;
-    FRenderingOptions := TGLMeshObject(Source).FRenderingOptions;
-    FBinormalsTexCoordIndex := TGLMeshObject(Source).FBinormalsTexCoordIndex;
-    FTangentsTexCoordIndex := TGLMeshObject(Source).FTangentsTexCoordIndex;
-
-    // Clear FTexCoordsEx.
-    for I := 0 to FTexCoordsEx.Count - 1 do
-      TGLVectorList(FTexCoordsEx[I]).Free;
-
-    FTexCoordsEx.Count := TGLMeshObject(Source).FTexCoordsEx.Count;
-
-    // Fill FTexCoordsEx.
-    for I := 0 to FTexCoordsEx.Count - 1 do
-    begin
-      FTexCoordsEx[I] := TGLVectorList.Create;
-      TGLVectorList(FTexCoordsEx[I]).Assign(TGLMeshObject(Source).FTexCoordsEx[I]);
-    end;
-  end;
-end;
-
-procedure TGLMeshObject.WriteToFiler(writer: TGLVirtualWriter);
-var
-  i: Integer;
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(3); // Archive Version 3
-    FTexCoords.WriteToFiler(writer);
-    FLightMapTexCoords.WriteToFiler(writer);
-    FColors.WriteToFiler(writer);
-    FFaceGroups.WriteToFiler(writer);
-    WriteInteger(Integer(FMode));
-    WriteInteger(SizeOf(FRenderingOptions));
-    Write(FRenderingOptions, SizeOf(FRenderingOptions));
-    WriteInteger(FTexCoordsEx.Count);
-    for i := 0 to FTexCoordsEx.Count - 1 do
-      TexCoordsEx[i].WriteToFiler(writer);
-    WriteInteger(BinormalsTexCoordIndex);
-    WriteInteger(TangentsTexCoordIndex);
-  end;
-end;
-
-procedure TGLMeshObject.ReadFromFiler(reader: TGLVirtualReader);
-var
-  i, Count, archiveVersion: Integer;
-  lOldLightMapTexCoords: TGLTexPointList;
-  tc: TTexPoint;
-  size, ro: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion in [0 .. 3] then
-    with reader do
-    begin
-      FTexCoords.ReadFromFiler(reader);
-      if archiveVersion = 0 then
-      begin
-        // FLightMapTexCoords did not exist back than.
-        FLightMapTexCoords.Clear;
-      end
-      else if (archiveVersion = 1) or (archiveVersion = 2) then
-      begin
-        lOldLightMapTexCoords := TGLTexPointList.CreateFromFiler(reader);
-        for i := 0 to lOldLightMapTexCoords.Count - 1 do
-        begin
-          tc:=lOldLightMapTexCoords[i];
-          FLightMapTexCoords.Add(tc.S, tc.T);
-        end;
-        lOldLightMapTexCoords.Free;
-      end
-      else
-      begin
-        // Load FLightMapTexCoords the normal way.
-        FLightMapTexCoords.ReadFromFiler(reader);
-      end;
-
-      FColors.ReadFromFiler(reader);
-      FFaceGroups.ReadFromFiler(reader);
-      FMode := TGLMeshObjectMode(ReadInteger);
-      size := ReadInteger;
-      ro := 0;
-      Read(ro, size);
-      FRenderingOptions := TGLMeshObjectRenderingOptions(Byte(ro));
-      if archiveVersion >= 2 then
-      begin
-        Count := ReadInteger;
-        for i := 0 to Count - 1 do
-          TexCoordsEx[i].ReadFromFiler(reader);
-        BinormalsTexCoordIndex := ReadInteger;
-        TangentsTexCoordIndex := ReadInteger;
-      end;
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TGLMeshObject.Clear;
-var
-  i: Integer;
-begin
-  inherited;
-  FFaceGroups.Clear;
-  FColors.Clear;
-  FTexCoords.Clear;
-  FLightMapTexCoords.Clear;
-  for i := 0 to FTexCoordsEx.Count - 1 do
-    TexCoordsEx[i].Clear;
-end;
-
-function TGLMeshObject.ExtractTriangles(texCoords: TGLAffineVectorList = nil;
-  Normals: TGLAffineVectorList = nil): TGLAffineVectorList;
-begin
-  case Mode of
-    momTriangles:
-      begin
-        Result := inherited ExtractTriangles;
-        if Assigned(texCoords) then
-          texCoords.Assign(Self.TexCoords);
-        if Assigned(normals) then
-          normals.Assign(Self.Normals);
-      end;
-    momTriangleStrip:
-      begin
-        Result := TGLAffineVectorList.Create;
-        ConvertStripToList(Vertices, Result);
-        if Assigned(texCoords) then
-          ConvertStripToList(Self.TexCoords, texCoords);
-        if Assigned(normals) then
-          ConvertStripToList(Self.Normals, normals);
-      end;
-    momFaceGroups:
-      begin
-        Result := TGLAffineVectorList.Create;
-        FaceGroups.AddToTriangles(Result, texCoords, normals);
-      end;
-  else
-    Result := nil;
-    Assert(False);
-  end;
-end;
-
-function TGLMeshObject.TriangleCount: Integer;
-var
-  i: Integer;
-begin
-  case Mode of
-    momTriangles:
-      Result := (Vertices.Count div 3);
-    momTriangleStrip:
-      begin
-        Result := Vertices.Count - 2;
-        if Result < 0 then
-          Result := 0;
-      end;
-    momFaceGroups:
-      begin
-        Result := 0;
-        for i := 0 to FaceGroups.Count - 1 do
-          Result := Result + FaceGroups[i].TriangleCount;
-      end;
-  else
-    Result := 0;
-    Assert(False);
-  end;
-end;
-
-procedure TGLMeshObject.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
-begin
-  FaceGroups.PrepareMaterialLibraryCache(matLib);
-end;
-
-procedure TGLMeshObject.DropMaterialLibraryCache;
-begin
-  FaceGroups.DropMaterialLibraryCache;
-end;
-
-procedure TGLMeshObject.GetExtents(out min, max: TAffineVector);
-begin
-  if FVertices.Revision <> FExtentCacheRevision then
-  begin
-    FVertices.GetExtents(FExtentCache.min, FExtentCache.max);
-    FExtentCacheRevision := FVertices.Revision;
-  end;
-  min := FExtentCache.min;
-  max := FExtentCache.max;
-end;
-
-procedure TGLMeshObject.GetExtents(out aabb: TAABB);
-begin
-  if FVertices.Revision <> FExtentCacheRevision then
-  begin
-    FVertices.GetExtents(FExtentCache.min, FExtentCache.max);
-    FExtentCacheRevision := FVertices.Revision;
-  end;
-  aabb := FExtentCache;
-end;
-
-function TGLMeshObject.GetBarycenter: TGLVector;
-var
-  dMin, dMax: TAffineVector;
-begin
-  GetExtents(dMin, dMax);
-
-  Result.X := (dMin.X + dMax.X) / 2;
-  Result.Y := (dMin.Y + dMax.Y) / 2;
-  Result.Z := (dMin.Z + dMax.Z) / 2;
-  Result.W := 0;
-end;
-
-procedure TGLMeshObject.Prepare;
-var
-  i: Integer;
-begin
-  ValidBuffers := [];
-  for i := 0 to FaceGroups.Count - 1 do
-    FaceGroups[i].Prepare;
-end;
-
-function TGLMeshObject.PointInObject(const aPoint: TAffineVector): Boolean;
-var
-  min, max: TAffineVector;
-begin
-  GetExtents(min, max);
-  Result := (aPoint.X >= min.X) and
-            (aPoint.Y >= min.Y) and
-            (aPoint.Z >= min.Z) and
-            (aPoint.X <= max.X) and
-            (aPoint.Y <= max.Y) and
-            (aPoint.Z <= max.Z);
-end;
-
-procedure TGLMeshObject.SetTexCoords(const val: TGLAffineVectorList);
-begin
-  FTexCoords.Assign(val);
-end;
-
-procedure TGLMeshObject.SetLightmapTexCoords(const val: TGLAffineVectorList);
-begin
-  FLightMapTexCoords.Assign(val);
-end;
-
-procedure TGLMeshObject.SetColors(const val: TGLVectorList);
-begin
-  FColors.Assign(val);
-end;
-
-procedure TGLMeshObject.SetTexCoordsEx(Index: Integer; const val: TGLVectorList);
-begin
-  TexCoordsEx[index].Assign(val);
-end;
-
-function TGLMeshObject.GetTexCoordsEx(Index: Integer): TGLVectorList;
-var
-  i: Integer;
-begin
-  if index > FTexCoordsEx.Count - 1 then
-    for i := FTexCoordsEx.Count - 1 to index do
-      FTexCoordsEx.Add(TGLVectorList.Create);
-  Result := TGLVectorList(FTexCoordsEx[index]);
-end;
-
-procedure TGLMeshObject.SetBinormals(const val: TGLVectorList);
-begin
-  Binormals.Assign(val);
-end;
-
-function TGLMeshObject.GetBinormals: TGLVectorList;
-begin
-  Result := TexCoordsEx[BinormalsTexCoordIndex];
-end;
-
-procedure TGLMeshObject.SetBinormalsTexCoordIndex(const val: Integer);
-begin
-  Assert(val >= 0);
-  if val <> FBinormalsTexCoordIndex then
-  begin
-    FBinormalsTexCoordIndex := val;
-  end;
-end;
-
-procedure TGLMeshObject.SetTangents(const val: TGLVectorList);
-begin
-  Tangents.Assign(val);
-end;
-
-function TGLMeshObject.GetTangents: TGLVectorList;
-begin
-  Result := TexCoordsEx[TangentsTexCoordIndex];
-end;
-
-procedure TGLMeshObject.SetTangentsTexCoordIndex(const val: Integer);
-begin
-  Assert(val >= 0);
-  if val <> FTangentsTexCoordIndex then
-  begin
-    FTangentsTexCoordIndex := val;
-  end;
-end;
-
-procedure TGLMeshObject.GetTriangleData(tri: Integer; list: TGLAffineVectorList; var v0, v1, v2: TAffineVector);
-var
-  i, LastCount, Count: Integer;
-  fg: TFGVertexIndexList;
-begin
-  case Mode of
-    momTriangles:
-      begin
-        v0 := list[3 * tri];
-        v1 := list[3 * tri + 1];
-        v2 := list[3 * tri + 2];
-      end;
-    momTriangleStrip:
-      begin
-        v0 := list[tri];
-        v1 := list[tri + 1];
-        v2 := list[tri + 2];
-      end;
-    momFaceGroups:
-      begin
-        Count := 0;
-        for i := 0 to FaceGroups.Count - 1 do
-        begin
-          LastCount := Count;
-          fg := TFGVertexIndexList(FaceGroups[i]);
-          Count := Count + fg.TriangleCount;
-          if Count > tri then
-          begin
-            Count := tri - LastCount;
-            case fg.Mode of
-              fgmmTriangles, fgmmFlatTriangles:
-                begin
-                  v0 := list[fg.VertexIndices[3 * Count]];
-                  v1 := list[fg.VertexIndices[3 * Count + 1]];
-                  v2 := list[fg.VertexIndices[3 * Count + 2]];
-                end;
-              fgmmTriangleStrip:
-                begin
-                  v0 := list[fg.VertexIndices[Count]];
-                  v1 := list[fg.VertexIndices[Count + 1]];
-                  v2 := list[fg.VertexIndices[Count + 2]];
-                end;
-              fgmmTriangleFan:
-                begin
-                  v0 := list[fg.VertexIndices[0]];
-                  v1 := list[fg.VertexIndices[Count + 1]];
-                  v2 := list[fg.VertexIndices[Count + 2]];
-                end;
-              fgmmQuads:
-                begin
-                  if Count mod 2 = 0 then
-                  begin
-                    v0 := list[fg.VertexIndices[4 * (Count div 2)]];
-                    v1 := list[fg.VertexIndices[4 * (Count div 2) + 1]];
-                    v2 := list[fg.VertexIndices[4 * (Count div 2) + 2]];
-                  end
-                  else
-                  begin
-                    v0 := list[fg.VertexIndices[4 * (Count div 2)]];
-                    v1 := list[fg.VertexIndices[4 * (Count div 2) + 2]];
-                    v2 := list[fg.VertexIndices[4 * (Count div 2) + 3]];
-                  end;
-                end;
-            else
-              Assert(False);
-            end;
-            Break;
-          end;
-        end;
-
-      end;
-  else
-    Assert(False);
-  end;
-end;
-
-procedure TGLMeshObject.GetTriangleData(tri: Integer; list: TGLVectorList; var v0, v1, v2: TGLVector);
-var
-  i, LastCount, Count: Integer;
-  fg: TFGVertexIndexList;
-begin
-  case Mode of
-    momTriangles:
-      begin
-        v0 := list[3 * tri];
-        v1 := list[3 * tri + 1];
-        v2 := list[3 * tri + 2];
-      end;
-    momTriangleStrip:
-      begin
-        v0 := list[tri];
-        v1 := list[tri + 1];
-        v2 := list[tri + 2];
-      end;
-    momFaceGroups:
-      begin
-        Count := 0;
-        for i := 0 to FaceGroups.Count - 1 do
-        begin
-          LastCount := Count;
-          fg := TFGVertexIndexList(FaceGroups[i]);
-          Count := Count + fg.TriangleCount;
-          if Count > tri then
-          begin
-            Count := tri - LastCount;
-            case fg.Mode of
-              fgmmTriangles, fgmmFlatTriangles:
-                begin
-                  v0 := list[fg.VertexIndices[3 * Count]];
-                  v1 := list[fg.VertexIndices[3 * Count + 1]];
-                  v2 := list[fg.VertexIndices[3 * Count + 2]];
-                end;
-              fgmmTriangleStrip:
-                begin
-                  v0 := list[fg.VertexIndices[Count]];
-                  v1 := list[fg.VertexIndices[Count + 1]];
-                  v2 := list[fg.VertexIndices[Count + 2]];
-                end;
-              fgmmTriangleFan:
-                begin
-                  v0 := list[fg.VertexIndices[0]];
-                  v1 := list[fg.VertexIndices[Count + 1]];
-                  v2 := list[fg.VertexIndices[Count + 2]];
-                end;
-              fgmmQuads:
-                begin
-                  if Count mod 2 = 0 then
-                  begin
-                    v0 := list[fg.VertexIndices[4 * (Count div 2)]];
-                    v1 := list[fg.VertexIndices[4 * (Count div 2) + 1]];
-                    v2 := list[fg.VertexIndices[4 * (Count div 2) + 2]];
-                  end
-                  else
-                  begin
-                    v0 := list[fg.VertexIndices[4 * (Count div 2)]];
-                    v1 := list[fg.VertexIndices[4 * (Count div 2) + 2]];
-                    v2 := list[fg.VertexIndices[4 * (Count div 2) + 3]];
-                  end;
-                end;
-            else
-              Assert(False);
-            end;
-            Break;
-          end;
-        end;
-
-      end;
-  else
-    Assert(False);
-  end;
-end;
-
-procedure TGLMeshObject.SetTriangleData(tri: Integer; list: TGLAffineVectorList; const v0, v1, v2: TAffineVector);
-var
-  i, LastCount, Count: Integer;
-  fg: TFGVertexIndexList;
-begin
-  case Mode of
-    momTriangles:
-      begin
-        list[3 * tri] := v0;
-        list[3 * tri + 1] := v1;
-        list[3 * tri + 2] := v2;
-      end;
-    momTriangleStrip:
-      begin
-        list[tri] := v0;
-        list[tri + 1] := v1;
-        list[tri + 2] := v2;
-      end;
-    momFaceGroups:
-      begin
-        Count := 0;
-        for i := 0 to FaceGroups.Count - 1 do
-        begin
-          LastCount := Count;
-          fg := TFGVertexIndexList(FaceGroups[i]);
-          Count := Count + fg.TriangleCount;
-          if Count > tri then
-          begin
-            Count := tri - LastCount;
-            case fg.Mode of
-              fgmmTriangles, fgmmFlatTriangles:
-                begin
-                  list[fg.VertexIndices[3 * Count]] := v0;
-                  list[fg.VertexIndices[3 * Count + 1]] := v1;
-                  list[fg.VertexIndices[3 * Count + 2]] := v2;
-                end;
-              fgmmTriangleStrip:
-                begin
-                  list[fg.VertexIndices[Count]] := v0;
-                  list[fg.VertexIndices[Count + 1]] := v1;
-                  list[fg.VertexIndices[Count + 2]] := v2;
-                end;
-              fgmmTriangleFan:
-                begin
-                  list[fg.VertexIndices[0]] := v0;
-                  list[fg.VertexIndices[Count + 1]] := v1;
-                  list[fg.VertexIndices[Count + 2]] := v2;
-                end;
-              fgmmQuads:
-                begin
-                  if Count mod 2 = 0 then
-                  begin
-                    list[fg.VertexIndices[4 * (Count div 2)]] := v0;
-                    list[fg.VertexIndices[4 * (Count div 2) + 1]] := v1;
-                    list[fg.VertexIndices[4 * (Count div 2) + 2]] := v2;
-                  end
-                  else
-                  begin
-                    list[fg.VertexIndices[4 * (Count div 2)]] := v0;
-                    list[fg.VertexIndices[4 * (Count div 2) + 2]] := v1;
-                    list[fg.VertexIndices[4 * (Count div 2) + 3]] := v2;
-                  end;
-                end;
-            else
-              Assert(False);
-            end;
-            Break;
-          end;
-        end;
-
-      end;
-  else
-    Assert(False);
-  end;
-end;
-
-procedure TGLMeshObject.SetTriangleData(tri: Integer; list: TGLVectorList; const v0, v1, v2: TGLVector);
-var
-  i, LastCount, Count: Integer;
-  fg: TFGVertexIndexList;
-begin
-  case Mode of
-    momTriangles:
-      begin
-        list[3 * tri] := v0;
-        list[3 * tri + 1] := v1;
-        list[3 * tri + 2] := v2;
-      end;
-    momTriangleStrip:
-      begin
-        list[tri] := v0;
-        list[tri + 1] := v1;
-        list[tri + 2] := v2;
-      end;
-    momFaceGroups:
-      begin
-        Count := 0;
-        for i := 0 to FaceGroups.Count - 1 do
-        begin
-          LastCount := Count;
-          fg := TFGVertexIndexList(FaceGroups[i]);
-          Count := Count + fg.TriangleCount;
-          if Count > tri then
-          begin
-            Count := tri - LastCount;
-            case fg.Mode of
-              fgmmTriangles, fgmmFlatTriangles:
-                begin
-                  list[fg.VertexIndices[3 * Count]] := v0;
-                  list[fg.VertexIndices[3 * Count + 1]] := v1;
-                  list[fg.VertexIndices[3 * Count + 2]] := v2;
-                end;
-              fgmmTriangleStrip:
-                begin
-                  list[fg.VertexIndices[Count]] := v0;
-                  list[fg.VertexIndices[Count + 1]] := v1;
-                  list[fg.VertexIndices[Count + 2]] := v2;
-                end;
-              fgmmTriangleFan:
-                begin
-                  list[fg.VertexIndices[0]] := v0;
-                  list[fg.VertexIndices[Count + 1]] := v1;
-                  list[fg.VertexIndices[Count + 2]] := v2;
-                end;
-              fgmmQuads:
-                begin
-                  if Count mod 2 = 0 then
-                  begin
-                    list[fg.VertexIndices[4 * (Count div 2)]] := v0;
-                    list[fg.VertexIndices[4 * (Count div 2) + 1]] := v1;
-                    list[fg.VertexIndices[4 * (Count div 2) + 2]] := v2;
-                  end
-                  else
-                  begin
-                    list[fg.VertexIndices[4 * (Count div 2)]] := v0;
-                    list[fg.VertexIndices[4 * (Count div 2) + 2]] := v1;
-                    list[fg.VertexIndices[4 * (Count div 2) + 3]] := v2;
-                  end;
-                end;
-            else
-              Assert(False);
-            end;
-            Break;
-          end;
-        end;
-
-      end;
-  else
-    Assert(False);
-  end;
-end;
-
-procedure TGLMeshObject.SetUseVBO(const Value: Boolean);
-var
-  i: Integer;
-begin
-  if Value = FUseVBO then
-    Exit;
-
-  if FUseVBO then
-  begin
-    FreeAndNil(FVerticesVBO);
-    FreeAndNil(FNormalsVBO);
-    FreeAndNil(FColorsVBO);
-    for i := 0 to high(FTexCoordsVBO) do
-      FreeAndNil(FTexCoordsVBO[i]);
-    FreeAndNil(FLightmapTexCoordsVBO);
-  end;
-
-  FValidBuffers := [];
-
-  FUseVBO := Value;
-end;
-
-procedure TGLMeshObject.SetValidBuffers(Value: TGLVBOBuffers);
-var
-  I: Integer;
-begin
-  if FValidBuffers <> Value then
-  begin
-    FValidBuffers := Value;
-    if Assigned(FVerticesVBO) then
-      FVerticesVBO.NotifyChangesOfData;
-    if Assigned(FNormalsVBO) then
-      FNormalsVBO.NotifyChangesOfData;
-    if Assigned(FColorsVBO) then
-      FColorsVBO.NotifyChangesOfData;
-    for I := 0 to high(FTexCoordsVBO) do
-      if Assigned(FTexCoordsVBO[I]) then
-        FTexCoordsVBO[I].NotifyChangesOfData;
-    if Assigned(FLightmapTexCoordsVBO) then
-      FLightmapTexCoordsVBO.NotifyChangesOfData;
-  end;
-end;
-
-procedure TGLMeshObject.BuildTangentSpace(buildBinormals: Boolean = True; buildTangents: Boolean = True);
-var
-  i, j: Integer;
-  v, n, t: array [0 .. 2] of TAffineVector;
-  tangent, binormal: array [0 .. 2] of TGLVector;
-  vt, tt: TAffineVector;
-  interp, dot: Single;
-
-  procedure SortVertexData(sortidx: Integer);
-  begin
-    if t[0].V[sortidx] < t[1].V[sortidx] then
-    begin
-      vt := v[0];
-      tt := t[0];
-      v[0] := v[1];
-      t[0] := t[1];
-      v[1] := vt;
-      t[1] := tt;
-    end;
-    if t[0].V[sortidx] < t[2].V[sortidx] then
-    begin
-      vt := v[0];
-      tt := t[0];
-      v[0] := v[2];
-      t[0] := t[2];
-      v[2] := vt;
-      t[2] := tt;
-    end;
-    if t[1].V[sortidx] < t[2].V[sortidx] then
-    begin
-      vt := v[1];
-      tt := t[1];
-      v[1] := v[2];
-      t[1] := t[2];
-      v[2] := vt;
-      t[2] := tt;
-    end;
-  end;
-
-begin
-  Tangents.Clear;
-  Binormals.Clear;
-  if buildTangents then
-    Tangents.Count := Vertices.Count;
-  if buildBinormals then
-    Binormals.Count := Vertices.Count;
-  for i := 0 to TriangleCount - 1 do
-  begin
-    // Get triangle data
-    GetTriangleData(i, Vertices, v[0], v[1], v[2]);
-    GetTriangleData(i, Normals, n[0], n[1], n[2]);
-    GetTriangleData(i, TexCoords, t[0], t[1], t[2]);
-
-    for j := 0 to 2 do
-    begin
-      // Compute tangent
-      if buildTangents then
-      begin
-        SortVertexData(1);
-
-        if (t[2].Y - t[0].Y) = 0 then
-          interp := 1
-        else
-          interp := (t[1].Y - t[0].Y) / (t[2].Y - t[0].Y);
-
-        vt := VectorLerp(v[0], v[2], interp);
-        interp := t[0].X + (t[2].X - t[0].X) * interp;
-        vt := VectorSubtract(vt, v[1]);
-        if t[1].X < interp then
-          vt := VectorNegate(vt);
-        dot := VectorDotProduct(vt, n[j]);
-        vt.X := vt.X - n[j].X * dot;
-        vt.Y := vt.Y - n[j].Y * dot;
-        vt.Z := vt.Z - n[j].Z * dot;
-        tangent[j] := VectorMake(VectorNormalize(vt), 0);
-      end;
-
-      // Compute Bi-Normal
-      if buildBinormals then
-      begin
-        SortVertexData(0);
-
-        if (t[2].X - t[0].X) = 0 then
-          interp := 1
-        else
-          interp := (t[1].X - t[0].X) / (t[2].X - t[0].X);
-
-        vt := VectorLerp(v[0], v[2], interp);
-        interp := t[0].Y + (t[2].Y - t[0].Y) * interp;
-        vt := VectorSubtract(vt, v[1]);
-        if t[1].Y < interp then
-          vt := VectorNegate(vt);
-        dot := VectorDotProduct(vt, n[j]);
-        vt.X := vt.X - n[j].X * dot;
-        vt.Y := vt.Y - n[j].Y * dot;
-        vt.Z := vt.Z - n[j].Z * dot;
-        binormal[j] := VectorMake(VectorNormalize(vt), 0);
-      end;
-    end;
-
-    if buildTangents then
-      SetTriangleData(i, Tangents, tangent[0], tangent[1], tangent[2]);
-    if buildBinormals then
-      SetTriangleData(i, Binormals, binormal[0], binormal[1], binormal[2]);
-  end;
-end;
-
-procedure TGLMeshObject.DeclareArraysToOpenGL(var mrci: TGLRenderContextInfo; evenIfAlreadyDeclared: Boolean = False);
-var
-  i: Integer;
-  currentMapping: Cardinal;
-  lists: array [0 .. 4] of pointer;
-  tlists: array of pointer;
-begin
-  if evenIfAlreadyDeclared or (not FArraysDeclared) then
-  begin
-    FillChar(lists, SizeOf(lists), 0);
-    SetLength(tlists, FTexCoordsEx.Count);
-
-    // workaround for ATI bug, disable element VBO if
-    // inside a display list
-    FUseVBO := FUseVBO
-      and GL.ARB_vertex_buffer_object
-      and not mrci.GLStates.InsideList;
-
-    if not FUseVBO then
-    begin
-      lists[0] := Vertices.List;
-      lists[1] := Normals.List;
-      lists[2] := Colors.List;
-      lists[3] := TexCoords.List;
-      lists[4] := LightMapTexCoords.List;
-
-      for i := 0 to FTexCoordsEx.Count - 1 do
-        tlists[i] := TexCoordsEx[i].List;
-    end
-    else
-    begin
-      BufferArrays;
-    end;
-
-    if not mrci.ignoreMaterials then
-    begin
-      if Normals.Count > 0 then
-      begin
-        if FUseVBO then
-          FNormalsVBO.Bind;
-        gl.EnableClientState(GL_NORMAL_ARRAY);
-        gl.NormalPointer(GL_FLOAT, 0, lists[1]);
-      end
-      else
-        gl.DisableClientState(GL_NORMAL_ARRAY);
-      if (Colors.Count > 0) and (not mrci.ignoreMaterials) then
-      begin
-        if FUseVBO then
-          FColorsVBO.Bind;
-        gl.EnableClientState(GL_COLOR_ARRAY);
-        gl.ColorPointer(4, GL_FLOAT, 0, lists[2]);
-      end
-      else
-        gl.DisableClientState(GL_COLOR_ARRAY);
-      if TexCoords.Count > 0 then
-      begin
-        if FUseVBO then
-          FTexCoordsVBO[0].Bind;
-        xgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
-        xgl.TexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), lists[3]);
-      end
-      else
-        xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
-      if gl.ARB_multitexture then
-      begin
-        if LightMapTexCoords.Count > 0 then
-        begin
-          if FUseVBO then
-            FLightmapTexCoordsVBO.Bind;
-          gl.ClientActiveTexture(GL_TEXTURE1);
-          gl.TexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), lists[4]);
-          gl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
-        end;
-        for i := 0 to FTexCoordsEx.Count - 1 do
-        begin
-          if TexCoordsEx[i].Count > 0 then
-          begin
-            if FUseVBO then
-              FTexCoordsVBO[i].Bind;
-            gl.ClientActiveTexture(GL_TEXTURE0 + i);
-            gl.TexCoordPointer(4, GL_FLOAT, SizeOf(TGLVector), tlists[i]);
-            gl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
-          end;
-        end;
-        gl.ClientActiveTexture(GL_TEXTURE0);
-      end;
-    end
-    else
-    begin
-      gl.DisableClientState(GL_NORMAL_ARRAY);
-      gl.DisableClientState(GL_COLOR_ARRAY);
-      xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
-    end;
-
-    if Vertices.Count > 0 then
-    begin
-      if FUseVBO then
-        FVerticesVBO.Bind;
-      gl.EnableClientState(GL_VERTEX_ARRAY);
-      gl.VertexPointer(3, GL_FLOAT, 0, lists[0]);
-    end
-    else
-      gl.DisableClientState(GL_VERTEX_ARRAY);
-
-    if gl.EXT_compiled_vertex_array and (LightMapTexCoords.Count = 0) and not FUseVBO then
-      gl.LockArrays(0, Vertices.Count);
-
-    FLastLightMapIndex := -1;
-    FArraysDeclared := True;
-    FLightMapArrayEnabled := False;
-    if mrci.drawState <> dsPicking then
-      FLastXOpenGLTexMapping := xgl.GetBitWiseMapping;
-  end
-  else
-  begin
-    if not mrci.ignoreMaterials and not (mrci.drawState = dsPicking) then
-      if TexCoords.Count > 0 then
-      begin
-        currentMapping := xgl.GetBitWiseMapping;
-        if FLastXOpenGLTexMapping <> currentMapping then
-        begin
-          xgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
-          xgl.TexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), TexCoords.List);
-          FLastXOpenGLTexMapping := currentMapping;
-        end;
-      end;
-  end;
-end;
-
-procedure TGLMeshObject.DisableOpenGLArrays(var mrci: TGLRenderContextInfo);
-var
-  i: Integer;
-begin
-  if FArraysDeclared then
-  begin
-    DisableLightMapArray(mrci);
-    if gl.EXT_compiled_vertex_array and (LightMapTexCoords.Count = 0) and not FUseVBO then
-      gl.UnLockArrays;
-    if Vertices.Count > 0 then
-      gl.DisableClientState(GL_VERTEX_ARRAY);
-    if not mrci.ignoreMaterials then
-    begin
-      if Normals.Count > 0 then
-        gl.DisableClientState(GL_NORMAL_ARRAY);
-      if (Colors.Count > 0) and (not mrci.ignoreMaterials) then
-        gl.DisableClientState(GL_COLOR_ARRAY);
-      if TexCoords.Count > 0 then
-        xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
-      if gl.ARB_multitexture then
-      begin
-        if LightMapTexCoords.Count > 0 then
-        begin
-          gl.ClientActiveTexture(GL_TEXTURE1);
-          gl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
-        end;
-        for i := 0 to FTexCoordsEx.Count - 1 do
-        begin
-          if TexCoordsEx[i].Count > 0 then
-          begin
-            gl.ClientActiveTexture(GL_TEXTURE0 + i);
-            gl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
-          end;
-        end;
-        gl.ClientActiveTexture(GL_TEXTURE0);
-      end;
-    end;
-
-    if FUseVBO then
-    begin
-      if Vertices.Count > 0 then
-        FVerticesVBO.UnBind;
-      if Normals.Count > 0 then
-        FNormalsVBO.UnBind;
-      if Colors.Count > 0 then
-        FColorsVBO.UnBind;
-      if TexCoords.Count > 0 then
-        FTexCoordsVBO[0].UnBind;
-      if LightMapTexCoords.Count > 0 then
-        FLightmapTexCoordsVBO.UnBind;
-      if FTexCoordsEx.Count > 0 then
-      begin
-        for i := 0 to FTexCoordsEx.Count - 1 do
-        begin
-          if TexCoordsEx[i].Count > 0 then
-            FTexCoordsVBO[i].UnBind;
-        end;
-      end;
-    end;
-    FArraysDeclared := False;
-  end;
-end;
-
-procedure TGLMeshObject.EnableLightMapArray(var mrci: TGLRenderContextInfo);
-begin
-  if GL.ARB_multitexture and (not mrci.ignoreMaterials) then
-  begin
-    Assert(FArraysDeclared);
-    if not FLightMapArrayEnabled then
-    begin
-      mrci.GLStates.ActiveTexture := 1;
-      mrci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
-      mrci.GLStates.ActiveTexture := 0;
-      FLightMapArrayEnabled := True;
-    end;
-  end;
-end;
-
-procedure TGLMeshObject.DisableLightMapArray(var mrci: TGLRenderContextInfo);
-begin
-  if GL.ARB_multitexture and FLightMapArrayEnabled then
-  begin
-    mrci.GLStates.ActiveTexture := 1;
-    mrci.GLStates.ActiveTextureEnabled[ttTexture2D] := False;
-    mrci.GLStates.ActiveTexture := 0;
-    FLightMapArrayEnabled := False;
-  end;
-end;
-
-procedure TGLMeshObject.PrepareBuildList(var mrci: TGLRenderContextInfo);
-var
-  i: Integer;
-begin
-  if (Mode = momFaceGroups) and Assigned(mrci.materialLibrary) then
-  begin
-    for i := 0 to FaceGroups.Count - 1 do
-      with TGLFaceGroup(FaceGroups.List^[i]) do
-      begin
-        if MaterialCache <> nil then
-          MaterialCache.PrepareBuildList;
-      end;
-  end;
-end;
-
-procedure TGLMeshObject.BufferArrays;
-const
-  BufferUsage = GL_DYNAMIC_DRAW;
-var
-  I: integer;
-begin
-  if Vertices.Count > 0 then
-  begin
-    if not Assigned(FVerticesVBO) then
-      FVerticesVBO := TGLVBOArrayBufferHandle.Create;
-    FVerticesVBO.AllocateHandle;
-
-    if FVerticesVBO.IsDataNeedUpdate then
-    begin
-      FVerticesVBO.BindBufferData(Vertices.List, SizeOf(TAffineVector) * Vertices.Count, BufferUsage);
-      FVerticesVBO.NotifyDataUpdated;
-      FVerticesVBO.UnBind;
-    end;
-    Include(FValidBuffers, vbVertices);
-  end;
-
-  if Normals.Count > 0 then
-  begin
-    if not Assigned(FNormalsVBO) then
-      FNormalsVBO := TGLVBOArrayBufferHandle.Create;
-    FNormalsVBO.AllocateHandle;
-
-    if FNormalsVBO.IsDataNeedUpdate then
-    begin
-      FNormalsVBO.BindBufferData(Normals.List, SizeOf(TAffineVector) * Normals.Count, BufferUsage);
-      FNormalsVBO.NotifyDataUpdated;
-      FNormalsVBO.UnBind;
-    end;
-
-    Include(FValidBuffers, vbNormals);
-  end;
-
-  if Colors.Count > 0 then
-  begin
-    if not Assigned(FColorsVBO) then
-      FColorsVBO := TGLVBOArrayBufferHandle.Create;
-    FColorsVBO.AllocateHandle;
-
-    if FColorsVBO.IsDataNeedUpdate then
-    begin
-      FColorsVBO.BindBufferData(Colors.list, SizeOf(TGLVector) * Colors.Count, BufferUsage);
-      FColorsVBO.NotifyDataUpdated;
-      FColorsVBO.UnBind;
-    end;
-
-    Include(FValidBuffers, vbColors);
-  end;
-
-  if TexCoords.Count > 0 then
-  begin
-    if Length(FTexCoordsVBO) < 1 then
-      SetLength(FTexCoordsVBO, 1);
-
-    if not Assigned(FTexCoordsVBO[0]) then
-      FTexCoordsVBO[0] := TGLVBOArrayBufferHandle.Create;
-    FTexCoordsVBO[0].AllocateHandle;
-
-    if FTexCoordsVBO[0].IsDataNeedUpdate then
-    begin
-      FTexCoordsVBO[0].BindBufferData(texCoords.list, SizeOf(TAffineVector) * texCoords.Count, BufferUsage);
-      FTexCoordsVBO[0].NotifyDataUpdated;
-      FTexCoordsVBO[0].UnBind;
-    end;
-
-    Include(FValidBuffers, vbTexCoords);
-  end;
-
-  if LightMapTexCoords.Count > 0 then
-  begin
-    if not Assigned(FLightmapTexCoordsVBO) then
-      FLightmapTexCoordsVBO := TGLVBOArrayBufferHandle.Create;
-    FLightmapTexCoordsVBO.AllocateHandle;
-
-    FLightmapTexCoordsVBO.BindBufferData(LightMapTexCoords.list, SizeOf(TAffineVector) * LightMapTexCoords.Count, BufferUsage);
-    FLightmapTexCoordsVBO.NotifyDataUpdated;
-    FLightmapTexCoordsVBO.UnBind;
-
-    Include(FValidBuffers, vbLightMapTexCoords);
-  end;
-
-  if FTexCoordsEx.Count > 0 then
-  begin
-    if Length(FTexCoordsVBO) < FTexCoordsEx.Count then
-      SetLength(FTexCoordsVBO, FTexCoordsEx.Count);
-
-    for I := 0 to FTexCoordsEx.Count - 1 do
-    begin
-      if TexCoordsEx[i].Count <= 0 then
-        continue;
-
-      if not Assigned(FTexCoordsVBO[i]) then
-        FTexCoordsVBO[i] := TGLVBOArrayBufferHandle.Create;
-      FTexCoordsVBO[i].AllocateHandle;
-
-      if FTexCoordsVBO[i].IsDataNeedUpdate then
-      begin
-        FTexCoordsVBO[i].BindBufferData(TexCoordsEx[i].list, SizeOf(TGLVector) * TexCoordsEx[i].Count, BufferUsage);
-        FTexCoordsVBO[i].NotifyDataUpdated;
-        FTexCoordsVBO[i].UnBind;
-      end;
-    end;
-
-    Include(FValidBuffers, vbTexCoordsEx);
-  end;
-  gl.CheckError;
-end;
-
-procedure TGLMeshObject.BuildList(var mrci: TGLRenderContextInfo);
-var
-  i, j, groupID, nbGroups: Integer;
-  gotNormals, gotTexCoords, gotColor: Boolean;
-  gotTexCoordsEx: array of Boolean;
-  libMat: TGLLibMaterial;
-  fg: TGLFaceGroup;
-begin
-  // Make sure no VBO is bound and states enabled
-  FArraysDeclared := False;
-  FLastXOpenGLTexMapping := 0;
-  gotColor := (Vertices.Count = Colors.Count);
-  if gotColor then
-  begin
-    mrci.GLStates.Enable(stColorMaterial);
-    gl.ColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
-    mrci.GLStates.SetGLMaterialColors(cmFront, clrBlack, clrGray20, clrGray80, clrBlack, 0);
-    mrci.GLStates.SetGLMaterialColors(cmBack, clrBlack, clrGray20, clrGray80, clrBlack, 0);
-  end;
-  case Mode of
-    momTriangles, momTriangleStrip:
-	if Vertices.Count > 0 then
-      begin
-        DeclareArraysToOpenGL(mrci);
-        gotNormals := (Vertices.Count = Normals.Count);
-        gotTexCoords := (Vertices.Count = TexCoords.Count);
-        SetLength(gotTexCoordsEx, FTexCoordsEx.Count);
-        for i := 0 to FTexCoordsEx.Count - 1 do
-          gotTexCoordsEx[i] := (TexCoordsEx[i].Count > 0) and GL.ARB_multitexture;
-        if Mode = momTriangles then
-          gl.Begin_(GL_TRIANGLES)
-        else
-          gl.Begin_(GL_TRIANGLE_STRIP);
-        for i := 0 to Vertices.Count - 1 do
-        begin
-          if gotNormals then
-            gl.Normal3fv(@Normals.List[i]);
-          if gotColor then
-            gl.Color4fv(@Colors.List[i]);
-          if FTexCoordsEx.Count > 0 then
-          begin
-            if gotTexCoordsEx[0] then
-              gl.MultiTexCoord4fv(GL_TEXTURE0, @TexCoordsEx[0].List[i])
-            else if gotTexCoords then
-              xgl.TexCoord2fv(@TexCoords.List[i]);
-            for j := 1 to FTexCoordsEx.Count - 1 do
-              if gotTexCoordsEx[j] then
-                gl.MultiTexCoord4fv(GL_TEXTURE0 + j, @TexCoordsEx[j].list[i]);
-          end
-          else
-          begin
-            if gotTexCoords then
-              xgl.TexCoord2fv(@TexCoords.List[i]);
-          end;
-          gl.Vertex3fv(@Vertices.List[i]);
-        end;
-        gl.End_;
-      end;
-    momFaceGroups:
-      begin
-        if Assigned(mrci.materialLibrary) then
-        begin
-          if moroGroupByMaterial in RenderingOptions then
-          begin
-            // group-by-material rendering, reduces material switches,
-            // but alters rendering order
-            groupID := vNextRenderGroupID;
-            Inc(vNextRenderGroupID);
-            for i := 0 to FaceGroups.Count - 1 do
-            begin
-              if FaceGroups[i].FRenderGroupID <> groupID then
-              begin
-                libMat := FaceGroups[i].FMaterialCache;
-                if Assigned(libMat) then
-                  libMat.Apply(mrci);
-                repeat
-                  for j := i to FaceGroups.Count - 1 do
-                    with FaceGroups[j] do
-                    begin
-                      if (FRenderGroupID <> groupID) and (FMaterialCache = libMat) then
-                      begin
-                        FRenderGroupID := groupID;
-                        BuildList(mrci);
-                      end;
-                    end;
-                until (not Assigned(libMat)) or (not libMat.UnApply(mrci));
-              end;
-            end;
-          end
-          else
-          begin
-            // canonical rendering (regroups only contiguous facegroups)
-            i := 0;
-            nbGroups := FaceGroups.Count;
-            while i < nbGroups do
-            begin
-              libMat := FaceGroups[i].FMaterialCache;
-              if Assigned(libMat) then
-              begin
-                libMat.Apply(mrci);
-                repeat
-                  j := i;
-                  while j < nbGroups do
-                  begin
-                    fg := FaceGroups[j];
-                    if fg.MaterialCache <> libMat then
-                      Break;
-                    fg.BuildList(mrci);
-                    Inc(j);
-                  end;
-                until not libMat.UnApply(mrci);
-                i := j;
-              end
-              else
-              begin
-                FaceGroups[i].BuildList(mrci);
-                Inc(i);
-              end;
-            end;
-          end;
-          // restore faceculling
-          if (stCullFace in mrci.GLStates.States) then
-          begin
-            if not mrci.bufferFaceCull then
-              mrci.GLStates.Disable(stCullFace);
-          end
-          else
-          begin
-            if mrci.bufferFaceCull then
-              mrci.GLStates.Enable(stCullFace);
-          end;
-        end
-        else
-          for i := 0 to FaceGroups.Count - 1 do
-            FaceGroups[i].BuildList(mrci);
-      end;
-  else
-    Assert(False);
-  end;
-  DisableOpenGLArrays(mrci);
-end;
-
-// ------------------
-// ------------------ TGLMeshObjectList ------------------
-// ------------------
-
-constructor TGLMeshObjectList.CreateOwned(aOwner: TGLBaseMesh);
-begin
-  FOwner := AOwner;
-  Create;
-end;
-
-destructor TGLMeshObjectList.Destroy;
-begin
-  Clear;
-  inherited;
-end;
-
-procedure TGLMeshObjectList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  i: Integer;
-  mesh: TGLMeshObject;
-begin
-  inherited;
-  for i := 0 to Count - 1 do
-  begin
-    mesh := Items[i];
-    mesh.FOwner := Self;
-    if mesh is TGLSkeletonMeshObject then
-      TGLSkeletonMeshObject(mesh).PrepareBoneMatrixInvertedMeshes;
-  end;
-end;
-
-procedure TGLMeshObjectList.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    TGLMeshObject(List^[i]).PrepareMaterialLibraryCache(matLib);
-end;
-
-procedure TGLMeshObjectList.DropMaterialLibraryCache;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    TGLMeshObject(List^[i]).DropMaterialLibraryCache;
-end;
-
-procedure TGLMeshObjectList.PrepareBuildList(var mrci: TGLRenderContextInfo);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    with Items[i] do
-      if Visible then
-        PrepareBuildList(mrci);
-end;
-
-procedure TGLMeshObjectList.BuildList(var mrci: TGLRenderContextInfo);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    with Items[i] do
-      if Visible then
-        BuildList(mrci);
-end;
-
-procedure TGLMeshObjectList.MorphTo(morphTargetIndex: Integer);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    if Items[i] is TGLMorphableMeshObject then
-      TGLMorphableMeshObject(Items[i]).MorphTo(morphTargetIndex);
-end;
-
-procedure TGLMeshObjectList.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    if Items[i] is TGLMorphableMeshObject then
-      TGLMorphableMeshObject(Items[i]).Lerp(morphTargetIndex1, morphTargetIndex2, lerpFactor);
-end;
-
-function TGLMeshObjectList.MorphTargetCount: Integer;
-var
-  i: Integer;
-begin
-  Result := MaxInt;
-  for i := 0 to Count - 1 do
-    if Items[i] is TGLMorphableMeshObject then
-      with TGLMorphableMeshObject(Items[i]) do
-        if Result > MorphTargets.Count then
-          Result := MorphTargets.Count;
-  if Result = MaxInt then
-    Result := 0;
-end;
-
-procedure TGLMeshObjectList.Clear;
-var
-  i: Integer;
-begin
-  DropMaterialLibraryCache;
-  for i := 0 to Count - 1 do
-    with Items[i] do
-    begin
-      FOwner := nil;
-      Free;
-    end;
-  inherited;
-end;
-
-function TGLMeshObjectList.GetMeshObject(Index: Integer): TGLMeshObject;
-begin
-  Result := TGLMeshObject(List^[Index]);
-end;
-
-procedure TGLMeshObjectList.GetExtents(out min, max: TAffineVector);
-var
-  i, k: Integer;
-  lMin, lMax: TAffineVector;
-const
-  cBigValue: Single = 1E30;
-  cSmallValue: Single = -1E30;
-begin
-  SetVector(min, cBigValue, cBigValue, cBigValue);
-  SetVector(max, cSmallValue, cSmallValue, cSmallValue);
-  for i := 0 to Count - 1 do
-  begin
-    GetMeshObject(i).GetExtents(lMin, lMax);
-    for k := 0 to 2 do
-    begin
-      if lMin.V[k] < min.V[k] then
-        min.V[k] := lMin.V[k];
-      if lMax.V[k] > max.V[k] then
-        max.V[k] := lMax.V[k];
-    end;
-  end;
-end;
-
-procedure TGLMeshObjectList.Translate(const delta: TAffineVector);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    GetMeshObject(i).Translate(delta);
-end;
-
-function TGLMeshObjectList.ExtractTriangles(texCoords: TGLAffineVectorList = nil;
-  normals: TGLAffineVectorList = nil): TGLAffineVectorList;
-var
-  i: Integer;
-  obj: TGLMeshObject;
-  objTris: TGLAffineVectorList;
-  objTexCoords: TGLAffineVectorList;
-  objNormals: TGLAffineVectorList;
-begin
-  Result := TGLAffineVectorList.Create;
-  Result.AdjustCapacityToAtLeast(Self.TriangleCount * 3);
-  if Assigned(texCoords) then
-    objTexCoords := TGLAffineVectorList.Create
-  else
-    objTexCoords := nil;
-  if Assigned(normals) then
-    objNormals := TGLAffineVectorList.Create
-  else
-    objNormals := nil;
-  try
-    for i := 0 to Count - 1 do
-    begin
-      obj := GetMeshObject(i);
-      if not obj.Visible then
-        continue;
-      objTris := obj.ExtractTriangles(objTexCoords, objNormals);
-      try
-        Result.Add(objTris);
-        if Assigned(texCoords) then
-        begin
-          texCoords.Add(objTexCoords);
-          objTexCoords.Count := 0;
-        end;
-        if Assigned(normals) then
-        begin
-          normals.Add(objNormals);
-          objNormals.Count := 0;
-        end;
-      finally
-        objTris.Free;
-      end;
-    end;
-  finally
-    objTexCoords.Free;
-    objNormals.Free;
-  end;
-end;
-
-function TGLMeshObjectList.TriangleCount: Integer;
-var
-  i: Integer;
-begin
-  Result := 0;
-  for i := 0 to Count - 1 do
-    Result := Result + Items[i].TriangleCount;
-end;
-
-function TGLMeshObjectList.Area: Single;
-var
-  i: Integer;
-  Tri: TFaceRec;
-  List: TGLAffineVectorList;
-
-begin
-  Result := 0;
-  List := Self.ExtractTriangles;
-  if List.Count > 0 then
-  try
-    i := 0;
-    while i < List.Count do
-    begin
-      Tri.Normal := CalcPlaneNormal(List[i], List[i+1], List[i+2]);
-      Tri.V1 := VectorTransform(List[i], TGLBaseSceneObject(Owner).AbsoluteMatrix);
-      Tri.V2 := VectorTransform(List[i+1], TGLBaseSceneObject(Owner).AbsoluteMatrix);
-      Tri.V3 := VectorTransform(List[i+2], TGLBaseSceneObject(Owner).AbsoluteMatrix);
-      Inc(i, 3);
-      Result := Result + TriangleArea(Tri.V1, Tri.V2, Tri.V3);
-    end;
-  finally
-    List.Free();
-  end;
-end;
-
-function TGLMeshObjectList.Volume: Single;
-var
-  i: Integer;
-  Tri: TFaceRec;
-  List: TGLAffineVectorList;
-
-begin
-  Result := 0;
-  List := Self.ExtractTriangles;
-  if List.Count > 0 then
-  try
-    i := 0;
-    while i < List.Count do
-    begin
-      Tri.Normal := CalcPlaneNormal(List[i], List[i+1], List[i+2]);
-      Tri.V1 := VectorTransform(List[i], TGLBaseSceneObject(Owner).AbsoluteMatrix);
-      Tri.V2 := VectorTransform(List[i+1], TGLBaseSceneObject(Owner).AbsoluteMatrix);
-      Tri.V3 := VectorTransform(List[i+2], TGLBaseSceneObject(Owner).AbsoluteMatrix);
-      Inc(i, 3);
-      Result := Result + VectorDotProduct(Tri.V1, VectorCrossProduct(Tri.V2, Tri.V3));
-    end;
-    Result := Result / 6;
-  finally
-    List.Free();
-  end;
-end;
-
-procedure TGLMeshObjectList.Prepare;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    Items[i].Prepare;
-end;
-
-function TGLMeshObjectList.FindMeshByName(const MeshName: string): TGLMeshObject;
-var
-  i: Integer;
-begin
-  Result := nil;
-  for i := 0 to Count - 1 do
-    if Items[i].Name = MeshName then
-    begin
-      Result := Items[i];
-      Break;
-    end;
-end;
-
-procedure TGLMeshObjectList.BuildTangentSpace(buildBinormals, buildTangents: Boolean);
-var
-  I: Integer;
-begin
-  if Count <> 0 then
-    for I := 0 to Count - 1 do
-      GetMeshObject(I).BuildTangentSpace(buildBinormals, buildTangents);
-end;
-
-function TGLMeshObjectList.GetUseVBO: Boolean;
-var
-  I: Integer;
-begin
-  Result := True;
-  if Count <> 0 then
-    for I := 0 to Count - 1 do
-      Result := Result and GetMeshObject(I).FUseVBO;
-end;
-
-procedure TGLMeshObjectList.SetUseVBO(const Value: Boolean);
-var
-  I: Integer;
-begin
-  if Count <> 0 then
-    for I := 0 to Count - 1 do
-      GetMeshObject(I).SetUseVBO(Value);
-end;
-
-// ------------------
-// ------------------ TGLMeshMorphTarget ------------------
-// ------------------
-
-constructor TGLMeshMorphTarget.CreateOwned(AOwner: TGLMeshMorphTargetList);
-begin
-  FOwner := AOwner;
-  Create;
-  if Assigned(FOwner) then
-    FOwner.Add(Self);
-end;
-
-destructor TGLMeshMorphTarget.Destroy;
-begin
-  if Assigned(FOwner) then
-    FOwner.Remove(Self);
-  inherited;
-end;
-
-procedure TGLMeshMorphTarget.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    // nothing
-  end;
-end;
-
-procedure TGLMeshMorphTarget.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      // nothing
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-// ------------------
-// ------------------ TGLMeshMorphTargetList ------------------
-// ------------------
-
-constructor TGLMeshMorphTargetList.CreateOwned(aOwner: TPersistent);
-begin
-  FOwner := AOwner;
-  Create;
-end;
-
-destructor TGLMeshMorphTargetList.Destroy;
-begin
-  Clear;
-  inherited;
-end;
-
-procedure TGLMeshMorphTargetList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  i: Integer;
-begin
-  inherited;
-  for i := 0 to Count - 1 do
-    Items[i].FOwner := Self;
-end;
-
-procedure TGLMeshMorphTargetList.Translate(const delta: TAffineVector);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    Items[i].Translate(delta);
-end;
-
-procedure TGLMeshMorphTargetList.Clear;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    with Items[i] do
-    begin
-      FOwner := nil;
-      Free;
-    end;
-  inherited;
-end;
-
-function TGLMeshMorphTargetList.GeTGLMeshMorphTarget(Index: Integer): TGLMeshMorphTarget;
-begin
-  Result := TGLMeshMorphTarget(List^[Index]);
-end;
-
-// ------------------
-// ------------------ TGLMorphableMeshObject ------------------
-// ------------------
-
-constructor TGLMorphableMeshObject.Create;
-begin
-  inherited;
-  FMorphTargets := TGLMeshMorphTargetList.CreateOwned(Self);
-end;
-
-destructor TGLMorphableMeshObject.Destroy;
-begin
-  FMorphTargets.Free;
-  inherited;
-end;
-
-procedure TGLMorphableMeshObject.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    FMorphTargets.WriteToFiler(writer);
-  end;
-end;
-
-procedure TGLMorphableMeshObject.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      FMorphTargets.ReadFromFiler(reader);
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TGLMorphableMeshObject.Clear;
-begin
-  inherited;
-  FMorphTargets.Clear;
-end;
-
-procedure TGLMorphableMeshObject.Translate(const delta: TAffineVector);
-begin
-  inherited;
-  MorphTargets.Translate(delta);
-  ValidBuffers := ValidBuffers - [vbVertices];
-end;
-
-procedure TGLMorphableMeshObject.MorphTo(morphTargetIndex: Integer);
-begin
-  if (morphTargetIndex = 0) and (MorphTargets.Count = 0) then
-    Exit;
-  Assert(Cardinal(morphTargetIndex) < Cardinal(MorphTargets.Count));
-  with MorphTargets[morphTargetIndex] do
-  begin
-    if Vertices.Count > 0 then
-    begin
-      Self.Vertices.Assign(Vertices);
-      ValidBuffers := ValidBuffers - [vbVertices];
-    end;
-    if Normals.Count > 0 then
-    begin
-      Self.Normals.Assign(Normals);
-      ValidBuffers := ValidBuffers - [vbNormals];
-    end;
-  end;
-end;
-
-procedure TGLMorphableMeshObject.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
-var
-  mt1, mt2: TGLMeshMorphTarget;
-begin
-  Assert((Cardinal(morphTargetIndex1) < Cardinal(MorphTargets.Count)) and
-    (Cardinal(morphTargetIndex2) < Cardinal(MorphTargets.Count)));
-  if lerpFactor = 0 then
-    MorphTo(morphTargetIndex1)
-  else if lerpFactor = 1 then
-    MorphTo(morphTargetIndex2)
-  else
-  begin
-    mt1 := MorphTargets[morphTargetIndex1];
-    mt2 := MorphTargets[morphTargetIndex2];
-    if mt1.Vertices.Count > 0 then
-    begin
-      Vertices.Lerp(mt1.Vertices, mt2.Vertices, lerpFactor);
-      ValidBuffers := ValidBuffers - [vbVertices];
-    end;
-    if mt1.Normals.Count > 0 then
-    begin
-      Normals.Lerp(mt1.Normals, mt2.Normals, lerpFactor);
-      Normals.Normalize;
-      ValidBuffers := ValidBuffers - [vbNormals];
-    end;
-  end;
-end;
-
-// ------------------
-// ------------------ TGLSkeletonMeshObject ------------------
-// ------------------
-
-constructor TGLSkeletonMeshObject.Create;
-begin
-  FBoneMatrixInvertedMeshes := TList.Create;
-  FBackupInvertedMeshes := TList.Create; // ragdoll
-  inherited Create;
-end;
-
-destructor TGLSkeletonMeshObject.Destroy;
-begin
-  Clear;
-  FBoneMatrixInvertedMeshes.Free;
-  FBackupInvertedMeshes.Free;
-  inherited Destroy;
-end;
-
-procedure TGLSkeletonMeshObject.WriteToFiler(writer: TGLVirtualWriter);
-var
-  i: Integer;
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    WriteInteger(FVerticeBoneWeightCount);
-    WriteInteger(FBonesPerVertex);
-    WriteInteger(FVerticeBoneWeightCapacity);
-    for i := 0 to FVerticeBoneWeightCount - 1 do
-      Write(FVerticesBonesWeights[i][0], FBonesPerVertex * SizeOf(TGLVertexBoneWeight));
-  end;
-end;
-
-procedure TGLSkeletonMeshObject.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion, i: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      FVerticeBoneWeightCount := ReadInteger;
-      FBonesPerVertex := ReadInteger;
-      FVerticeBoneWeightCapacity := ReadInteger;
-      ResizeVerticesBonesWeights;
-      for i := 0 to FVerticeBoneWeightCount - 1 do
-        Read(FVerticesBonesWeights[i][0], FBonesPerVertex * SizeOf(TGLVertexBoneWeight));
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TGLSkeletonMeshObject.Clear;
-var
-  i: Integer;
-begin
-  inherited;
-  FVerticeBoneWeightCount := 0;
-  FBonesPerVertex := 0;
-  ResizeVerticesBonesWeights;
-  for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
-    TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
-  FBoneMatrixInvertedMeshes.Clear;
-end;
-
-procedure TGLSkeletonMeshObject.SetVerticeBoneWeightCount(const val: Integer);
-begin
-  if val <> FVerticeBoneWeightCount then
-  begin
-    FVerticeBoneWeightCount := val;
-    if FVerticeBoneWeightCount > FVerticeBoneWeightCapacity then
-      VerticeBoneWeightCapacity := FVerticeBoneWeightCount + 16;
-    FLastVerticeBoneWeightCount := FVerticeBoneWeightCount;
-  end;
-end;
-
-procedure TGLSkeletonMeshObject.SetVerticeBoneWeightCapacity(const val: Integer);
-begin
-  if val <> FVerticeBoneWeightCapacity then
-  begin
-    FVerticeBoneWeightCapacity := val;
-    ResizeVerticesBonesWeights;
-  end;
-end;
-
-procedure TGLSkeletonMeshObject.SetBonesPerVertex(const val: Integer);
-begin
-  if val <> FBonesPerVertex then
-  begin
-    FBonesPerVertex := val;
-    ResizeVerticesBonesWeights;
-  end;
-end;
-
-procedure TGLSkeletonMeshObject.ResizeVerticesBonesWeights;
-var
-  n, m, i, j: Integer;
-  newArea: PGLVerticesBoneWeights;
-begin
-  n := BonesPerVertex * VerticeBoneWeightCapacity;
-  if n = 0 then
-  begin
-    // release everything
-    if Assigned(FVerticesBonesWeights) then
-    begin
-      FreeMem(FVerticesBonesWeights[0]);
-      FreeMem(FVerticesBonesWeights);
-      FVerticesBonesWeights := nil;
-    end;
-  end
-  else
-  begin
-    // allocate new area
-    GetMem(newArea, VerticeBoneWeightCapacity * SizeOf(PGLVertexBoneWeightArray));
-    newArea[0] := AllocMem(n * SizeOf(TGLVertexBoneWeight));
-    for i := 1 to VerticeBoneWeightCapacity - 1 do
-      newArea[i] := PGLVertexBoneWeightArray(Cardinal(newArea[0]) +
-	    Cardinal(i * SizeOf(TGLVertexBoneWeight) * BonesPerVertex));
-    // transfer old data
-    if FLastVerticeBoneWeightCount < VerticeBoneWeightCount then
-      n := FLastVerticeBoneWeightCount
-    else
-      n := VerticeBoneWeightCount;
-    if FLastBonesPerVertex < BonesPerVertex then
-      m := FLastBonesPerVertex
-    else
-      m := BonesPerVertex;
-    for i := 0 to n - 1 do
-      for j := 0 to m - 1 do
-        newArea[i][j] := VerticesBonesWeights[i][j];
-    // release old area and switch to new
-    if Assigned(FVerticesBonesWeights) then
-    begin
-      FreeMem(FVerticesBonesWeights[0]);
-      FreeMem(FVerticesBonesWeights);
-    end;
-    FVerticesBonesWeights := newArea;
-  end;
-  FLastBonesPerVertex := FBonesPerVertex;
-end;
-
-procedure TGLSkeletonMeshObject.AddWeightedBone(aBoneID: Integer; aWeight: Single);
-begin
-  if BonesPerVertex < 1 then
-    BonesPerVertex := 1;
-  VerticeBoneWeightCount := VerticeBoneWeightCount + 1;
-  with VerticesBonesWeights^[VerticeBoneWeightCount - 1]^[0] do
-  begin
-    BoneID := aBoneID;
-    Weight := aWeight;
-  end;
-end;
-
-procedure TGLSkeletonMeshObject.AddWeightedBones(const boneIDs: TGLVertexBoneWeightDynArray);
-var
-  i: Integer;
-  n: Integer;
-begin
-  n := Length(boneIDs);
-  if BonesPerVertex < n then
-    BonesPerVertex := n;
-  VerticeBoneWeightCount := VerticeBoneWeightCount + 1;
-  for i := 0 to n - 1 do
-  begin
-    with VerticesBonesWeights^[VerticeBoneWeightCount - 1]^[i] do
-    begin
-      BoneID := boneIDs[i].BoneID;
-      Weight := boneIDs[i].Weight;
-    end;
-  end;
-end;
-
-function TGLSkeletonMeshObject.FindOrAdd(BoneID: Integer; const vertex, normal: TAffineVector): Integer;
-var
-  i: Integer;
-  dynArray: TGLVertexBoneWeightDynArray;
-begin
-  if BonesPerVertex > 1 then
-  begin
-    SetLength(dynArray, 1);
-    dynArray[0].BoneID := boneID;
-    dynArray[0].Weight := 1;
-    Result := FindOrAdd(dynArray, vertex, normal);
-    Exit;
-  end;
-  Result := -1;
-  for i := 0 to Vertices.Count - 1 do
-    if (VerticesBonesWeights^[i]^[0].BoneID = BoneID) and VectorEquals(Vertices.List^[i], vertex) and
-	  VectorEquals(Normals.List^[i], normal) then
-    begin
-      Result := i;
-      Break;
-    end;
-  if Result < 0 then
-  begin
-    AddWeightedBone(BoneID, 1);
-    Vertices.Add(vertex);
-    Result := Normals.Add(normal);
-  end;
-end;
-
-function TGLSkeletonMeshObject.FindOrAdd(const boneIDs: TGLVertexBoneWeightDynArray; const vertex,
-  normal: TAffineVector): Integer;
-var
-  i, j: Integer;
-  bonesMatch: Boolean;
-begin
-  Result := -1;
-  for i := 0 to Vertices.Count - 1 do
-  begin
-    bonesMatch := True;
-    for j := 0 to High(boneIDs) do
-    begin
-      if (boneIDs[j].BoneID <> VerticesBonesWeights^[i]^[j].BoneID)
-        or (boneIDs[j].Weight <> VerticesBonesWeights^[i]^[j].Weight) then
-      begin
-        bonesMatch := False;
-        Break;
-      end;
-    end;
-    if bonesMatch and VectorEquals(Vertices[i], vertex)
-      and VectorEquals(Normals[i], normal) then
-    begin
-      Result := i;
-      Break;
-    end;
-  end;
-  if Result < 0 then
-  begin
-    AddWeightedBones(boneIDs);
-    Vertices.Add(vertex);
-    Result := Normals.Add(normal);
-  end;
-end;
-
-procedure TGLSkeletonMeshObject.PrepareBoneMatrixInvertedMeshes;
-var
-  i, k, boneIndex: Integer;
-  invMesh: TGLBaseMeshObject;
-  invMat: TGLMatrix;
-  Bone: TGLSkeletonBone;
-  p: TGLVector;
-begin
-  // cleanup existing stuff
-  for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
-    TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
-  FBoneMatrixInvertedMeshes.Clear;
-  // calculate
-  for k := 0 to BonesPerVertex - 1 do
-  begin
-    invMesh := TGLBaseMeshObject.Create;
-    FBoneMatrixInvertedMeshes.Add(invMesh);
-    invMesh.Vertices := Vertices;
-    invMesh.Normals := Normals;
-    for i := 0 to Vertices.Count - 1 do
-    begin
-      boneIndex := VerticesBonesWeights^[i]^[k].BoneID;
-      Bone := Owner.Owner.Skeleton.RootBones.BoneByID(boneIndex);
-      // transform point
-      MakePoint(p, Vertices[i]);
-      invMat := Bone.GlobalMatrix;
-      InvertMatrix(invMat);
-      p := VectorTransform(p, invMat);
-      invMesh.Vertices[i] := PAffineVector(@p)^;
-      // transform normal
-      SetVector(p, normals[i]);
-      invMat := Bone.GlobalMatrix;
-      invMat.W := NullHmgPoint;
-      InvertMatrix(invMat);
-      p := VectorTransform(p, invMat);
-      invMesh.Normals[i] := PAffineVector(@p)^;
-    end;
-  end;
-end;
-
-procedure TGLSkeletonMeshObject.BackupBoneMatrixInvertedMeshes; // ragdoll
-var
-  i: Integer;
-  bm: TGLBaseMeshObject;
-begin
-  // cleanup existing stuff
-  for i := 0 to FBackupInvertedMeshes.Count - 1 do
-    TGLBaseMeshObject(FBackupInvertedMeshes[i]).Free;
-  FBackupInvertedMeshes.Clear;
-  // copy current stuff
-  for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
-  begin
-    bm := TGLBaseMeshObject.Create;
-    bm.Assign(TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]));
-    FBackupInvertedMeshes.Add(bm);
-    TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
-  end;
-  FBoneMatrixInvertedMeshes.Clear;
-end;
-
-procedure TGLSkeletonMeshObject.RestoreBoneMatrixInvertedMeshes; // ragdoll
-var
-  i: Integer;
-  bm: TGLBaseMeshObject;
-begin
-  // cleanup existing stuff
-  for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
-    TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
-  FBoneMatrixInvertedMeshes.Clear;
-  // restore the backup
-  for i := 0 to FBackupInvertedMeshes.Count - 1 do
-  begin
-    bm := TGLBaseMeshObject.Create;
-    bm.Assign(TGLBaseMeshObject(FBackupInvertedMeshes[i]));
-    FBoneMatrixInvertedMeshes.Add(bm);
-    TGLBaseMeshObject(FBackupInvertedMeshes[i]).Free;
-  end;
-  FBackupInvertedMeshes.Clear;
-end;
-
-procedure TGLSkeletonMeshObject.ApplyCurrentSkeletonFrame(normalize: Boolean);
-var
-  i, j, BoneID: Integer;
-  refVertices, refNormals: TGLAffineVectorList;
-  n, nt: TGLVector;
-  Bone: TGLSkeletonBone;
-  Skeleton: TGLSkeleton;
-  tempvert, tempnorm: TAffineVector;
-begin
-  with TGLBaseMeshObject(FBoneMatrixInvertedMeshes[0]) do
-  begin
-    refVertices := Vertices;
-    refNormals := Normals;
-  end;
-  Skeleton := Owner.Owner.Skeleton;
-  n.W := 0;
-  if BonesPerVertex = 1 then
-  begin
-    // simple case, one bone per vertex
-    for i := 0 to refVertices.Count - 1 do
-    begin
-      BoneID := VerticesBonesWeights^[i]^[0].BoneID;
-      Bone := Skeleton.BoneByID(BoneID);
-      Vertices.List^[i] := VectorTransform(refVertices.List^[i], Bone.GlobalMatrix);
-      PAffineVector(@n)^ := refNormals.list^[i];
-      nt := VectorTransform(n, Bone.GlobalMatrix);
-      Normals.List^[i] := PAffineVector(@nt)^;
-    end;
-  end
-  else
-  begin
-    // multiple bones per vertex
-    for i := 0 to refVertices.Count - 1 do
-    begin
-      Vertices.List^[i] := NullVector;
-      Normals.List^[i] := NullVector;
-      for j := 0 to BonesPerVertex - 1 do
-      begin
-        with TGLBaseMeshObject(FBoneMatrixInvertedMeshes[j]) do
-        begin
-          refVertices := Vertices;
-          refNormals := Normals;
-        end;
-        tempvert := NullVector;
-        tempnorm := NullVector;
-        if VerticesBonesWeights^[i]^[j].weight <> 0 then
-        begin
-          BoneID := VerticesBonesWeights^[i]^[j].BoneID;
-          Bone := Skeleton.BoneByID(BoneID);
-          CombineVector(tempvert, VectorTransform(refVertices.list^[i], Bone.GlobalMatrix),
-            VerticesBonesWeights^[i]^[j].weight);
-          PAffineVector(@n)^ := refNormals.list^[i];
-          n := VectorTransform(n, Bone.GlobalMatrix);
-          CombineVector(tempnorm, PAffineVector(@n)^, VerticesBonesWeights^[i]^[j].weight);
-        end;
-        AddVector(Vertices.list^[i], tempvert);
-        AddVector(normals.list^[i], tempnorm);
-      end;
-    end;
-  end;
-  if normalize then
-    normals.normalize;
-end;
-
-// ------------------
-// ------------------ TGLFaceGroup ------------------
-// ------------------
-
-constructor TGLFaceGroup.CreateOwned(AOwner: TGLFaceGroups);
-begin
-  FOwner := AOwner;
-  FLightMapIndex := -1;
-  Create;
-  if Assigned(FOwner) then
-    FOwner.Add(Self);
-end;
-
-destructor TGLFaceGroup.Destroy;
-begin
-  if Assigned(FOwner) then
-    FOwner.Remove(Self);
-  inherited;
-end;
-
-procedure TGLFaceGroup.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    if FLightMapIndex < 0 then
-    begin
-      WriteInteger(0); // Archive Version 0
-      WriteString(FMaterialName);
-    end
-    else
-    begin
-      WriteInteger(1); // Archive Version 1, added FLightMapIndex
-      WriteString(FMaterialName);
-      WriteInteger(FLightMapIndex);
-    end;
-  end;
-end;
-
-procedure TGLFaceGroup.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion in [0 .. 1] then
-    with reader do
-    begin
-      FMaterialName := ReadString;
-      if archiveVersion >= 1 then
-        FLightMapIndex := ReadInteger
-      else
-        FLightMapIndex := -1;
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TGLFaceGroup.AttachLightmap(lightMap: TGLTexture; var mrci: TGLRenderContextInfo);
-begin
-  if GL.ARB_multitexture then
-    with lightMap do
-    begin
-      Assert(Image.NativeTextureTarget = ttTexture2D);
-      mrci.GLStates.TextureBinding[1, ttTexture2D] := Handle;
-      gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-      mrci.GLStates.ActiveTexture := 0;
-    end;
-end;
-
-procedure TGLFaceGroup.AttachOrDetachLightmap(var mrci: TGLRenderContextInfo);
-var
-  libMat: TGLLibMaterial;
-begin
-  if GL.ARB_multitexture then
-  begin
-    if (not mrci.ignoreMaterials) and Assigned(mrci.LightmapLibrary) then
-    begin
-      if Owner.Owner.FLastLightMapIndex <> LightMapIndex then
-      begin
-        Owner.Owner.FLastLightMapIndex := LightMapIndex;
-        if LightMapIndex >= 0 then
-        begin
-          // attach and activate lightmap
-          Assert(LightMapIndex < TGLMaterialLibrary(mrci.LightmapLibrary).Materials.Count);
-          libMat := TGLMaterialLibrary(mrci.LightmapLibrary).Materials[LightMapIndex];
-          AttachLightmap(libMat.Material.Texture, mrci);
-          Owner.Owner.EnableLightMapArray(mrci);
-        end
-        else
-        begin
-          // desactivate lightmap
-          Owner.Owner.DisableLightMapArray(mrci);
-        end;
-      end;
-    end;
-  end;
-end;
-
-procedure TGLFaceGroup.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
-begin
-  if (FMaterialName <> '') and (matLib <> nil) then
-    FMaterialCache := matLib.Materials.GetLibMaterialByName(FMaterialName)
-  else
-    FMaterialCache := nil;
-end;
-
-procedure TGLFaceGroup.DropMaterialLibraryCache;
-begin
-  FMaterialCache := nil;
-end;
-
-procedure TGLFaceGroup.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
-  aNormals: TGLAffineVectorList = nil);
-begin
-  // nothing
-end;
-
-procedure TGLFaceGroup.Reverse;
-begin
-  // nothing
-end;
-
-procedure TGLFaceGroup.Prepare;
-begin
-  // nothing
-end;
-
-// ------------------
-// ------------------ TFGVertexIndexList ------------------
-// ------------------
-
-constructor TFGVertexIndexList.Create;
-begin
-  inherited;
-  FVertexIndices := TGLIntegerList.Create;
-  FMode := fgmmTriangles;
-end;
-
-destructor TFGVertexIndexList.Destroy;
-begin
-  FVertexIndices.Free;
-  FIndexVBO.Free;
-  inherited;
-end;
-
-procedure TFGVertexIndexList.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    FVertexIndices.WriteToFiler(writer);
-    WriteInteger(Integer(FMode));
-  end;
-end;
-
-procedure TFGVertexIndexList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      FVertexIndices.ReadFromFiler(reader);
-      FMode := TGLFaceGroupMeshMode(ReadInteger);
-      InvalidateVBO;
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TFGVertexIndexList.SetupVBO;
-const
-  BufferUsage = GL_STATIC_DRAW;
-begin
-  if not Assigned(FIndexVBO) then
-    FIndexVBO := TGLVBOElementArrayHandle.Create;
-
-  FIndexVBO.AllocateHandle;
-
-  if FIndexVBO.IsDataNeedUpdate then
-  begin
-    FIndexVBO.BindBufferData(vertexIndices.list, SizeOf(Integer) * vertexIndices.Count, BufferUsage);
-    FIndexVBO.NotifyDataUpdated;
-  end;
-end;
-
-procedure TFGVertexIndexList.SetVertexIndices(const val: TGLIntegerList);
-begin
-  FVertexIndices.Assign(val);
-  InvalidateVBO;
-end;
-
-procedure TFGVertexIndexList.BuildList(var mrci: TGLRenderContextInfo);
-const
-  cFaceGroupMeshModeToOpenGL: array [TGLFaceGroupMeshMode] of Integer = (GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLES,
-    GL_TRIANGLE_FAN, GL_QUADS);
-begin
-  if VertexIndices.Count = 0 then
-    Exit;
-  Owner.Owner.DeclareArraysToOpenGL(mrci, False);
-  AttachOrDetachLightmap(mrci);
-
-  if Owner.Owner.UseVBO then
-  begin
-    SetupVBO;
-
-    FIndexVBO.Bind;
-    gl.DrawElements(cFaceGroupMeshModeToOpenGL[mode], vertexIndices.Count, GL_UNSIGNED_INT, nil);
-    FIndexVBO.UnBind;
-  end
-  else
-  begin
-    gl.DrawElements(cFaceGroupMeshModeToOpenGL[mode], vertexIndices.Count, GL_UNSIGNED_INT, vertexIndices.list);
-  end;
-end;
-
-procedure TFGVertexIndexList.AddToList(Source, destination: TGLAffineVectorList; indices: TGLIntegerList);
-var
-  i, n: Integer;
-begin
-  if not Assigned(destination) then
-    Exit;
-  if indices.Count < 3 then
-    Exit;
-  case Mode of
-    fgmmTriangles, fgmmFlatTriangles:
-      begin
-        n := (indices.Count div 3) * 3;
-        if Source.Count > 0 then
-        begin
-          destination.AdjustCapacityToAtLeast(destination.Count + n);
-          for i := 0 to n - 1 do
-            destination.Add(Source[indices.list^[i]]);
-        end
-        else
-          destination.AddNulls(destination.Count + n);
-      end;
-    fgmmTriangleStrip:
-      begin
-        if Source.Count > 0 then
-          ConvertStripToList(Source, indices, destination)
-        else
-          destination.AddNulls(destination.Count + (indices.Count - 2) * 3);
-      end;
-    fgmmTriangleFan:
-      begin
-        n := (indices.Count - 2) * 3;
-        if Source.Count > 0 then
-        begin
-          destination.AdjustCapacityToAtLeast(destination.Count + n);
-          for i := 2 to VertexIndices.Count - 1 do
-          begin
-            destination.Add(Source[indices.list^[0]], Source[indices.list^[i - 1]], Source[indices.list^[i]]);
-          end;
-        end
-        else
-          destination.AddNulls(destination.Count + n);
-      end;
-    fgmmQuads:
-      begin
-        n := indices.Count div 4;
-        if Source.Count > 0 then
-        begin
-          destination.AdjustCapacityToAtLeast(destination.Count + n * 6);
-          i := 0;
-          while n > 0 do
-          begin
-            destination.Add(Source[indices.list^[i]], Source[indices.list^[i + 1]], Source[indices.list^[i + 2]]);
-            destination.Add(Source[indices.list^[i]], Source[indices.list^[i + 2]], Source[indices.list^[i + 3]]);
-            Inc(i, 4);
-            Dec(n);
-          end;
-        end
-        else
-          destination.AddNulls(destination.Count + n * 6);
-      end;
-  else
-    Assert(False);
-  end;
-end;
-
-procedure TFGVertexIndexList.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
-  aNormals: TGLAffineVectorList = nil);
-var
-  mo: TGLMeshObject;
-begin
-  mo := Owner.Owner;
-  AddToList(mo.Vertices, aList, VertexIndices);
-  AddToList(mo.TexCoords, aTexCoords, VertexIndices);
-  AddToList(mo.Normals, aNormals, VertexIndices);
-  InvalidateVBO;
-end;
-
-function TFGVertexIndexList.TriangleCount: Integer;
-begin
-  case Mode of
-    fgmmTriangles, fgmmFlatTriangles:
-      Result := VertexIndices.Count div 3;
-    fgmmTriangleFan, fgmmTriangleStrip:
-      begin
-        Result := VertexIndices.Count - 2;
-        if Result < 0 then
-          Result := 0;
-      end;
-    fgmmQuads:
-      result := VertexIndices.Count div 2;
-  else
-    Result := 0;
-    Assert(False);
-  end;
-end;
-
-procedure TFGVertexIndexList.Reverse;
-begin
-  VertexIndices.Reverse;
-  InvalidateVBO;
-end;
-
-procedure TFGVertexIndexList.Add(idx: Integer);
-begin
-  FVertexIndices.Add(idx);
-  InvalidateVBO;
-end;
-
-procedure TFGVertexIndexList.GetExtents(var min, max: TAffineVector);
-var
-  i, k: Integer;
-  f: Single;
-  ref: PFloatArray;
-const
-  cBigValue: Single = 1E50;
-  cSmallValue: Single = -1E50;
-begin
-  SetVector(min, cBigValue, cBigValue, cBigValue);
-  SetVector(max, cSmallValue, cSmallValue, cSmallValue);
-  for i := 0 to VertexIndices.Count - 1 do
-  begin
-    ref := Owner.Owner.Vertices.ItemAddress[VertexIndices[i]];
-    for k := 0 to 2 do
-    begin
-      f := ref^[k];
-      if f < min.V[k] then
-        min.V[k] := f;
-      if f > max.V[k] then
-        max.V[k] := f;
-    end;
-  end;
-end;
-
-procedure TFGVertexIndexList.ConvertToList;
-var
-  i: Integer;
-  bufList: TGLIntegerList;
-begin
-  if VertexIndices.Count >= 3 then
-  begin
-    case Mode of
-      fgmmTriangleStrip:
-        begin
-          bufList := TGLIntegerList.Create;
-          try
-            ConvertStripToList(VertexIndices, bufList);
-            VertexIndices := bufList;
-          finally
-            bufList.Free;
-          end;
-          FMode := fgmmTriangles;
-        end;
-      fgmmTriangleFan:
-        begin
-          bufList := TGLIntegerList.Create;
-          try
-            for i := 0 to VertexIndices.Count - 3 do
-              bufList.Add(vertexIndices[0], vertexIndices[i], vertexIndices[i + 1]);
-            vertexIndices := bufList;
-          finally
-            bufList.Free;
-          end;
-          FMode := fgmmTriangles;
-        end;
-    end;
-    InvalidateVBO;
-  end;
-end;
-
-function TFGVertexIndexList.GetNormal: TAffineVector;
-begin
-  if VertexIndices.Count < 3 then
-    Result := NullVector
-  else
-    with Owner.Owner.Vertices do
-      CalcPlaneNormal(Items[VertexIndices[0]], Items[VertexIndices[1]],
-        Items[VertexIndices[2]], Result);
-end;
-
-procedure TFGVertexIndexList.InvalidateVBO;
-begin
-  if Assigned(FIndexVBO) then
-    FIndexVBO.NotifyChangesOfData;
-end;
-
-// ------------------
-// ------------------ TFGVertexNormalTexIndexList ------------------
-// ------------------
-
-constructor TFGVertexNormalTexIndexList.Create;
-begin
-  inherited;
-  FNormalIndices := TGLIntegerList.Create;
-  FTexCoordIndices := TGLIntegerList.Create;
-end;
-
-destructor TFGVertexNormalTexIndexList.Destroy;
-begin
-  FTexCoordIndices.Free;
-  FNormalIndices.Free;
-  inherited;
-end;
-
-procedure TFGVertexNormalTexIndexList.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    FNormalIndices.WriteToFiler(writer);
-    FTexCoordIndices.WriteToFiler(writer);
-  end;
-end;
-
-procedure TFGVertexNormalTexIndexList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      FNormalIndices.ReadFromFiler(reader);
-      FTexCoordIndices.ReadFromFiler(reader);
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TFGVertexNormalTexIndexList.SetNormalIndices(const val: TGLIntegerList);
-begin
-  FNormalIndices.Assign(val);
-end;
-
-procedure TFGVertexNormalTexIndexList.SetTexCoordIndices(const val: TGLIntegerList);
-begin
-  FTexCoordIndices.Assign(val);
-end;
-
-procedure TFGVertexNormalTexIndexList.BuildList(var mrci: TGLRenderContextInfo);
-var
-  i: Integer;
-  vertexPool: PAffineVectorArray;
-  normalPool: PAffineVectorArray;
-  texCoordPool: PAffineVectorArray;
-  colorPool: PVectorArray;
-  normalIdxList, texCoordIdxList, vertexIdxList: PIntegerVector;
-begin
-  Assert(((TexCoordIndices.Count = 0) or (VertexIndices.Count <= TexCoordIndices.Count))
-    and ((NormalIndices.Count = 0) or (VertexIndices.Count <= NormalIndices.Count)));
-  vertexPool := Owner.Owner.Vertices.List;
-  normalPool := Owner.Owner.Normals.List;
-  colorPool := Owner.Owner.Colors.List;
-  texCoordPool := Owner.Owner.TexCoords.List;
-  case Mode of
-    fgmmTriangles, fgmmFlatTriangles: gl.Begin_(GL_TRIANGLES);
-    fgmmTriangleStrip: gl.Begin_(GL_TRIANGLE_STRIP);
-    fgmmTriangleFan: gl.Begin_(GL_TRIANGLE_FAN);
-  else
-    Assert(False);
-  end;
-  vertexIdxList := VertexIndices.List;
-  if NormalIndices.Count > 0 then
-    normalIdxList := NormalIndices.List
-  else
-    normalIdxList := vertexIdxList;
-  if TexCoordIndices.Count > 0 then
-    texCoordIdxList := TexCoordIndices.List
-  else
-    texCoordIdxList := vertexIdxList;
-
-  for i := 0 to VertexIndices.Count - 1 do
-  begin
-    gl.Normal3fv(@normalPool[normalIdxList^[i]]);
-    if Assigned(colorPool) then
-      gl.Color4fv(@colorPool[vertexIdxList^[i]]);
-    if Assigned(texCoordPool) then
-      xgl.TexCoord2fv(@texCoordPool[texCoordIdxList^[i]]);
-    gl.Vertex3fv(@vertexPool[vertexIdxList^[i]]);
-  end;
-
-  gl.End_;
-end;
-
-procedure TFGVertexNormalTexIndexList.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
-  aNormals: TGLAffineVectorList = nil);
-begin
-  AddToList(Owner.Owner.Vertices, aList, VertexIndices);
-  AddToList(Owner.Owner.TexCoords, aTexCoords, TexCoordIndices);
-  AddToList(Owner.Owner.Normals, aNormals, NormalIndices);
-end;
-
-procedure TFGVertexNormalTexIndexList.Add(vertexIdx, normalIdx, texCoordIdx: Integer);
-begin
-  inherited Add(vertexIdx);
-  FNormalIndices.Add(normalIdx);
-  FTexCoordIndices.Add(texCoordIdx);
-end;
-
-// ------------------
-// ------------------ TFGIndexTexCoordList ------------------
-// ------------------
-
-constructor TFGIndexTexCoordList.Create;
-begin
-  inherited;
-  FTexCoords := TGLAffineVectorList.Create;
-end;
-
-destructor TFGIndexTexCoordList.Destroy;
-begin
-  FTexCoords.Free;
-  inherited;
-end;
-
-procedure TFGIndexTexCoordList.WriteToFiler(writer: TGLVirtualWriter);
-begin
-  inherited WriteToFiler(writer);
-  with writer do
-  begin
-    WriteInteger(0); // Archive Version 0
-    FTexCoords.WriteToFiler(writer);
-  end;
-end;
-
-procedure TFGIndexTexCoordList.ReadFromFiler(reader: TGLVirtualReader);
-var
-  archiveVersion: Integer;
-begin
-  inherited ReadFromFiler(reader);
-  archiveVersion := reader.ReadInteger;
-  if archiveVersion = 0 then
-    with reader do
-    begin
-      FTexCoords.ReadFromFiler(reader);
-    end
-  else
-    RaiseFilerException(archiveVersion);
-end;
-
-procedure TFGIndexTexCoordList.SetTexCoords(const val: TGLAffineVectorList);
-begin
-  FTexCoords.Assign(val);
-end;
-
-procedure TFGIndexTexCoordList.BuildList(var mrci: TGLRenderContextInfo);
-var
-  i, k: Integer;
-  texCoordPool: PAffineVectorArray;
-  vertexPool: PAffineVectorArray;
-  normalPool: PAffineVectorArray;
-  indicesPool: PIntegerArray;
-  colorPool: PVectorArray;
-  gotColor: Boolean;
-
-begin
-  Assert(VertexIndices.Count = TexCoords.Count);
-  texCoordPool := TexCoords.List;
-  vertexPool := Owner.Owner.Vertices.List;
-  indicesPool := @VertexIndices.List[0];
-  colorPool := @Owner.Owner.Colors.List[0];
-  gotColor := (Owner.Owner.Vertices.Count = Owner.Owner.Colors.Count);
-
-  case Mode of
-    fgmmTriangles: gl.Begin_(GL_TRIANGLES);
-    fgmmFlatTriangles: gl.Begin_(GL_TRIANGLES);
-    fgmmTriangleStrip: gl.Begin_(GL_TRIANGLE_STRIP);
-    fgmmTriangleFan: gl.Begin_(GL_TRIANGLE_FAN);
-    fgmmQuads: gl.Begin_(GL_QUADS);
-  else
-    Assert(False);
-  end;
-  if Owner.Owner.Normals.Count = Owner.Owner.Vertices.Count then
-  begin
-    normalPool := Owner.Owner.Normals.List;
-    for i := 0 to VertexIndices.Count - 1 do
-    begin
-      xgl.TexCoord2fv(@texCoordPool[i]);
-      k := indicesPool[i];
-      if gotColor then
-        gl.Color4fv(@colorPool[k]);
-      gl.Normal3fv(@normalPool[k]);
-      gl.Vertex3fv(@vertexPool[k]);
-    end;
-  end
-  else
-  begin
-    for i := 0 to VertexIndices.Count - 1 do
-    begin
-      xgl.TexCoord2fv(@texCoordPool[i]);
-      if gotColor then
-        gl.Color4fv(@colorPool[indicesPool[i]]);
-      gl.Vertex3fv(@vertexPool[indicesPool[i]]);
-    end;
-  end;
-  gl.End_;
-  gl.CheckError;
-end;
-
-procedure TFGIndexTexCoordList.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
-  aNormals: TGLAffineVectorList = nil);
-var
-  i, n: Integer;
-  texCoordList: TGLAffineVectorList;
-begin
-  AddToList(Owner.Owner.Vertices, aList, VertexIndices);
-  AddToList(Owner.Owner.Normals, aNormals, VertexIndices);
-  texCoordList := Self.TexCoords;
-  case Mode of
-    fgmmTriangles, fgmmFlatTriangles:
-      begin
-        if Assigned(aTexCoords) then
-        begin
-          n := (VertexIndices.Count div 3) * 3;
-          aTexCoords.AdjustCapacityToAtLeast(aTexCoords.Count + n);
-          for i := 0 to n - 1 do
-            aTexCoords.Add(texCoordList[i]);
-        end;
-      end;
-    fgmmTriangleStrip:
-      begin
-        if Assigned(aTexCoords) then
-          ConvertStripToList(aTexCoords, texCoordList);
-      end;
-    fgmmTriangleFan:
-      begin
-        if Assigned(aTexCoords) then
-        begin
-          aTexCoords.AdjustCapacityToAtLeast(aTexCoords.Count + (VertexIndices.Count - 2) * 3);
-          for i := 2 to VertexIndices.Count - 1 do
-          begin
-            aTexCoords.Add(texCoordList[0], texCoordList[i - 1], texCoordList[i]);
-          end;
-        end;
-      end;
-  else
-    Assert(False);
-  end;
-end;
-
-procedure TFGIndexTexCoordList.Add(idx: Integer; const texCoord: TAffineVector);
-begin
-  TexCoords.Add(texCoord);
-  inherited Add(idx);
-end;
-
-procedure TFGIndexTexCoordList.Add(idx: Integer; const s, t: Single);
-begin
-  TexCoords.Add(s, t, 0);
-  inherited Add(idx);
-end;
-
-// ------------------
-// ------------------ TGLFaceGroups ------------------
-// ------------------
-
-constructor TGLFaceGroups.CreateOwned(AOwner: TGLMeshObject);
-begin
-  FOwner := AOwner;
-  Create;
-end;
-
-destructor TGLFaceGroups.Destroy;
-begin
-  Clear;
-  inherited;
-end;
-
-procedure TGLFaceGroups.ReadFromFiler(reader: TGLVirtualReader);
-var
-  i: Integer;
-begin
-  inherited;
-  for i := 0 to Count - 1 do
-    Items[i].FOwner := Self;
-end;
-
-procedure TGLFaceGroups.Clear;
-var
-  i: Integer;
-  fg: TGLFaceGroup;
-begin
-  for i := 0 to Count - 1 do
-  begin
-    fg := GetFaceGroup(i);
-    if Assigned(fg) then
-    begin
-      fg.FOwner := nil;
-      fg.Free;
-    end;
-  end;
-  inherited;
-end;
-
-function TGLFaceGroups.GetFaceGroup(Index: Integer): TGLFaceGroup;
-begin
-  Result := TGLFaceGroup(List^[Index]);
-end;
-
-procedure TGLFaceGroups.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    TGLFaceGroup(List^[i]).PrepareMaterialLibraryCache(matLib);
-end;
-
-procedure TGLFaceGroups.DropMaterialLibraryCache;
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    TGLFaceGroup(List^[i]).DropMaterialLibraryCache;
-end;
-
-procedure TGLFaceGroups.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
-  aNormals: TGLAffineVectorList = nil);
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    Items[i].AddToTriangles(aList, aTexCoords, aNormals);
-end;
-
-function TGLFaceGroups.MaterialLibrary: TGLMaterialLibrary;
-var
-  mol: TGLMeshObjectList;
-  bm: TGLBaseMesh;
-begin
-  if Assigned(Owner) then
-  begin
-    mol := Owner.Owner;
-    if Assigned(mol) then
-    begin
-      bm := mol.Owner;
-      if Assigned(bm) then
-      begin
-        Result := bm.MaterialLibrary;
-        Exit;
-      end;
-    end;
-  end;
-  Result := nil;
-end;
-
-function CompareMaterials(item1, item2: TObject): Integer;
-
-  function MaterialIsOpaque(fg: TGLFaceGroup): Boolean;
-  var
-    libMat: TGLLibMaterial;
-  begin
-    libMat := fg.MaterialCache;
-    Result := (not Assigned(libMat)) or (not libMat.Material.Blended);
-  end;
-
-var
-  fg1, fg2: TGLFaceGroup;
-  opaque1, opaque2: Boolean;
-begin
-  fg1 := TGLFaceGroup(item1);
-  opaque1 := MaterialIsOpaque(fg1);
-  fg2 := TGLFaceGroup(item2);
-  opaque2 := MaterialIsOpaque(fg2);
-  if opaque1 = opaque2 then
-  begin
-    Result := CompareStr(fg1.MaterialName, fg2.MaterialName);
-    if Result = 0 then
-      Result := fg1.LightMapIndex - fg2.LightMapIndex;
-  end
-  else if opaque1 then
-    Result := -1
-  else
-    Result := 1;
-end;
-
-procedure TGLFaceGroups.SortByMaterial;
-begin
-  PrepareMaterialLibraryCache(Owner.Owner.Owner.MaterialLibrary);
-  Sort(@CompareMaterials);
-end;
-
-// ------------------
-// ------------------ TGLVectorFile ------------------
-// ------------------
-
-constructor TGLVectorFile.Create(AOwner: TPersistent);
-begin
-  Assert(AOwner is TGLBaseMesh);
-  inherited;
-end;
-
-function TGLVectorFile.Owner: TGLBaseMesh;
-begin
-  Result := TGLBaseMesh(GetOwner);
-end;
-
-procedure TGLVectorFile.SetNormalsOrientation(const val: TGLMeshNormalsOrientation);
-begin
-  FNormalsOrientation := val;
-end;
-
-// ------------------
-// ------------------ TGLSMVectorFile ------------------
-// ------------------
-
-class function TGLSMVectorFile.Capabilities: TGLDataFileCapabilities;
-begin
-  Result := [dfcRead, dfcWrite];
-end;
-
-procedure TGLSMVectorFile.LoadFromStream(aStream: TStream);
-begin
-  Owner.MeshObjects.LoadFromStream(aStream);
-end;
-
-procedure TGLSMVectorFile.SaveToStream(aStream: TStream);
-begin
-  Owner.MeshObjects.SaveToStream(aStream);
-end;
-
-// ------------------
-// ------------------ TGLBaseMesh ------------------
-// ------------------
-
-constructor TGLBaseMesh.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  if FMeshObjects = nil then
-    FMeshObjects := TGLMeshObjectList.CreateOwned(Self);
-  if FSkeleton = nil then
-    FSkeleton := TGLSkeleton.CreateOwned(Self);
-  FUseMeshMaterials := True;
-  FAutoCentering := [];
-  FAxisAlignedDimensionsCache.X := -1;
-  FBaryCenterOffsetChanged := True;
-  FAutoScaling := TGLCoordinates.CreateInitialized(Self, XYZWHmgVector, csPoint);
-end;
-
-destructor TGLBaseMesh.Destroy;
-begin
-  FConnectivity.Free;
-  DropMaterialLibraryCache;
-  FSkeleton.Free;
-  FMeshObjects.Free;
-  FAutoScaling.Free;
-  inherited Destroy;
-end;
-
-procedure TGLBaseMesh.Assign(Source: TPersistent);
-begin
-  if Source is TGLBaseMesh then
-  begin
-    FSkeleton.Clear;
-    FNormalsOrientation := TGLBaseMesh(Source).FNormalsOrientation;
-    FMaterialLibrary := TGLBaseMesh(Source).FMaterialLibrary;
-    FLightmapLibrary := TGLBaseMesh(Source).FLightmapLibrary;
-    FAxisAlignedDimensionsCache :=  TGLBaseMesh(Source).FAxisAlignedDimensionsCache;
-    FBaryCenterOffset := TGLBaseMesh(Source).FBaryCenterOffset;
-    FUseMeshMaterials := TGLBaseMesh(Source).FUseMeshMaterials;
-    FOverlaySkeleton := TGLBaseMesh(Source).FOverlaySkeleton;
-    FIgnoreMissingTextures := TGLBaseMesh(Source).FIgnoreMissingTextures;
-    FAutoCentering := TGLBaseMesh(Source).FAutoCentering;
-    FAutoScaling.Assign(TGLBaseMesh(Source).FAutoScaling);
-    FSkeleton.Assign(TGLBaseMesh(Source).FSkeleton);
-    FSkeleton.RootBones.PrepareGlobalMatrices;
-    FMeshObjects.Assign(TGLBaseMesh(Source).FMeshObjects);
-  end;
-  inherited Assign(Source);
-end;
-
-procedure TGLBaseMesh.LoadFromFile(const filename: string);
-var
-  fs: TFileStream;
-begin
-  FLastLoadedFilename := '';
-  if fileName <> '' then
-  begin
-    try
-      fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyWrite);
-      LoadFromStream(fileName, fs);
-      FLastLoadedFilename := filename;
-    finally
-      fs.Free;
-    end;
-  end;
-end;
-
-procedure TGLBaseMesh.LoadFromStream(const fileName: string; aStream: TStream);
-var
-  newVectorFile: TGLVectorFile;
-  vectorFileClass: TGLVectorFileClass;
-begin
-  FLastLoadedFilename := '';
-  if fileName <> '' then
-  begin
-    MeshObjects.Clear;
-    Skeleton.Clear;
-    vectorFileClass := GetVectorFileFormats.FindFromFileName(filename);
-    newVectorFile := VectorFileClass.Create(Self);
-    try
-      newVectorFile.ResourceName := filename;
-      PrepareVectorFile(newVectorFile);
-      if Assigned(Scene) then
-        Scene.BeginUpdate;
-      try
-        newVectorFile.LoadFromStream(aStream);
-        FLastLoadedFilename := filename;
-      finally
-        if Assigned(Scene) then
-          Scene.EndUpdate;
-      end;
-    finally
-      newVectorFile.Free;
-    end;
-    PerformAutoScaling;
-    PerformAutoCentering;
-    PrepareMesh;
-  end;
-end;
-
-procedure TGLBaseMesh.SaveToFile(const filename: string);
-var
-  fs: TStream;
-begin
-  if fileName <> '' then
-  begin
-    try
-      fs := TFileStream.Create(fileName, fmCreate);
-      SaveToStream(fileName, fs);
-    finally
-      fs.Free;
-    end;
-  end;
-end;
-
-procedure TGLBaseMesh.SaveToStream(const fileName: string; aStream: TStream);
-var
-  newVectorFile: TGLVectorFile;
-  vectorFileClass: TGLVectorFileClass;
-begin
-  if fileName <> '' then
-  begin
-    vectorFileClass := GetVectorFileFormats.FindFromFileName(filename);
-    newVectorFile := VectorFileClass.Create(Self);
-    try
-      newVectorFile.ResourceName := filename;
-      PrepareVectorFile(newVectorFile);
-      newVectorFile.SaveToStream(aStream);
-    finally
-      newVectorFile.Free;
-    end;
-  end;
-end;
-
-procedure TGLBaseMesh.AddDataFromFile(const filename: string);
-var
-  fs: TStream;
-begin
-  if fileName <> '' then
-  begin
-    fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyWrite);
-    try
-      AddDataFromStream(fileName, fs);
-    finally
-      fs.Free;
-    end;
-  end;
-end;
-
-procedure TGLBaseMesh.AddDataFromStream(const filename: string; aStream: TStream);
-var
-  newVectorFile: TGLVectorFile;
-  VectorFileClass: TGLVectorFileClass;
-begin
-  if filename <> '' then
-  begin
-    VectorFileClass := GetVectorFileFormats.FindFromFileName(filename);
-    newVectorFile := VectorFileClass.Create(Self);
-    newVectorFile.ResourceName := filename;
-    PrepareVectorFile(newVectorFile);
-    try
-      if Assigned(Scene) then
-        Scene.BeginUpdate;
-      newVectorFile.LoadFromStream(aStream);
-      if Assigned(Scene) then
-        Scene.EndUpdate;
-    finally
-      NewVectorFile.Free;
-    end;
-    PrepareMesh;
-  end;
-end;
-
-procedure TGLBaseMesh.GetExtents(out min, max: TAffineVector);
-var
-  i, k: Integer;
-  lMin, lMax: TAffineVector;
-const
-  cBigValue: Single = 1E50;
-  cSmallValue: Single = -1E50;
-begin
-  SetVector(min, cBigValue, cBigValue, cBigValue);
-  SetVector(max, cSmallValue, cSmallValue, cSmallValue);
-  for i := 0 to MeshObjects.Count - 1 do
-  begin
-    TGLMeshObject(MeshObjects[i]).GetExtents(lMin, lMax);
-    for k := 0 to 2 do
-    begin
-      if lMin.V[k] < min.V[k] then
-        min.V[k] := lMin.V[k];
-      if lMax.V[k] > max.V[k] then
-        max.V[k] := lMax.V[k];
-    end;
-  end;
-end;
-
-function TGLBaseMesh.GetBarycenter: TAffineVector;
-var
-  i, nb: Integer;
-begin
-  Result := NullVector;
-  nb := 0;
-  for i := 0 to MeshObjects.Count - 1 do
-    TGLMeshObject(MeshObjects[i]).ContributeToBarycenter(Result, nb);
-  if nb > 0 then
-    ScaleVector(Result, 1 / nb);
-end;
-
-function TGLBaseMesh.LastLoadedFilename: string;
-begin
-  Result := FLastLoadedFilename;
-end;
-
-procedure TGLBaseMesh.SetMaterialLibrary(const val: TGLMaterialLibrary);
-begin
-  if FMaterialLibrary <> val then
-  begin
-    if FMaterialLibraryCachesPrepared then
-      DropMaterialLibraryCache;
-    if Assigned(FMaterialLibrary) then
-    begin
-      DestroyHandle;
-      FMaterialLibrary.RemoveFreeNotification(Self);
-    end;
-    FMaterialLibrary := val;
-    if Assigned(FMaterialLibrary) then
-      FMaterialLibrary.FreeNotification(Self);
-    StructureChanged;
-  end;
-end;
-
-procedure TGLBaseMesh.SetLightmapLibrary(const val: TGLMaterialLibrary);
-begin
-  if FLightmapLibrary <> val then
-  begin
-    if Assigned(FLightmapLibrary) then
-    begin
-      DestroyHandle;
-      FLightmapLibrary.RemoveFreeNotification(Self);
-    end;
-    FLightmapLibrary := val;
-    if Assigned(FLightmapLibrary) then
-      FLightmapLibrary.FreeNotification(Self);
-    StructureChanged;
-  end;
-end;
-
-procedure TGLBaseMesh.SetNormalsOrientation(const val: TGLMeshNormalsOrientation);
-begin
-  if val <> FNormalsOrientation then
-  begin
-    FNormalsOrientation := val;
-    StructureChanged;
-  end;
-end;
-
-procedure TGLBaseMesh.SetOverlaySkeleton(const val: Boolean);
-begin
-  if FOverlaySkeleton <> val then
-  begin
-    FOverlaySkeleton := val;
-    NotifyChange(Self);
-  end;
-end;
-
-procedure TGLBaseMesh.SetAutoScaling(const Value: TGLCoordinates);
-begin
-  FAutoScaling.SetPoint(Value.DirectX, Value.DirectY, Value.DirectZ);
-end;
-
-procedure TGLBaseMesh.Notification(AComponent: TComponent; Operation: TOperation);
-begin
-  if Operation = opRemove then
-  begin
-    if AComponent = FMaterialLibrary then
-      MaterialLibrary := nil
-    else if AComponent = FLightmapLibrary then
-      LightmapLibrary := nil;
-  end;
-  inherited;
-end;
-
-function TGLBaseMesh.AxisAlignedDimensionsUnscaled: TGLVector;
-var
-  dMin, dMax: TAffineVector;
-begin
-  if FAxisAlignedDimensionsCache.X < 0 then
-  begin
-    MeshObjects.GetExtents(dMin, dMax);
-    FAxisAlignedDimensionsCache.X := (dMax.X - dMin.X) / 2;
-    FAxisAlignedDimensionsCache.Y := (dMax.Y - dMin.Y) / 2;
-    FAxisAlignedDimensionsCache.Z := (dMax.Z - dMin.Z) / 2;
-    FAxisAlignedDimensionsCache.W := 0;
-  end;
-  SetVector(Result, FAxisAlignedDimensionsCache);
-end;
-
-function TGLBaseMesh.BarycenterOffset: TGLVector;
-var
-  dMin, dMax: TAffineVector;
-begin
-  if FBaryCenterOffsetChanged then
-  begin
-    MeshObjects.GetExtents(dMin, dMax);
-
-    FBaryCenterOffset.X := (dMin.X + dMax.X) / 2;
-    FBaryCenterOffset.Y := (dMin.Y + dMax.Y) / 2;
-    FBaryCenterOffset.Z := (dMin.Z + dMax.Z) / 2;
-    FBaryCenterOffset.W := 0;
-    FBaryCenterOffsetChanged := False;
-  end;
-  Result := FBaryCenterOffset;
-end;
-
-function TGLBaseMesh.BarycenterPosition: TGLVector;
-begin
-  Result := VectorAdd(Position.DirectVector, BarycenterOffset);
-end;
-
-function TGLBaseMesh.BarycenterAbsolutePosition: TGLVector;
-begin
-  Result := LocalToAbsolute(BarycenterPosition);
-end;
-
-procedure TGLBaseMesh.DestroyHandle;
-begin
-  if Assigned(FMaterialLibrary) then
-    MaterialLibrary.DestroyHandles;
-  if Assigned(FLightmapLibrary) then
-    LightmapLibrary.DestroyHandles;
-  inherited;
-end;
-
-procedure TGLBaseMesh.PrepareVectorFile(aFile: TGLVectorFile);
-begin
-  aFile.NormalsOrientation := NormalsOrientation;
-end;
-
-procedure TGLBaseMesh.PerformAutoCentering;
-var
-  delta, min, max: TAffineVector;
-begin
-  if macUseBarycenter in AutoCentering then
-  begin
-    delta := VectorNegate(GetBarycenter);
-  end
-  else
-  begin
-    GetExtents(min, max);
-    if macCenterX in AutoCentering then
-      delta.X := -0.5 * (min.X + max.X)
-    else
-      delta.X := 0;
-    if macCenterY in AutoCentering then
-      delta.Y := -0.5 * (min.Y + max.Y)
-    else
-      delta.Y := 0;
-    if macCenterZ in AutoCentering then
-      delta.Z := -0.5 * (min.Z + max.Z)
-    else
-      delta.Z := 0;
-  end;
-  MeshObjects.Translate(delta);
-
-  if macRestorePosition in AutoCentering then
-    Position.Translate(VectorNegate(delta));
-end;
-
-procedure TGLBaseMesh.PerformAutoScaling;
-var
-  i: Integer;
-  vScal: TAffineFltVector;
-begin
-  if (FAutoScaling.DirectX <> 1) or (FAutoScaling.DirectY <> 1) or (FAutoScaling.DirectZ <> 1) then
-  begin
-    MakeVector(vScal, FAutoScaling.DirectX, FAutoScaling.DirectY, FAutoScaling.DirectZ);
-    for i := 0 to MeshObjects.Count - 1 do
-    begin
-      MeshObjects[i].Vertices.Scale(vScal);
-    end;
-  end;
-end;
-
-procedure TGLBaseMesh.PrepareMesh;
-begin
-  StructureChanged;
-end;
-
-procedure TGLBaseMesh.PrepareMaterialLibraryCache;
-begin
-  if FMaterialLibraryCachesPrepared then
-    DropMaterialLibraryCache;
-  MeshObjects.PrepareMaterialLibraryCache(FMaterialLibrary);
-  FMaterialLibraryCachesPrepared := True;
-end;
-
-procedure TGLBaseMesh.DropMaterialLibraryCache;
-begin
-  if FMaterialLibraryCachesPrepared then
-  begin
-    MeshObjects.DropMaterialLibraryCache;
-    FMaterialLibraryCachesPrepared := False;
-  end;
-end;
-
-procedure TGLBaseMesh.PrepareBuildList(var mrci: TGLRenderContextInfo);
-begin
-  MeshObjects.PrepareBuildList(mrci);
-  if LightmapLibrary <> nil then
-    LightmapLibrary.Materials.PrepareBuildList
-end;
-
-procedure TGLBaseMesh.SetUseMeshMaterials(const val: Boolean);
-begin
-  if val <> FUseMeshMaterials then
-  begin
-    FUseMeshMaterials := val;
-    if FMaterialLibraryCachesPrepared and (not val) then
-      DropMaterialLibraryCache;
-    StructureChanged;
-  end;
-end;
-
-procedure TGLBaseMesh.BuildList(var rci: TGLRenderContextInfo);
-begin
-  MeshObjects.BuildList(rci);
-end;
-
-procedure TGLBaseMesh.DoRender(var rci: TGLRenderContextInfo; renderSelf, renderChildren: Boolean);
-begin
-  if Assigned(LightmapLibrary) then
-    xgl.ForbidSecondTextureUnit;
-  if renderSelf then
-  begin
-    // set winding
-    case FNormalsOrientation of
-      mnoDefault:  ; // nothing
-      mnoInvert:  rci.GLStates.InvertGLFrontFace;
-    else
-      Assert(False);
-    end;
-    if not rci.ignoreMaterials then
-    begin
-      if UseMeshMaterials and Assigned(MaterialLibrary) then
-      begin
-        rci.MaterialLibrary := MaterialLibrary;
-        if not FMaterialLibraryCachesPrepared then
-          PrepareMaterialLibraryCache;
-      end
-      else
-        rci.MaterialLibrary := nil;
-      if Assigned(LightmapLibrary) then
-        rci.LightmapLibrary := LightmapLibrary
-      else
-        rci.LightmapLibrary := nil;
-      if rci.amalgamating or not(ListHandleAllocated or (osDirectDraw in ObjectStyle)) then
-        PrepareBuildList(rci);
-      Material.Apply(rci);
-      repeat
-        if (osDirectDraw in ObjectStyle) or
-		    rci.amalgamating or UseMeshMaterials then
-          BuildList(rci)
-        else
-          rci.GLStates.CallList(GetHandle(rci));
-      until not Material.UnApply(rci);
-      rci.MaterialLibrary := nil;
-    end
-    else
-    begin
-      if (osDirectDraw in ObjectStyle) or rci.amalgamating then
-        BuildList(rci)
-      else
-        rci.GLStates.CallList(GetHandle(rci));
-    end;
-    if FNormalsOrientation <> mnoDefault then
-      rci.GLStates.InvertGLFrontFace;
-  end;
-  if Assigned(LightmapLibrary) then
-    xgl.AllowSecondTextureUnit;
-  if renderChildren and (Count > 0) then
-    Self.RenderChildren(0, Count - 1, rci);
-end;
-
-procedure TGLBaseMesh.StructureChanged;
-begin
-  FAxisAlignedDimensionsCache.X := -1;
-  FBaryCenterOffsetChanged := True;
-  DropMaterialLibraryCache;
-  MeshObjects.Prepare;
-  inherited;
-end;
-
-procedure TGLBaseMesh.StructureChangedNoPrepare;
-begin
-  inherited StructureChanged;
-end;
-
-function TGLBaseMesh.RayCastIntersect(const rayStart, rayVector: TGLVector; intersectPoint: PGLVector = nil;
-  intersectNormal: PGLVector = nil): Boolean;
-
-var
-  i,j: Integer;
-  Obj: TGLMeshObject;
-  Tris: TGLAffineVectorList;
-  locRayStart, locRayVector, iPoint, iNormal: TGLVector;
-  d, minD: Single;
-
-begin
-  SetVector(locRayStart, AbsoluteToLocal(rayStart));
-  SetVector(locRayVector, AbsoluteToLocal(rayVector));
-  minD := -1;
-
-  for j := 0 to MeshObjects.Count - 1 do
-  begin
-    Obj := MeshObjects.GetMeshObject(j);
-    if not Obj.Visible then
-      Continue;
-    Tris := Obj.ExtractTriangles(NIL, NIL); //objTexCoords & objNormals
-    try
-      i := 0;
-      while i < Tris.Count do
-      begin
-        if RayCastTriangleIntersect(locRayStart, locRayVector, Tris.List^[i],
-          Tris.List^[i + 1], Tris.List^[i + 2], @iPoint, @iNormal) then
-        begin
-          d := VectorDistance2(locRayStart, iPoint);
-          if (d < minD) or (minD < 0) then
-          begin
-            minD := d;
-            if intersectPoint <> nil then
-              intersectPoint^ := iPoint;
-            if intersectNormal <> nil then
-              intersectNormal^ := iNormal;
-          end;
-        end;
-        Inc(i, 3);
-      end;
-    finally
-      Tris.Free;
-    end;
-  end;
-
-  Result := (minD >= 0);
-  if Result then
-  begin
-    if intersectPoint <> nil then
-      SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
-    if intersectNormal <> nil then
-    begin
-      SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
-      if NormalsOrientation = mnoInvert then
-        NegateVector(intersectNormal^);
-    end;
-  end;
-end;
-
-function TGLBaseMesh.GenerateSilhouette(const silhouetteParameters: TGLSilhouetteParameters): TGLSilhouette;
-var
-  mc: TGLBaseMeshConnectivity;
-  sil: TGLSilhouette;
-begin
-  sil := nil;
-  if Assigned(FConnectivity) then
-  begin
-    mc := TGLBaseMeshConnectivity(FConnectivity);
-    mc.CreateSilhouette(silhouetteParameters, sil, True);
-  end
-  else
-  begin
-    mc := TGLBaseMeshConnectivity.CreateFromMesh(Self);
-    try
-      mc.CreateSilhouette(silhouetteParameters, sil, True);
-    finally
-      mc.Free;
-    end;
-  end;
-  Result := sil;
-end;
-
-procedure TGLBaseMesh.BuildSilhouetteConnectivityData;
-var
-  i, j: Integer;
-  mo: TGLMeshObject;
-begin
-  FreeAndNil(FConnectivity);
-  // connectivity data works only on facegroups of TFGVertexIndexList class
-  for i := 0 to MeshObjects.Count - 1 do
-  begin
-    mo := (MeshObjects[i] as TGLMeshObject);
-    if mo.Mode <> momFaceGroups then
-      Exit;
-    for j := 0 to mo.FaceGroups.Count - 1 do
-      if not mo.FaceGroups[j].InheritsFrom(TFGVertexIndexList) then
-        Exit;
-  end;
-  FConnectivity := TGLBaseMeshConnectivity.CreateFromMesh(Self);
-end;
-
-// ------------------
-// ------------------ TGLFreeForm ------------------
-// ------------------
-
-constructor TGLFreeForm.Create(aOwner: TComponent);
-begin
-  inherited;
-  // ObjectStyle := [osDirectDraw];
-  FUseMeshMaterials := True;
-end;
-
-destructor TGLFreeForm.Destroy;
-begin
-  FOctree.Free;
-  inherited Destroy;
-end;
-
-procedure TGLFreeForm.BuildOctree(TreeDepth: Integer = 3);
-var
-  emin, emax: TAffineVector;
-  tl: TGLAffineVectorList;
-begin
-  if not Assigned(FOctree) then // moved here from GetOctree
-    FOctree := TGLOctree.Create;
-
-  GetExtents(emin, emax);
-  tl := MeshObjects.ExtractTriangles;
-  try
-    with Octree do
-    begin
-      DisposeTree;
-      InitializeTree(emin, emax, tl, TreeDepth);
-    end;
-  finally
-    tl.Free;
-  end;
-end;
-
-function TGLFreeForm.OctreeRayCastIntersect(const rayStart, rayVector: TGLVector; intersectPoint: PGLVector = nil;
-  intersectNormal: PGLVector = nil): Boolean;
-var
-  locRayStart, locRayVector: TGLVector;
-begin
-  Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
-  SetVector(locRayStart, AbsoluteToLocal(rayStart));
-  SetVector(locRayVector, AbsoluteToLocal(rayVector));
-  Result := Octree.RayCastIntersect(locRayStart, locRayVector, intersectPoint, intersectNormal);
-  if Result then
-  begin
-    if intersectPoint <> nil then
-      SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
-    if intersectNormal <> nil then
-    begin
-      SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
-      if NormalsOrientation = mnoInvert then
-        NegateVector(intersectNormal^);
-    end;
-  end;
-end;
-
-function TGLFreeForm.OctreePointInMesh(const Point: TGLVector): Boolean;
-const
-  cPointRadiusStep = 10000;
-var
-  rayStart, rayVector, hitPoint, hitNormal: TGLVector;
-  BRad: double;
-  HitCount: Integer;
-  hitDot: double;
-begin
-  Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
-  Result := False;
-
-  // Makes calculations sligthly faster by ignoring cases that are guaranteed
-  // to be outside the object
-  if not PointInObject(Point) then
-    Exit;
-
-  BRad := BoundingSphereRadius;
-
-  // This could be a fixed vector, but a fixed vector could have a systemic
-  // bug on an non-closed mesh, making it fail constantly for one or several
-  // faces.
-  rayVector := VectorMake(2 * random - 1, 2 * random - 1, 2 * random - 1);
-  rayStart := VectorAdd(VectorScale(rayVector, -BRad), Point);
-
-  HitCount := 0;
-
-  while OctreeRayCastIntersect(rayStart, rayVector, @hitPoint, @hitNormal) do
-  begin
-    // Are we past our taget?
-    if VectorDotProduct(rayVector, VectorSubtract(Point, hitPoint)) < 0 then
-    begin
-      Result := HitCount > 0;
-      Exit;
-    end;
-
-    hitDot := VectorDotProduct(hitNormal, rayVector);
-    if hitDot < 0 then
-      Inc(HitCount)
-    else if hitDot > 0 then
-      Dec(HitCount);
-
-    // ditDot = 0 is a tricky special case where the ray is just grazing the
-    // side of a face - this case means that it doesn't necessarily actually
-    // enter the mesh - but it _could_ enter the mesh. If this situation occurs,
-    // we should restart the run using a new rayVector - but this implementation
-    // currently doesn't.
-
-    // Restart the ray slightly beyond the point it hit the previous face. Note
-    // that this step introduces a possible issue with faces that are very close
-    rayStart := VectorAdd(hitPoint, VectorScale(rayVector, BRad / cPointRadiusStep));
-  end;
-end;
-
-function TGLFreeForm.OctreeSphereSweepIntersect(const rayStart, rayVector: TGLVector; const velocity, radius: Single;
-  intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
-var
-  locRayStart, locRayVector: TGLVector;
-begin
-  Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
-  SetVector(locRayStart, AbsoluteToLocal(rayStart));
-  SetVector(locRayVector, AbsoluteToLocal(rayVector));
-  Result := Octree.SphereSweepIntersect(locRayStart, locRayVector, velocity, radius, intersectPoint, intersectNormal);
-  if Result then
-  begin
-    if intersectPoint <> nil then
-      SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
-    if intersectNormal <> nil then
-    begin
-      SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
-      if NormalsOrientation = mnoInvert then
-        NegateVector(intersectNormal^);
-    end;
-  end;
-end;
-
-function TGLFreeForm.OctreeTriangleIntersect(const v1, v2, v3: TAffineVector): Boolean;
-var
-  t1, t2, t3: TAffineVector;
-begin
-  Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
-  SetVector(t1, AbsoluteToLocal(v1));
-  SetVector(t2, AbsoluteToLocal(v2));
-  SetVector(t3, AbsoluteToLocal(v3));
-
-  Result := Octree.TriangleIntersect(t1, t2, t3);
-end;
-
-function TGLFreeForm.OctreeAABBIntersect(const AABB: TAABB; objMatrix, invObjMatrix: TGLMatrix;
-  triangles: TGLAffineVectorList = nil): Boolean;
-var
-  m1to2, m2to1: TGLMatrix;
-begin
-  Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
-
-  // get matrixes needed
-  // object to self
-  MatrixMultiply(objMatrix, InvAbsoluteMatrix, m1to2);
-  // self to object
-  MatrixMultiply(AbsoluteMatrix, invObjMatrix, m2to1);
-
-  Result := Octree.AABBIntersect(aabb, m1to2, m2to1, triangles);
-end;
-
-// ------------------
-// ------------------ TGLActorAnimation ------------------
-// ------------------
-
-constructor TGLActorAnimation.Create(Collection: TCollection);
-begin
-  inherited Create(Collection);
-end;
-
-destructor TGLActorAnimation.Destroy;
-begin
-  with (Collection as TGLActorAnimations).FOwner do
-    if FTargetSmoothAnimation = Self then
-      FTargetSmoothAnimation := nil;
-  inherited Destroy;
-end;
-
-procedure TGLActorAnimation.Assign(Source: TPersistent);
-begin
-  if Source is TGLActorAnimation then
-  begin
-    FName := TGLActorAnimation(Source).FName;
-    FStartFrame := TGLActorAnimation(Source).FStartFrame;
-    FEndFrame := TGLActorAnimation(Source).FEndFrame;
-    FReference := TGLActorAnimation(Source).FReference;
-  end
-  else
-    inherited;
-end;
-
-function TGLActorAnimation.GetDisplayName: string;
-begin
-  Result := Format('%d - %s [%d - %d]', [Index, Name, StartFrame, EndFrame]);
-end;
-
-function TGLActorAnimation.FrameCount: Integer;
-begin
-  case Reference of
-    aarMorph: Result := TGLActorAnimations(Collection).FOwner.MeshObjects.MorphTargetCount;
-    aarSkeleton: Result := TGLActorAnimations(Collection).FOwner.Skeleton.Frames.Count;
-  else
-    Result := 0;
-    Assert(False);
-  end;
-end;
-
-procedure TGLActorAnimation.SetStartFrame(const val: Integer);
-var
-  m: Integer;
-begin
-  if val < 0 then
-    FStartFrame := 0
-  else
-  begin
-    m := FrameCount;
-    if val >= m then
-      FStartFrame := m - 1
-    else
-      FStartFrame := val;
-  end;
-  if FStartFrame > FEndFrame then
-    FEndFrame := FStartFrame;
-end;
-
-procedure TGLActorAnimation.SetEndFrame(const val: Integer);
-var
-  m: Integer;
-begin
-  if val < 0 then
-    FEndFrame := 0
-  else
-  begin
-    m := FrameCount;
-    if val >= m then
-      FEndFrame := m - 1
-    else
-      FEndFrame := val;
-  end;
-  if FStartFrame > FEndFrame then
-    FStartFrame := FEndFrame;
-end;
-
-procedure TGLActorAnimation.SetReference(val: TGLActorAnimationReference);
-begin
-  if val <> FReference then
-  begin
-    FReference := val;
-    StartFrame := StartFrame;
-    EndFrame := EndFrame;
-  end;
-end;
-
-procedure TGLActorAnimation.SetAsString(const val: string);
-var
-  sl: TStringList;
-begin
-  sl := TStringList.Create;
-  try
-    sl.CommaText := val;
-    Assert(sl.Count >= 3);
-    FName := sl[0];
-    FStartFrame := StrToInt(sl[1]);
-    FEndFrame := StrToInt(sl[2]);
-    if sl.Count = 4 then
-    begin
-      if LowerCase(sl[3]) = 'morph' then
-        Reference := aarMorph
-      else if LowerCase(sl[3]) = 'skeleton' then
-        Reference := aarSkeleton
-      else
-        Assert(False);
-    end
-    else
-      Reference := aarMorph;
-  finally
-    sl.Free;
-  end;
-end;
-
-function TGLActorAnimation.GetAsString: string;
-const
-  cAARToString: array [aarMorph .. aarSkeleton] of string = ('morph', 'skeleton');
-begin
-  Result := Format('"%s",%d,%d,%s', [FName, FStartFrame, FEndFrame, cAARToString[reference]]);
-end;
-
-function TGLActorAnimation.OwnerActor: TGLActor;
-begin
-  Result := ((Collection as TGLActorAnimations).GetOwner as TGLActor);
-end;
-
-procedure TGLActorAnimation.MakeSkeletalTranslationStatic;
-begin
-  OwnerActor.Skeleton.MakeSkeletalTranslationStatic(StartFrame, EndFrame);
-end;
-
-procedure TGLActorAnimation.MakeSkeletalRotationDelta;
-begin
-  OwnerActor.Skeleton.MakeSkeletalRotationDelta(StartFrame, EndFrame);
-end;
-
-// ------------------
-// ------------------ TGLActorAnimations ------------------
-// ------------------
-
-constructor TGLActorAnimations.Create(AOwner: TGLActor);
-begin
-  FOwner := AOwner;
-  inherited Create(TGLActorAnimation);
-end;
-
-function TGLActorAnimations.GetOwner: TPersistent;
-begin
-  Result := FOwner;
-end;
-
-procedure TGLActorAnimations.SetItems(Index: Integer; const val: TGLActorAnimation);
-begin
-  inherited Items[index] := val;
-end;
-
-function TGLActorAnimations.GetItems(Index: Integer): TGLActorAnimation;
-begin
-  Result := TGLActorAnimation(inherited Items[index]);
-end;
-
-function TGLActorAnimations.Last: TGLActorAnimation;
-begin
-  if Count > 0 then
-    Result := TGLActorAnimation(inherited Items[Count - 1])
-  else
-    Result := nil;
-end;
-
-function TGLActorAnimations.Add: TGLActorAnimation;
-begin
-  Result := (inherited Add) as TGLActorAnimation;
-end;
-
-function TGLActorAnimations.FindItemID(ID: Integer): TGLActorAnimation;
-begin
-  Result := (inherited FindItemID(ID)) as TGLActorAnimation;
-end;
-
-function TGLActorAnimations.FindName(const aName: string): TGLActorAnimation;
-var
-  i: Integer;
-begin
-  Result := nil;
-  for i := 0 to Count - 1 do
-    if CompareText(Items[i].Name, aName) = 0 then
-    begin
-      Result := Items[i];
-      Break;
-    end;
-end;
-
-function TGLActorAnimations.FindFrame(aFrame: Integer; aReference: TGLActorAnimationReference): TGLActorAnimation;
-var
-  i: Integer;
-begin
-  Result := nil;
-  for i := 0 to Count - 1 do
-    with Items[i] do
-      if (StartFrame <= aFrame) and (EndFrame >= aFrame) and (Reference = aReference) then
-      begin
-        Result := Items[i];
-        Break;
-      end;
-end;
-
-procedure TGLActorAnimations.SetToStrings(aStrings: TStrings);
-
-var
-  i: Integer;
-begin
-  with aStrings do
-  begin
-    BeginUpdate;
-    Clear;
-    for i := 0 to Self.Count - 1 do
-      Add(Self.Items[i].Name);
-    EndUpdate;
-  end;
-end;
-
-procedure TGLActorAnimations.SaveToStream(aStream: TStream);
-var
-  i: Integer;
-begin
-  WriteCRLFString(aStream, cAAFHeader);
-  WriteCRLFString(aStream, IntToStr(Count));
-  for i := 0 to Count - 1 do
-    WriteCRLFString(aStream, Items[i].AsString);
-end;
-
-procedure TGLActorAnimations.LoadFromStream(aStream: TStream);
-var
-  i, n: Integer;
-begin
-  Clear;
-  if ReadCRLFString(aStream) <> cAAFHeader then
-    Assert(False);
-  n := StrToInt(ReadCRLFString(aStream));
-  for i := 0 to n - 1 do
-    Add.AsString := ReadCRLFString(aStream);
-end;
-
-procedure TGLActorAnimations.SaveToFile(const fileName: string);
-var
-  fs: TStream;
-begin
-  fs := TFileStream.Create(fileName, fmCreate);
-  try
-    SaveToStream(fs);
-  finally
-    fs.Free;
-  end;
-end;
-
-procedure TGLActorAnimations.LoadFromFile(const fileName: string);
-var
-  fs: TStream;
-begin
-  try
-    fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyWrite);
-  finally
-    fs.Free;
-  end;
-end;
-
-// ------------------
-// ------------------ TGLBaseAnimationControler ------------------
-// ------------------
-
-constructor TGLBaseAnimationControler.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  FEnabled := True;
-end;
-
-destructor TGLBaseAnimationControler.Destroy;
-begin
-  SetActor(nil);
-  inherited Destroy;
-end;
-
-procedure TGLBaseAnimationControler.Notification(AComponent: TComponent; Operation: TOperation);
-begin
-  if (AComponent = FActor) and (Operation = opRemove) then
-    SetActor(nil);
-  inherited;
-end;
-
-procedure TGLBaseAnimationControler.DoChange;
-begin
-  if Assigned(FActor) then
-    FActor.NotifyChange(Self);
-end;
-
-procedure TGLBaseAnimationControler.SetEnabled(const val: Boolean);
-begin
-  if val <> FEnabled then
-  begin
-    FEnabled := val;
-    if Assigned(FActor) then
-      DoChange;
-  end;
-end;
-
-procedure TGLBaseAnimationControler.SetActor(const val: TGLActor);
-begin
-  if FActor <> val then
-  begin
-    if Assigned(FActor) then
-      FActor.UnRegisterControler(Self);
-    FActor := val;
-    if Assigned(FActor) then
-    begin
-      FActor.RegisterControler(Self);
-      DoChange;
-    end;
-  end;
-end;
-
-function TGLBaseAnimationControler.Apply(var lerpInfo: TGLBlendedLerpInfo): Boolean;
-begin
-  // virtual
-  Result := False;
-end;
-
-// ------------------
-// ------------------ TGLAnimationControler ------------------
-// ------------------
-
-procedure TGLAnimationControler.DoChange;
-begin
-  if AnimationName <> '' then
-    inherited;
-end;
-
-procedure TGLAnimationControler.SetAnimationName(const val: TGLActorAnimationName);
-begin
-  if FAnimationName <> val then
-  begin
-    FAnimationName := val;
-    DoChange;
-  end;
-end;
-
-procedure TGLAnimationControler.SetRatio(const val: Single);
-begin
-  if FRatio <> val then
-  begin
-    FRatio := ClampValue(val, 0, 1);
-    DoChange;
-  end;
-end;
-
-function TGLAnimationControler.Apply(var lerpInfo: TGLBlendedLerpInfo): Boolean;
-var
-  anim: TGLActorAnimation;
-  baseDelta: Integer;
-begin
-  if not Enabled then
-  begin
-    Result := False;
-    Exit;
-  end;
-
-  anim := Actor.Animations.FindName(AnimationName);
-  Result := (anim <> nil);
-  if not Result then
-    Exit;
-
-  with lerpInfo do
-  begin
-    if Ratio = 0 then
-    begin
-      frameIndex1 := anim.StartFrame;
-      frameIndex2 := frameIndex1;
-      lerpFactor := 0;
-    end
-    else if Ratio = 1 then
-    begin
-      frameIndex1 := anim.EndFrame;
-      frameIndex2 := frameIndex1;
-      lerpFactor := 0;
-    end
-    else
-    begin
-      baseDelta := anim.EndFrame - anim.StartFrame;
-      lerpFactor := anim.StartFrame + baseDelta * Ratio;
-      frameIndex1 := Trunc(lerpFactor);
-      frameIndex2 := frameIndex1 + 1;
-      lerpFactor := Frac(lerpFactor);
-    end;
-    weight := 1;
-    externalRotations := nil;
-    externalQuaternions := nil;
-  end;
-end;
-
-// ------------------
-// ------------------ TGLActor ------------------
-// ------------------
-
-constructor TGLActor.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  ObjectStyle := ObjectStyle + [osDirectDraw];
-  FFrameInterpolation := afpLinear;
-  FAnimationMode := aamNone;
-  FInterval := 100; // 10 animation frames per second
-  FAnimations := TGLActorAnimations.Create(Self);
-  FControlers := nil; // created on request
-  FOptions := cDefaultGLActorOptions;
-end;
-
-destructor TGLActor.Destroy;
-begin
-  inherited Destroy;
-  FControlers.Free;
-  FAnimations.Free;
-end;
-
-procedure TGLActor.Assign(Source: TPersistent);
-begin
-  inherited Assign(Source);
-  if Source is TGLActor then
-  begin
-    FAnimations.Assign(TGLActor(Source).FAnimations);
-    FAnimationMode := TGLActor(Source).FAnimationMode;
-    Synchronize(TGLActor(Source));
-  end;
-end;
-
-procedure TGLActor.RegisterControler(aControler: TGLBaseAnimationControler);
-begin
-  if not Assigned(FControlers) then
-    FControlers := TList.Create;
-  FControlers.Add(aControler);
-  FreeNotification(aControler);
-end;
-
-procedure TGLActor.UnRegisterControler(aControler: TGLBaseAnimationControler);
-begin
-  Assert(Assigned(FControlers));
-  FControlers.Remove(aControler);
-  RemoveFreeNotification(aControler);
-  if FControlers.Count = 0 then
-    FreeAndNil(FControlers);
-end;
-
-procedure TGLActor.SetCurrentFrame(val: Integer);
-begin
-  if val <> CurrentFrame then
-  begin
-    if val > FrameCount - 1 then
-      FCurrentFrame := FrameCount - 1
-    else if val < 0 then
-      FCurrentFrame := 0
-    else
-      FCurrentFrame := val;
-    FCurrentFrameDelta := 0;
-    case AnimationMode of
-      aamPlayOnce: if (CurrentFrame = EndFrame) and (FTargetSmoothAnimation =
-        nil) then
-          FAnimationMode := aamNone;
-      aamBounceForward: if CurrentFrame = EndFrame then
-          FAnimationMode := aamBounceBackward;
-      aamBounceBackward: if CurrentFrame = StartFrame then
-          FAnimationMode := aamBounceForward;
-    end;
-    StructureChanged;
-    if Assigned(FOnFrameChanged) then
-      FOnFrameChanged(Self);
-  end;
-end;
-
-procedure TGLActor.SetCurrentFrameDirect(const Value: Integer);
-begin
-  FCurrentFrame := Value;
-end;
-
-procedure TGLActor.SetStartFrame(val: Integer);
-begin
-  if (val >= 0) and (val < FrameCount) and (val <> StartFrame) then
-    FStartFrame := val;
-  if EndFrame < StartFrame then
-    FEndFrame := FStartFrame;
-  if CurrentFrame < StartFrame then
-    CurrentFrame := FStartFrame;
-end;
-
-procedure TGLActor.SetEndFrame(val: Integer);
-begin
-  if (val >= 0) and (val < FrameCount) and (val <> EndFrame) then
-    FEndFrame := val;
-  if CurrentFrame > EndFrame then
-    CurrentFrame := FEndFrame;
-end;
-
-procedure TGLActor.SetReference(val: TGLActorAnimationReference);
-begin
-  if val <> Reference then
-  begin
-    FReference := val;
-    StartFrame := StartFrame;
-    EndFrame := EndFrame;
-    CurrentFrame := CurrentFrame;
-    StructureChanged;
-  end;
-end;
-
-procedure TGLActor.SetAnimations(const val: TGLActorAnimations);
-begin
-  FAnimations.Assign(val);
-end;
-
-function TGLActor.StoreAnimations: Boolean;
-begin
-  Result := (FAnimations.Count > 0);
-end;
-
-procedure TGLActor.SetOptions(const val: TGLActorOptions);
-begin
-  if val <> FOptions then
-  begin
-    FOptions := val;
-    StructureChanged;
-  end;
-end;
-
-function TGLActor.NextFrameIndex: Integer;
-begin
-  case AnimationMode of
-    aamLoop, aamBounceForward:
-      begin
-        if FTargetSmoothAnimation <> nil then
-          Result := FTargetSmoothAnimation.StartFrame
-        else
-        begin
-          Result := CurrentFrame + 1;
-          if Result > EndFrame then
-          begin
-            Result := StartFrame + (Result - EndFrame - 1);
-            if Result > EndFrame then
-              Result := EndFrame;
-          end;
-        end;
-      end;
-    aamNone, aamPlayOnce:
-      begin
-        if FTargetSmoothAnimation <> nil then
-          Result := FTargetSmoothAnimation.StartFrame
-        else
-        begin
-          Result := CurrentFrame + 1;
-          if Result > EndFrame then
-            Result := EndFrame;
-        end;
-      end;
-    aamBounceBackward, aamLoopBackward:
-      begin
-        if FTargetSmoothAnimation <> nil then
-          Result := FTargetSmoothAnimation.StartFrame
-        else
-        begin
-          Result := CurrentFrame - 1;
-          if Result < StartFrame then
-          begin
-            Result := EndFrame - (StartFrame - Result - 1);
-            if Result < StartFrame then
-              Result := StartFrame;
-          end;
-        end;
-      end;
-    aamExternal: Result := CurrentFrame; // Do nothing
-  else
-    Result := CurrentFrame;
-    Assert(False);
-  end;
-end;
-
-procedure TGLActor.NextFrame(nbSteps: Integer = 1);
-var
-  n: Integer;
-begin
-  n := nbSteps;
-  while n > 0 do
-  begin
-    CurrentFrame := NextFrameIndex;
-    Dec(n);
-    if Assigned(FOnEndFrameReached) and (CurrentFrame = EndFrame) then
-      FOnEndFrameReached(Self);
-    if Assigned(FOnStartFrameReached) and (CurrentFrame = StartFrame) then
-      FOnStartFrameReached(Self);
-  end;
-end;
-
-procedure TGLActor.PrevFrame(nbSteps: Integer = 1);
-var
-  Value: Integer;
-begin
-  Value := FCurrentFrame - nbSteps;
-  if Value < FStartFrame then
-  begin
-    Value := FEndFrame - (FStartFrame - Value);
-    if Value < FStartFrame then
-      Value := FStartFrame;
-  end;
-  CurrentFrame := Value;
-end;
-
-procedure TGLActor.DoAnimate();
-var
-  i, k: Integer;
-  nextFrameIdx: Integer;
-  lerpInfos: array of TGLBlendedLerpInfo;
-begin
-  nextFrameIdx := NextFrameIndex;
-  case Reference of
-    aarMorph: if nextFrameIdx >= 0 then
-      begin
-        case FrameInterpolation of
-          afpLinear:
-            MeshObjects.Lerp(CurrentFrame, nextFrameIdx, CurrentFrameDelta)
-        else
-          MeshObjects.MorphTo(CurrentFrame);
-        end;
-      end;
-    aarSkeleton: if Skeleton.Frames.Count > 0 then
-      begin
-        if Assigned(FControlers) and (AnimationMode <> aamExternal) then
-        begin
-          // Blended Skeletal Lerping
-          SetLength(lerpInfos, FControlers.Count + 1);
-          if nextFrameIdx >= 0 then
-          begin
-            case FrameInterpolation of
-              afpLinear: with lerpInfos[0] do
-                begin
-                  frameIndex1 := CurrentFrame;
-                  frameIndex2 := nextFrameIdx;
-                  lerpFactor := CurrentFrameDelta;
-                  weight := 1;
-                end;
-            else
-              with lerpInfos[0] do
-              begin
-                frameIndex1 := CurrentFrame;
-                frameIndex2 := CurrentFrame;
-                lerpFactor := 0;
-                weight := 1;
-              end;
-            end;
-          end
-          else
-          begin
-            with lerpInfos[0] do
-            begin
-              frameIndex1 := CurrentFrame;
-              frameIndex2 := CurrentFrame;
-              lerpFactor := 0;
-              weight := 1;
-            end;
-          end;
-          k := 1;
-          for i := 0 to FControlers.Count - 1 do
-            if TGLBaseAnimationControler(FControlers[i]).Apply(lerpInfos[k])
-              then
-              Inc(k);
-          SetLength(lerpInfos, k);
-          Skeleton.BlendedLerps(lerpInfos);
-        end
-        else if (nextFrameIdx >= 0) and (AnimationMode <> aamExternal) then
-        begin
-          // Single Skeletal Lerp
-          case FrameInterpolation of
-            afpLinear:
-              Skeleton.Lerp(CurrentFrame, nextFrameIdx, CurrentFrameDelta);
-          else
-            Skeleton.SetCurrentFrame(Skeleton.Frames[CurrentFrame]);
-          end;
-        end;
-        Skeleton.MorphMesh(aoSkeletonNormalizeNormals in Options);
-      end;
-    aarNone: ; // do nothing
-  end;
-end;
-
-procedure TGLActor.BuildList(var rci: TGLRenderContextInfo);
-begin
-  DoAnimate;
-  inherited;
-  if OverlaySkeleton then
-  begin
-    rci.GLStates.Disable(stDepthTest);
-    Skeleton.RootBones.BuildList(rci);
-  end;
-end;
-
-procedure TGLActor.PrepareMesh;
-begin
-  FStartFrame := 0;
-  FEndFrame := FrameCount - 1;
-  FCurrentFrame := 0;
-  if Assigned(FOnFrameChanged) then
-    FOnFrameChanged(Self);
-  inherited;
-end;
-
-procedure TGLActor.PrepareBuildList(var mrci: TGLRenderContextInfo);
-begin
-  // no preparation needed for actors, they don't use buildlists
-end;
-
-function TGLActor.FrameCount: Integer;
-begin
-  case Reference of
-    aarMorph:
-      Result := MeshObjects.MorphTargetCount;
-    aarSkeleton:
-      Result := Skeleton.Frames.Count;
-    aarNone:
-      Result := 0;
-  else
-    Result := 0;
-    Assert(False);
-  end;
-end;
-
-procedure TGLActor.DoProgress(const progressTime: TGLProgressTimes);
-var
-  fDelta: Single;
-begin
-  inherited;
-  if (AnimationMode <> aamNone) and (Interval > 0) then
-  begin
-    if (StartFrame <> EndFrame) and (FrameCount > 1) then
-    begin
-      FCurrentFrameDelta := FCurrentFrameDelta + (progressTime.deltaTime * 1000) / FInterval;
-      if FCurrentFrameDelta > 1 then
-      begin
-        if Assigned(FTargetSmoothAnimation) then
-        begin
-          SwitchToAnimation(FTargetSmoothAnimation);
-          FTargetSmoothAnimation := nil;
-        end;
-        // we need to step on
-        fDelta := Frac(FCurrentFrameDelta);
-        NextFrame(Trunc(FCurrentFrameDelta));
-        FCurrentFrameDelta := fDelta;
-        StructureChanged;
-      end
-      else if FrameInterpolation <> afpNone then
-        StructureChanged;
-    end;
-  end;
-end;
-
-procedure TGLActor.LoadFromStream(const FileName: string; aStream: TStream);
-begin
-  if FileName <> '' then
-  begin
-    Animations.Clear;
-    inherited LoadFromStream(FileName, aStream);
-  end;
-end;
-
-procedure TGLActor.SwitchToAnimation(const AnimationName: string; smooth: Boolean = False);
-begin
-  SwitchToAnimation(Animations.FindName(AnimationName), smooth);
-end;
-
-procedure TGLActor.SwitchToAnimation(animationIndex: Integer; smooth: Boolean = False);
-begin
-  if (animationIndex >= 0) and (animationIndex < Animations.Count) then
-    SwitchToAnimation(Animations[animationIndex], smooth);
-end;
-
-procedure TGLActor.SwitchToAnimation(anAnimation: TGLActorAnimation; smooth: Boolean = False);
-begin
-  if Assigned(anAnimation) then
-  begin
-    if smooth then
-    begin
-      FTargetSmoothAnimation := anAnimation;
-      FCurrentFrameDelta := 0;
-    end
-    else
-    begin
-      Reference := anAnimation.Reference;
-      StartFrame := anAnimation.StartFrame;
-      EndFrame := anAnimation.EndFrame;
-      CurrentFrame := StartFrame;
-    end;
-  end;
-end;
-
-function TGLActor.CurrentAnimation: string;
-var
-  aa: TGLActorAnimation;
-begin
-  aa := Animations.FindFrame(CurrentFrame, Reference);
-  if Assigned(aa) then
-    Result := aa.Name
-  else
-    Result := '';
-end;
-
-procedure TGLActor.Synchronize(referenceActor: TGLActor);
-begin
-  if Assigned(referenceActor) then
-  begin
-    if referenceActor.StartFrame < FrameCount then
-      FStartFrame := referenceActor.StartFrame;
-    if referenceActor.EndFrame < FrameCount then
-      FEndFrame := referenceActor.EndFrame;
-    FReference := referenceActor.Reference;
-    if referenceActor.CurrentFrame < FrameCount then
-      FCurrentFrame := referenceActor.CurrentFrame;
-    FCurrentFrameDelta := referenceActor.CurrentFrameDelta;
-    FAnimationMode := referenceActor.AnimationMode;
-    FFrameInterpolation := referenceActor.FrameInterpolation;
-    if referenceActor.FTargetSmoothAnimation <> nil then
-      FTargetSmoothAnimation := Animations.FindName(referenceActor.FTargetSmoothAnimation.Name)
-    else
-      FTargetSmoothAnimation := nil;
-    if (Skeleton.Frames.Count > 0) and (referenceActor.Skeleton.Frames.Count > 0) then
-      Skeleton.Synchronize(referenceActor.Skeleton);
-  end;
-end;
-
-function TGLActor.isSwitchingAnimation: boolean;
-begin
-  result := FTargetSmoothAnimation <> nil;
-end;
-
-// ------------------------------------------------------------------
-initialization
-// ------------------------------------------------------------------
-
-RegisterVectorFileFormat('glsm', 'GLScene Mesh', TGLSMVectorFile);
-
-  RegisterClasses(
-    [TGLFreeForm, TGLActor, TGLSkeleton, TGLSkeletonFrame, TGLSkeletonBone,
-    TGLSkeletonMeshObject, TGLMeshObject, TGLSkeletonFrameList, TGLMeshMorphTarget,
-    TGLMorphableMeshObject, TGLFaceGroup, TFGVertexIndexList,
-    TFGVertexNormalTexIndexList, TGLAnimationControler,
-    TFGIndexTexCoordList, TGLSkeletonCollider, TGLSkeletonColliderList]);
-
-finalization
-
-FreeAndNil(vVectorFileFormats);
-
-end.
-