public void SetLevel(BlastCorpsLevel level)
        {
            this.level = level;
             levelModel = new Model3D(level);

             foreach (Vehicle veh in level.vehicles)
             {
            if (veh.type == 0) // player
            {
               location = new Vector3((veh.x + 20) * scale, (veh.y + 400) * scale, (veh.z - 400) * scale);
               pitch = -MathHelper.PiOver6;
               facing = MathHelper.PiOver2 + MathHelper.PiOver6;
               SetupViewport();
               glControlViewer.Invalidate();
               break;
            }
             }

             if (loaded)
             {
            glControlViewer.Invalidate();
             }
        }
        public static void ExportDisplayList(BlastCorpsRom rom, BlastCorpsLevel level, string filename, float scale)
        {
            Model3D model = new Model3D(level);

             string mtlFileName = filename + ".mtl";

             using (System.IO.StreamWriter file = new System.IO.StreamWriter(filename))
             {
            int vertCount = 1;
            file.WriteLine(fileHeader());
            file.WriteLine("mtllib {0}", Path.GetFileName(mtlFileName));
            foreach (Triangle tri in model.triangles)
            {
               float uScale = 32.0f * tri.texture.width;
               float vScale = 32.0f * tri.texture.height;
               file.WriteLine();
               file.WriteLine("usemtl Texture{0:X4}", tri.texture.address);
               file.WriteLine(toObjVert(tri.vertices[0], scale, uScale, vScale));
               file.WriteLine(toObjVert(tri.vertices[1], scale, uScale, vScale));
               file.WriteLine(toObjVert(tri.vertices[2], scale, uScale, vScale));
               file.WriteLine("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}", vertCount, (vertCount + 1), (vertCount + 2));
               vertCount += 3;
            }
             }

             // create textures directory
             string textureDirName = "textures";
             string textureDir = Path.Combine(Path.GetDirectoryName(filename), textureDirName);
             Directory.CreateDirectory(textureDir);
             using (System.IO.StreamWriter file = new System.IO.StreamWriter(mtlFileName))
             {
            List<uint> processedTextures = new List<uint>();
            file.WriteLine(fileHeader());
            foreach (Texture t in model.textures)
            {
               if (!processedTextures.Contains(t.address))
               {
                  string textureFilename = String.Format("{0:X4}.png", t.address);
                  string textureFile = String.Format(textureDirName + "/" + textureFilename);
                  file.WriteLine("newmtl Texture{0:X4}", t.address);
                  file.WriteLine("Ka 0.0 0.0 0.0"); // ambiant color
                  file.WriteLine("Kd 1.0 1.0 1.0"); // diffuse color
                  file.WriteLine("Ks 0.3 0.3 0.3"); // specular color
                  file.WriteLine("d 1");            // dissolved
                  file.WriteLine("map_Kd {0}", textureFile);
                  file.WriteLine();

                  BlastCorpsTexture bct = new BlastCorpsTexture(rom.GetRawData(), t.address, 0);
                  bct.decode();
                  byte[] n64Texture = bct.GetInflated();
                  N64Format format = N64Format.RGBA;
                  int depth = 16;

                  switch (bct.type)
                  {
                     case 0: // IA8?
                        // TODO: memcpy, no info
                        format = N64Format.IA;
                        depth = 8;
                        break;
                     case 1: // RBGA16?
                        format = N64Format.RGBA;
                        depth = 16;
                        break;
                     case 2: // RGBA32?
                        format = N64Format.RGBA;
                        depth = 32;
                        break;
                     case 3: // IA8?
                        format = N64Format.IA;
                        depth = 8;
                        break;
                     case 4: // IA16?
                        format = N64Format.IA;
                        depth = 16;
                        break;
                     case 5: // RGBA32?
                        format = N64Format.RGBA;
                        depth = 32;
                        break;
                     case 6: // IA8?
                        format = N64Format.IA;
                        depth = 8;
                        break;
                  }

                  Bitmap loadedBitmap;
                  switch (format)
                  {
                     case N64Format.RGBA:
                        loadedBitmap = N64Graphics.RGBA(n64Texture, t.width, t.height, depth);
                        break;
                     case N64Format.IA:
                     default:
                        loadedBitmap = N64Graphics.IA(n64Texture, t.width, t.height, depth);
                        break;
                  }
                  loadedBitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
                  loadedBitmap.Save(Path.Combine(textureDir, textureFilename));

                  processedTextures.Add(t.address);
               }
            }
             }
        }