/*****************************************************************
 * CodeName: VJProjector.Net
 * Copyright: Virtual Media Systems, S.L. 2004
 * Assembly: LibGFX
 * Type: C# Source Code
 * Version: 1.0
 * Description: ASE Scene Loader
 * 
 * Revisions
 * ------------------------------------------------
 * [F] 25/03/2004, Jcl - Shaping up
 * 
 *****************************************************************/
 
using System;
using System.IO;
using System.Globalization;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
using VJProjector.GFX.Immerse.Math;
using VJProjector.GFX.Immerse.Meshes;
using VJProjector.GFX.Immerse.Types;
using VJProjector.GFX.Immerse.Materials;
using VJProjector.GFX.Immerse.Collections;
using VJProjector.GFX.Immerse.GPU;
using VJProjector.GFX.Immerse.Render;
 
namespace VJProjector.GFX.Immerse.SceneImporters
{
  using Math = System.Math;
 
	public class ReadASE : ISceneImporter
	{
    private static NumberFormatInfo provider;
 
    static ReadASE() 
    {
      provider = new NumberFormatInfo();
      provider.NumberDecimalSeparator = ".";
      provider.NumberGroupSeparator = ",";
      provider.NumberGroupSizes = new int[ ] { 3 };
    }
 
    private string [] GetTokens(string st) 
    {
      char [] separators = { '\t',' '};
      char [] cArr = st.ToCharArray();
      char [] cArrRes = new char[st.Length+1];
      for(int i = 0; i < st.Length-1; i++) cArrRes[i] = (char)0;
      //Trace.WriteLine(st);
 
      bool inString = false;
      int idx = 0;
      for(int i = 0; i < st.Length; i++) 
      {
        if(cArr[i] == '"' && !inString) 
        {
          inString = true;
        } 
        else if(cArr[i] == '"' && inString) // If next char is ", continue the string
        {
          inString = false;
        }
        if(cArr[i] == ' ' && inString) 
        {
          cArr[i]=(char)255; // Temp char for splitting ' '
        }
        cArrRes[idx++] = cArr[i];       
      }
      string res = new string(cArrRes);
      res = res.Substring(0, res.Length-1); // Remove the trailing \0
      res = res.Trim();
      string [] tokens = res.Split(separators);
      int numRealTokens = 0;
      for(int i = 0; i < tokens.Length; i++) 
      {
        tokens[i] = tokens[i].Replace((char)255,' ');
        tokens[i] = tokens[i].Trim();
        if(tokens[i].Length>0)
          numRealTokens++;
      }
      // Remove empty tokens
      string [] retTokens = new string[numRealTokens];
      numRealTokens = 0;
      for(int i = 0; i < tokens.Length; i++) 
      {
        if(tokens[i].Length>0) retTokens[numRealTokens++]=tokens[i];
      }
      return retTokens;
    }
    private static string GetQuotedString(string quotedString) 
    {
      if(quotedString[0]=='"' && quotedString[quotedString.Length-1]=='"')
        return quotedString.Substring(1,quotedString.Length-2);
      return quotedString;
    }
 
    private static bool IsGroupStart(string [] tokens) 
    {
      if(tokens[tokens.Length-1] == "{")
        return true;
      return false;
    }
    private static bool IsGroupEnd(string [] tokens) 
    {
      if(tokens[tokens.Length-1] == "}")
        return true;
      return false;
    }
    private static string GetLineToken(string [] tokens) 
    {
      return tokens[0].Substring(1,tokens[0].Length-1).ToUpper(); // Remove the *
    }
 
    private string GetString(string [] tokens, int position) 
    {
      return GetQuotedString(tokens[position+1]);
    }
    private string GetNonQuotedString(string [] tokens, int position) 
    {
      return tokens[position+1];
    }
    private int GetInteger(string [] tokens, int position) 
    {
      return Convert.ToInt32(tokens[position+1],provider);
    }
    private float GetFloat(string [] tokens, int position) 
    {
      return Convert.ToSingle(tokens[position+1],provider);
    }    
    private Vector GetXYZVector(string [] tokens) 
    {
      return GetXYZVector(tokens, 0);
    }
    private Vector GetXYZVector(string [] tokens, int offset) 
    {
      if(tokens.Length-offset < 4)
        return new Vector(0,0,0);
      return new Vector(Convert.ToSingle(tokens[1+offset],provider),Convert.ToSingle(tokens[2+offset],provider),Convert.ToSingle(tokens[3+offset],provider));
    }
    private TexCoordsEX GetUVWCoords(string [] tokens) 
    {
      return GetUVWCoords(tokens, 0);
    }
    private TexCoordsEX GetUVWCoords(string [] tokens, int offset) 
    {
      if(tokens.Length-offset < 2) 
      {
        return new TexCoordsEX(GetFloat(tokens, offset+0),0,0);
      }
      if(tokens.Length-offset < 3)
        return new TexCoordsEX(GetFloat(tokens, offset+0),1-GetFloat(tokens, offset+1),0);
 
      return new TexCoordsEX(GetFloat(tokens, offset+0),1-GetFloat(tokens, offset+1),GetFloat(tokens, offset+2));
    }
    private Quaternion GetQuaternion(string [] tokens) 
    {
      if(tokens.Length < 5) return new Quaternion(0,0,0,0);
      return new Quaternion(Convert.ToSingle(tokens[1],provider),Convert.ToSingle(tokens[2],provider),Convert.ToSingle(tokens[3],provider),Convert.ToSingle(tokens[1],provider));
    }
    private ColorEX GetColorEX(string [] tokens) 
    {
      bool useAlpha = false;
      if(tokens.Length < 4)
        return new ColorEX(0,0,0,0);
      if(tokens.Length > 4)
        useAlpha = true;
      return new ColorEX(Convert.ToSingle(tokens[1],provider),Convert.ToSingle(tokens[2],provider),Convert.ToSingle(tokens[3],provider),useAlpha?Convert.ToSingle(tokens[4],provider):1);
    }
 
    private static Vector MaxToOpenGL(Vector v) 
    {
      Vector r = v.Swizzle("xzy");
      r.Z*=-1;
      return r;
    }
    private static Vector MaxAngleToOpenGL(Vector v) 
    {
      Vector r = v.Swizzle("xzy");
      r.Z*=-1;
      return r;
    }
 
    private bool GetFace(string [] tokens, out int faceNum, out int A, out int B, out int C, out int AB, out int BC, out int CA, out int SmoothGroup, out int MatlID) 
    {
      faceNum=A=B=C=AB=BC=CA=SmoothGroup=MatlID=0;
      if(tokens[0]!="*MESH_FACE") return false;
      string fnSt = GetString(tokens, 0);
      fnSt = fnSt.Substring(0, fnSt.Length-1); // Remove the ':'
      faceNum = Convert.ToInt32(fnSt, provider);
      A = GetInteger(tokens, 2);
      B = GetInteger(tokens, 4);
      C = GetInteger(tokens, 6);
      AB = 1;
      BC = 1;
      CA = 1;
      SmoothGroup = 0;
      MatlID = 0;
      int tokenBase = 7;
      while(tokenBase < tokens.Length-1) 
      {
        if(GetString(tokens, tokenBase) == "AB:") // It has edges
        {
          AB = GetInteger(tokens, tokenBase+1);
          BC = GetInteger(tokens, tokenBase+3);
          BC = GetInteger(tokens, tokenBase+5);
          tokenBase+=6;
        }
/*        else if(GetString(tokens, tokenBase) == "*MESH_SMOOTHING") // Smoothing
        {
          string st = GetString(tokens, tokenBase+1);;
          if(st.IndexOf(",")>=0)
            SmoothGroup = Convert.ToInt32(st.Substring(0,st.IndexOf(",")), provider);
          else
            SmoothGroup = Convert.ToInt32(st, provider);
          tokenBase+=2;
        }*/
        else if(GetString(tokens, tokenBase) == "*MESH_MTLID")  // Material ID
        {
          MatlID = GetInteger(tokens, tokenBase+1);
          tokenBase+=2;
        }
        else
        {
          tokenBase++; // Don't let an infinite loop due to non-implemented stuff
        }
      }
      return true;
    }
 
    private Scene Read(StreamReader br) 
    {
      Scene scn = new Scene();
      Stack currentTree = new Stack();
      string currentBlock = @"\";
      string currentPath = @"\";
      string blockRoot = @"\";
 
      MaterialCollection materials = new MaterialCollection();
      IRenderableCollection meshes = new IRenderableCollection();
      meshes.Clear();
      materials.Clear();
      Material currentMaterial = null;
      Mesh currentMesh = null;
      Hashtable materialIDs = new Hashtable();
 
      Quaternion scaleTemp = new Quaternion();
      Vector quatAxisTemp = Vector.Unit;
      float quatAngleTemp = 0;
 
      int stageCount=-1;
 
      int currentDefType = 0;
 
      Matrix rm = Matrix.Identity;
      ColorEX [] vertexColors = new ColorEX[1];
 
      Texture tmpTexture = null;
      Bmp tmpBitmap = null;
      AnimationKey lastKey = null;
 
      // Start reading out
      bool done = false;
      int lineCount = 0;
      while(!done) 
      {
        string str = br.ReadLine();
        if(str==null) break;
        string [] toks = GetTokens(str);
        lineCount++;        
        if(IsGroupEnd(toks)) 
        {
          Trace.Unindent();
          Trace.WriteLine("<<< " + currentBlock);
          if(currentBlock == "GEOMOBJECT")
            currentDefType = 0;
 
          currentTree.Pop();
          if(currentTree.Count == 0)
          {
            currentPath = @"\";
            currentBlock = @"\";
            blockRoot = @"\";
          }
          else
          {
            if(currentTree.Count>1) 
            {
              currentPath = currentPath.Substring(0,currentPath.LastIndexOf(@"\"));
              currentBlock = currentPath.Substring(currentPath.LastIndexOf(@"\")+1);
              blockRoot = currentPath.Substring(0,currentPath.IndexOf(@"\"));
            }
            else
            {
              currentPath = blockRoot;
              currentBlock = currentPath;
              blockRoot = currentPath;
            }
          }            
        } 
        else 
        {
          bool startGroup = false;
          string st = GetLineToken(toks);
          if(IsGroupStart(toks)) 
          {
            currentTree.Push(toks[0]);
            if(currentTree.Count == 1) 
            {
              currentPath = st;
              currentBlock = st;
              blockRoot = st;
            } 
            else 
            {
              currentPath += @"\" + st;
              currentBlock = st;
            }
            Trace.WriteLine(">>> " + currentBlock);
            Trace.Indent();
            startGroup = true;
          }
          /* SCENE BLOCK */
          /*-------------*/
          if(currentBlock == "SCENE")
          {
            if(st == "SCENE_FIRSTFRAME") 
            {
              scn.FirstFrame = GetInteger(toks, 0);
            }
            else if(st == "SCENE_LASTFRAME") 
            {
              scn.LastFrame = GetInteger(toks, 0);
            }
            else if(st == "SCENE_TICKSPERFRAME") 
            {
              scn.TicksPerFrame = GetInteger(toks, 0);
            }
            else if(st == "SCENE_FRAMESPEED") 
            {
              scn.FrameSpeed = GetInteger(toks, 0);
            }
            else if(st == "SCENE_BACKGROUND_STATIC") 
            {
              scn.BackgroundColor = GetColorEX(toks);
            }
            else if(st == "SCENE_AMBIENT_STATIC") 
            {
              scn.AmbientColor = GetColorEX(toks);
            }
          }
            /* MATERIALS */
            /*-----------*/
          else if(st == "MATERIAL_COUNT" && blockRoot == "MATERIAL_LIST") 
          {
            materials = new MaterialCollection(GetInteger(toks, 0));
          }
          else if(st == "MATERIAL" && startGroup && blockRoot == "MATERIAL_LIST") 
          {
            Material m = new Material();
            materials.Add(m);
            currentMaterial = m;
            materialIDs[GetInteger(toks, 0)] = m;
            stageCount = -1;
          }
          else if(blockRoot == "MATERIAL_LIST") 
          {
            if(st == "MATERIAL_NAME") 
            {
              currentMaterial.Name = GetString(toks, 0);
            }
            else if(st == "MATERIAL_AMBIENT") 
            {
              currentMaterial.AmbientBack = currentMaterial.AmbientFront = GetColorEX(toks);
            }
            else if(st == "MATERIAL_DIFFUSE")
            {
              currentMaterial.DiffuseBack = currentMaterial.DiffuseFront = GetColorEX(toks);
            }
            else if(st == "MATERIAL_SPECULAR")
            {
              currentMaterial.SpecularBack = currentMaterial.SpecularFront = GetColorEX(toks);
            }
            else if(st == "MATERIAL_SHINE")
            {
              float f = GetFloat(toks, 0);
              currentMaterial.ShininessFront = 128-f*128;
              currentMaterial.ShininessBack = 128-f*128;
            }
            else if(st == "MATERIAL_SHINESTRENGTH")
            {
              float f = GetFloat(toks, 0);
              //              currentMaterial.ShininessFront *= 128-f*128;
              //              currentMaterial.ShininessBack *= 128-f*128;
            }
            else if(st == "MATERIAL_TRANSPARENCY")
            {
              //currentMaterial.DiffuseBack.A = currentMaterial.DiffuseFront.A = GetFloat(toks, 0);
            }
            else if(st == "MATERIAL_WIRESIZE")
            {
              // Not implemented
            }
            else if(st == "MATERIAL_SELFILLUM")
            {
              // Not implemented
            }
 
            if(st == "MAP_DIFFUSE"
              ||st == "MAP_REFLECT"
              ||currentBlock == "MAP_GENERIC"
              && startGroup) 
            {
              stageCount++;
              tmpTexture = new Texture("ASEtmp", null);
              tmpBitmap = null;
            }
            if(currentBlock == "MAP_DIFFUSE"
              ||currentBlock == "MAP_REFLECT"
              ||currentBlock == "MAP_GENERIC") 
            {
              if(st == "MAP_CLASS") 
              {
                string bmclass = GetString(toks,0);
                if(bmclass == "Bitmap") 
                {                  
                  tmpBitmap = new Bmp(); 
                }
              }
              if(st == "MAP_NAME") 
              {
                tmpTexture.Name = GetString(toks,0);
              }
              if(st == "BITMAP") 
              {
                int tID = 0;
                try 
                {
                  tmpBitmap.LoadFromFile(GetString(toks, 0));
                  tmpBitmap.UsesMipmaps = true;
                  tmpBitmap.TileType[0] = TextureTileTypes.ClampToEdge;
                  tmpBitmap.TileType[1] = TextureTileTypes.ClampToEdge;
                  tmpBitmap.MinFilter = TextureFilter.LinearMipmapLinear;
                  tmpBitmap.MagFilter = TextureFilter.LinearMipmapLinear;
                  tmpBitmap.InitializeOnHardware(ref tID);
                  tmpTexture = new Texture(tmpTexture.Name, tmpBitmap);
                } 
                catch 
                {
                  MessageBox.Show("Can't open bitmap: " + GetString(toks, 0),"Error");
                  Trace.Unindent();
                  tmpTexture = null;
                  tmpBitmap = null;
                }
              }
              if(st == "MAP_TYPE" && tmpTexture!=null) 
              {
                string s = GetNonQuotedString(toks, 0);
                if(s == "Screen") 
                {
                  currentMaterial.Stages[stageCount].SetDiffuseMap(tmpTexture);
                }
                else if(s == "Spherical") 
                {
                  currentMaterial.Stages[stageCount].SetReflectionMap(tmpTexture,(currentBlock != "MAP_REFLECT")?CombineTypes.Modulate:CombineTypes.Add);
                }
              }
            }
          }
            /* MESHES */
            /*--------*/
          else if(startGroup && currentBlock == "GEOMOBJECT") 
          {
            Mesh m = new Mesh();
            meshes.Add(m);
            currentMesh = m; 
            currentMesh.NumTexCoordLayers = 0;
            quatAxisTemp = new Vector(0,0,0);
            quatAngleTemp = 0;
            rm = Matrix.Identity;
            currentDefType = 1;
            //Trace.WriteLine("ASEImport: New Mesh Created");
          }
          else if(currentDefType == 1) // It's a Mesh (GEOMOBJECT)
          {
            if(st == "NODE_NAME") 
            {
              currentMesh.Name = GetString(toks, 0);
              //Trace.WriteLine(String.Format("ASEImport: Node Name: '{0}'", currentMesh.Name));
            }
            else if (st == "NODE_PARENT") 
            {
              string pName = GetString(toks, 0);
              foreach(INode n in meshes) 
              {
                if(n.Name == pName) 
                {
                  currentMesh.Parent = n;
                }
              }
            }
            else if(st == "MATERIAL_REF") 
            {
              int MtlID = GetInteger(toks, 0);
              if(materialIDs[MtlID]!=null)
                currentMesh.Material = (Material)materialIDs[MtlID];
            }
            else if(currentBlock == "NODE_TM") 
            {
              if(st == "TM_POS") 
              {
                Vector v = MaxToOpenGL(GetXYZVector(toks));
                currentMesh.PRS.Position = v;
                //Trace.WriteLine(String.Format("ASEImport: Position: '{0}'", v.ToString()));
              }
              else if(st == "TM_ROTAXIS") 
              {
                quatAxisTemp = MaxToOpenGL(GetXYZVector(toks));
              }
              else if(st == "TM_ROTANGLE") 
              {
                quatAngleTemp = -GetFloat(toks, 0);
                currentMesh.PRS.Rotation = Quaternion.FromAngleAndAxis(quatAngleTemp, quatAxisTemp);
                //Trace.WriteLine(String.Format("ASEImport: Rotation: '{0}',{1}", quatAngleTemp,quatAxisTemp.ToString()));
                //Trace.WriteLine(String.Format("ASEImport: Rotation Quaternion: '{0}'", currentMesh.PRS.Rotation.ToString()));
              }
              else if(st == "TM_SCALE") 
              {
                Vector v = MaxToOpenGL(GetXYZVector(toks));
                currentMesh.PRS.Scale = v;
 
                Matrix m = currentMesh.PRS.GetMatrix();
                //Trace.WriteLine(String.Format("ASEImport: Scale: '{0}'", v.ToString()));
                //Trace.WriteLine(String.Format("ASEImport: Transformation Matrix: \n{0}", m.ToString()));
                /*
                                currentMesh.PRS.Position = Vector.Zero;
                                currentMesh.PRS.Rotation = Quaternion.Identity;
                                currentMesh.PRS.Scale = Vector.Unit;*/
              }
              /*
              if(st == "TM_ROW0") 
              {
                rm.m00 = GetFloat(toks, 0);
                rm.m01 = GetFloat(toks, 1);
                rm.m02 = GetFloat(toks, 2);
                rm.m03 = 0; //GetFloat(toks, 3);
              }
              else if(st == "TM_ROW1") 
              {
                rm.m10 = GetFloat(toks, 0);
                rm.m11 = GetFloat(toks, 1);
                rm.m12 = GetFloat(toks, 2);
                rm.m13 = 0; //GetFloat(toks, 3);
              }
              else if(st == "TM_ROW2") 
              {
                rm.m20 = GetFloat(toks, 0);
                rm.m21 = GetFloat(toks, 1);
                rm.m22 = GetFloat(toks, 2);
                rm.m23 = 0; //GetFloat(toks, 3);
              }
              else if(st == "TM_ROW3") 
              {
                rm.m30 = GetFloat(toks, 0);
                rm.m31 = GetFloat(toks, 1);
                rm.m32 = GetFloat(toks, 2);
                rm.m33 = 1; //GetFloat(toks, 3);
 
                Matrix m = Matrix.Identity;
                m.m00 = -rm.m00; m.m01 = -rm.m01; m.m02 = -rm.m02; m.m03 = -rm.m03;
                m.m10 =  rm.m20; m.m11 =  rm.m21; m.m12 =  rm.m22; m.m13 =  rm.m23;
                m.m20 =  rm.m10; m.m21 =  rm.m11; m.m22 =  rm.m12; m.m23 =  rm.m13;
                m.m30 =  rm.m30; m.m31 =  rm.m31; m.m32 =  rm.m32; m.m33 =  rm.m33;
 
                currentMesh.PRS.Position = m.Translation;
                currentMesh.PRS.Scale = m.Scale;
                currentMesh.PRS.Rotation.FromRotationMatrix(m);
              }*/
            }
            else if(currentBlock == "MESH") 
            {
              if(st == "MESH_NUMVERTEX") 
              {
                currentMesh.Vertices = new Vertex[GetInteger(toks, 0)];
 
              }
              else if(st == "MESH_NUMFACES") 
              {
                currentMesh.Faces = new Face[GetInteger(toks,0)];
              }
              else if(st == "MESH_NUMTVERTEX") 
              {
                int vNum = GetInteger(toks,0);
                if(vNum>0) 
                {
                  currentMesh.TexCoords = new TexCoordsEX[1][];
                  currentMesh.TexCoords[0] = new TexCoordsEX[vNum];
                  currentMesh.NumTexCoordLayers = 1;
                }
              }
              else if(st == "MESH_NUMCVERTEX") 
              {
                int i = GetInteger(toks, 0);
                if(i!=0)
                  vertexColors = new ColorEX[GetInteger(toks,0)];
                else
                  vertexColors = null;
                if(vertexColors == null)
                  currentMesh.UseVertexColors = false;
                else
                  currentMesh.UseVertexColors = true;
              }
            }
            else if(currentBlock == "MESH_VERTEX_LIST")
            {
              if(st == "MESH_VERTEX") 
              {
                int vNum = GetInteger(toks, 0);
                INode c = currentMesh.Parent;
                Matrix m = currentMesh.PRS.GetMatrix().Inverse();
                while(c != null) 
                {
                  if(c is Mesh)
                    m *= ((Mesh)c).PRS.GetMatrix().Inverse();
                  c = c.Parent;
                }
                //
                Vector v = MaxToOpenGL(GetXYZVector(toks,1));
                currentMesh.Vertices[vNum].Position = m * v;
              }
            }
            else if(currentBlock == "MESH_FACE_LIST")
            {
              if(st == "MESH_FACE")
              {
                int fN, A, B, C, AB, BC, CA, Smooth, MtlID;
                GetFace(toks, out fN, out A, out B, out C, out AB, out BC, out CA, out Smooth, out MtlID);
                currentMesh.Faces[fN].VertexIndex[0] = A;
                currentMesh.Faces[fN].VertexIndex[1] = B;
                currentMesh.Faces[fN].VertexIndex[2] = C;
                currentMesh.Faces[fN].SmoothingGroup = Smooth;
                if(materialIDs[MtlID]!=null)
                  currentMesh.Material = (Material)materialIDs[MtlID];
              }
            }
            else if(currentBlock == "MESH_TVERTLIST") 
            {
              if(st == "MESH_TVERT") 
              {
                int vNum = GetInteger(toks, 0);
                currentMesh.TexCoords[0][vNum] = GetUVWCoords(toks,1);
              }
            }
            else if(currentBlock == "MESH_TFACELIST") 
            {
              if(st == "MESH_TFACE") 
              {
                int vNum = GetInteger(toks, 0);
                int A = GetInteger(toks, 1);
                int B = GetInteger(toks, 2);
                int C = GetInteger(toks, 3);
                currentMesh.Faces[vNum].TexCoordsIndex[0]=A;
                currentMesh.Faces[vNum].TexCoordsIndex[1]=B;
                currentMesh.Faces[vNum].TexCoordsIndex[2]=C;
              }
            }
            else if(currentBlock == "MESH_CVERTLIST") 
            {
              if(st == "MESH_VERTCOL") 
              {
                int vNum = GetInteger(toks, 0);
                float A = GetFloat(toks, 1);
                float B = GetFloat(toks, 2);
                float C = GetFloat(toks, 3);
                float D = (toks.Length > 5)?GetFloat(toks, 4):1;
                vertexColors[vNum] = new ColorEX(A, B, C, D);
              }
            }
            else if(currentBlock == "MESH_CFACELIST") 
            {
              if(st == "MESH_CFACE") 
              {
                int vNum = GetInteger(toks, 0);
                int A = GetInteger(toks, 1);
                int B = GetInteger(toks, 2);
                int C = GetInteger(toks, 3);
                currentMesh.Vertices[currentMesh.Faces[vNum].VertexIndex[0]].Color = vertexColors[A];
                currentMesh.Vertices[currentMesh.Faces[vNum].VertexIndex[1]].Color = vertexColors[B];
                currentMesh.Vertices[currentMesh.Faces[vNum].VertexIndex[2]].Color = vertexColors[C];
              }
            }
            else if(currentBlock == "MESH_NORMALS") 
            {
              if(st == "MESH_FACENORMAL") 
              {
                int vNum = GetInteger(toks, 0);
                Vector v = MaxToOpenGL(GetXYZVector(toks, 1));
                v.Normalize();
                currentMesh.Faces[vNum].Normal = v;
              }
              else if(st == "MESH_VERTEXNORMAL") 
              {
                int vNum = GetInteger(toks, 0);
                Vector v = MaxToOpenGL(GetXYZVector(toks, 1));
                v.Normalize();
                currentMesh.Vertices[vNum].Normal = v;
              }
            }
            else if(currentBlock == "CONTROL_ROT_TCB") 
            {
              // We do not support TCB tracks
            }
            else if(currentBlock == "CONTROL_ROT_TRACK") 
            {
              if(startGroup) 
              {
                lastKey = null;
              }
              else if(st == "CONTROL_ROT_SAMPLE") 
              {
                int frameTime = (int)((float)GetInteger(toks, 0)*(float)1000/(float)scn.FrameSpeed/(float)scn.TicksPerFrame);
 
                quatAngleTemp = GetFloat(toks, 4);
                quatAxisTemp = MaxAngleToOpenGL(GetXYZVector(toks,1));
 
                while(quatAngleTemp >= Math.PI)
                { 
                  quatAngleTemp = ((float)Math.PI*2) - quatAngleTemp; 
                  quatAxisTemp *= -1; 
                }
                // Rotations are derivated from last frame, so we'll make it absolute here
                Quaternion q = Quaternion.FromAngleAndAxisRadians(-quatAngleTemp, quatAxisTemp);
                if(lastKey!=null) 
                {
                  q *= (Quaternion)(lastKey.KeyValue);
                }
                q = q.Normalize();
                q *= currentMesh.Rotation;
                //Trace.WriteLine(String.Format("ASEImport: Animation Key Rotation Sample: '{0}',{1}", quatAngleTemp,quatAxisTemp.ToString()));
                //Trace.WriteLine(String.Format("ASEImport: Animation Key Rotation Quaternion: '{0}'", q.ToString()));
                AnimationKey ak = new AnimationKey(currentMesh,frameTime, AnimationKey.KeyTypes.Rotation, AnimationKey.InterpolationTypes.Linear, q, lastKey, null);
                currentMesh.AnimationKeys.Add(ak);
                lastKey = ak;
              }
            }
            else if(currentBlock == "CONTROL_POS_TRACK") 
            {
              if(startGroup) 
              {
                lastKey = null;
              }
              else if(st == "CONTROL_POS_SAMPLE") 
              {
                int frameTime = (int)((float)GetInteger(toks, 0)*(float)1000/(float)scn.FrameSpeed/(float)scn.TicksPerFrame);
 
                Vector v = MaxToOpenGL(GetXYZVector(toks,1));
                //Trace.WriteLine(String.Format("ASEImport: Animation Key Position Sample: {0}", v.ToString()));
 
                //Quaternion q = new Quaternion(GetFloat(toks, 1),GetFloat(toks, 2),GetFloat(toks, 3),GetFloat(toks, 4));
                AnimationKey ak = new AnimationKey(currentMesh,frameTime, AnimationKey.KeyTypes.Position, AnimationKey.InterpolationTypes.Linear, v, lastKey, null);
                currentMesh.AnimationKeys.Add(ak);
                lastKey = ak;
              }
            }
          }
        }
        //if(br.BaseStream.Position >= br.BaseStream.Length)
          //done = true;
      }
      foreach(Material m in materials) 
      {
        scn.Materials.Add(m);
      }
      foreach(Mesh r in meshes) 
      {
        scn.AddNode(r);
        r.Initialize();
      }
      br.Close();
      return scn;      
    }
 
    public Scene LoadFromFile(string filename) 
    {
      //FileStream p = new FileStream(filename, FileMode.Open);
      StreamReader br = new StreamReader(filename);
      return Read(br);
    }
 
	}
}
 

Download ReadASE.cs ReadASE.cs - 28.3 KB