private void ParseSkinSet(BinaryParser parser, AnimSkin skin)
		{
			var name = parser.ConsumeUInt32();
			var numVerts = parser.ConsumeUInt32();
			var numBones = parser.ConsumeByte();
			parser.Expect(1);
			var boneIds = parser.ConsumeByteArray(numBones);
			var vertIds = parser.ConsumeUInt16Array((int)numVerts);
			var preMultipliedPositions = parser.ConsumeVector3Array((int)numVerts * numBones);
			var weights = parser.ConsumeFloatArray((int)numVerts * numBones);

			for (int index = 0; index < vertIds.Length; index++)
			{
				var id = vertIds[index];
				skin.Weights.EnsureAt(id);
				var vertexWeights = new VertexWeights { };
				if (numBones > 0)
				{
					vertexWeights.Bone0 = new VertexWeight { BoneIndex = boneIds[0], Weight = weights[0 + index * numBones] };
				}
				if (numBones > 1)
				{
					vertexWeights.Bone1 = new VertexWeight { BoneIndex = boneIds[1], Weight = weights[1 + index * numBones] };
				}
				if (numBones > 2)
				{
					vertexWeights.Bone2 = new VertexWeight { BoneIndex = boneIds[2], Weight = weights[2 + index * numBones] };
				}
				if (numBones > 3)
				{
					vertexWeights.Bone3 = new VertexWeight { BoneIndex = boneIds[3], Weight = weights[3 + index * numBones] };
				}
				skin.Weights[id] = vertexWeights;
			}
		}
		/// <summary>
		/// Parse binary block.
		/// </summary>
		public Managed Parse(BinaryParser parser)
		{
			var texture = this.context.Resolve<Texture>();
			texture.NameHash = parser.ConsumeUInt32();
			texture.Flags = parser.ConsumeUInt32();
			texture.FormatSW = (ImageFormat)parser.ConsumeByte();
			texture.FormatHW = (ImageFormat)parser.ConsumeByte();

			float x = parser.ConsumeFloat();
			float y = parser.ConsumeFloat();
			texture.UVScale = new Vector2(x, y);

			texture.Image = this.ParseImage(parser);

			var e = parser.ConsumeBool();
			//parser.Expect(false);

			return texture;
		}
		/// <summary>
		/// Parse binary block.
		/// </summary>
		public Managed Parse(BinaryParser parser)
		{
			var skel = this.context.Resolve<AnimSkel>();
			skel.NameHash = parser.ConsumeUInt32();

			var numBones = parser.ConsumeUInt32();
			while (numBones > 0)
			{
				parser.Expect(Hash.Get("CIwAnimBone"));
				var nameHash = parser.ConsumeUInt32();
				var parent = parser.ConsumeUInt32();
				var parentIndex = skel.EnsureBone(parent);
				var boneIndex = skel.EnsureBone(nameHash);
				var bone = skel.Bones[boneIndex];
				bone.Parent = parentIndex;
				bone.BindingRot = parser.ConsumeQuaternion();
				bone.BindingPos = parser.ConsumeVector3();
				bone.SkelId = parser.ConsumeUInt16();
				bone.Flags = parser.ConsumeUInt16();

				--numBones;
			}
			return skel;
		}
		/// <summary>
		/// Parse binary block.
		/// </summary>
		public Managed Parse(BinaryParser parser)
		{
			var material = this.context.Resolve<Material>();
			material.NameHash = parser.ConsumeUInt32();

			var isShort = parser.ConsumeBool();

			material.Flags = parser.ConsumeUInt32();

			if (!isShort)
			{
				material.ZDepthOfs = parser.ConsumeInt16();
				material.ZDepthOfsHW = parser.ConsumeInt16();
				material.ColEmissive = parser.ConsumeColor();
				material.ColAmbient = parser.ConsumeColor();
				material.ColDiffuse = parser.ConsumeColor();
				Color specular = parser.ConsumeColor();
				material.ColSpecular = specular;
				material.SpecularPower = specular.A;
				parser.Expect((uint)4);
			}
			material.Texture0.HashReference = parser.ConsumeUInt32();
			if (!isShort)
			{
				material.Texture1.HashReference = parser.ConsumeUInt32();
				material.Texture2.HashReference = parser.ConsumeUInt32();
				material.Texture3.HashReference = parser.ConsumeUInt32();

				var animated = parser.ConsumeBool();
				if (animated)
				{
					material.MatAnim = new MatAnim();
					parser.Expect(0);
					material.MatAnim.CelNum = parser.ConsumeByte();
					material.MatAnim.CelNumU = parser.ConsumeByte();
					material.MatAnim.CelW = parser.ConsumeByte();
					material.MatAnim.CelH = parser.ConsumeByte();
					material.MatAnim.CelPeriod = parser.ConsumeByte();
				}
				material.AlphaTestValue = parser.ConsumeByte();
				material.ShaderTechnique.HashReference = parser.ConsumeUInt32();
			}
			return material;
		}
		/// <summary>
		/// Parse binary block.
		/// </summary>
		public Managed Parse(BinaryParser parser)
		{
			var skin = this.context.Resolve<AnimSkin>();
			skin.NameHash = parser.ConsumeUInt32();
			skin.Flags = parser.ConsumeUInt32();
			skin.SkeletonModel.HashReference = parser.ConsumeUInt32();
			skin.Skeleton.HashReference = parser.ConsumeUInt32();
			var numGroups = parser.ConsumeUInt32();
			while (numGroups > 0)
			{
				--numGroups;
				var type = parser.ConsumeUInt32();
				if (type == Hash.Get("CIwAnimSkinSet"))
				{
					this.ParseSkinSet(parser, skin);
					continue;
				}
				throw new FormatException();
			}
			return skin;
		}
		/// <summary>
		/// Parse binary block.
		/// </summary>
		public Managed Parse(BinaryParser parser)
		{
			var anim = this.context.Resolve<Anim>();
			anim.NameHash = parser.ConsumeUInt32();

			anim.Skeleton.HashReference = parser.ConsumeUInt32();
			var numBones = parser.ConsumeUInt32();
			var boneFlags = parser.ConsumeUInt32();

			for (var numFrames = parser.ConsumeUInt32(); numFrames > 0; --numFrames)
			{
				var frameId = parser.ConsumeUInt32();
				if (frameId == Hash.Get("CIwAnimKeyFrame"))
				{
					var frame = this.context.Resolve<AnimKeyFrame>();
					parser.Expect((uint)0x0);
					frame.Time = parser.ConsumeFloat();
					var type = parser.ConsumeByte();
					var someVec = parser.ConsumeVector3();
					parser.Expect(0x01);

					anim.AddFrame(frame);

					uint num;
					bool b;
					switch (type)
					{
						case 2:
							parser.ConsumeUInt32(); // 0x01FFFFF, 0x01FFFFE
							num = parser.ConsumeUInt32();
							b = parser.ConsumeBool();

							for (uint index = 0; index < num; ++index)
							{
								var bone = frame.Bones[(int)index];
								bone.BindingPos = parser.ConsumeVector3();
								bone.BindingRot = parser.ConsumeQuaternion();
							}
							break;
						case 3:
							parser.ConsumeUInt32(); // 0x00002000, 1
							num = parser.ConsumeUInt32();
							b = parser.ConsumeBool();
							for (uint index = 0; index < num; ++index)
							{
								parser.ConsumeQuaternion();
							}
							break;
						default:
							throw new NotImplementedException();
					}
					continue;
				}
				throw new NotImplementedException();

				//this.m_KeyFrames.Serialise(serialise);
			}
			anim.Duration = parser.ConsumeFloat();
			var aaa = parser.ConsumeUInt32();
			return anim;
			//throw new NotImplementedException();

			//serialise.Fixed(ref this.m_TransformPrecision);
			//serialise.ManagedHash(ref this.m_OfsAnim);
			//serialise.DebugWrite(256);
		}
		private void ParseModelExtSelSetFace(BinaryParser parser, Model model, uint name, uint flags)
		{
			var m_Flags = parser.ConsumeByte();
			var m_FlagsSW = parser.ConsumeByte();
			var m_FlagsHW = parser.ConsumeByte();
			var m_OTZOfsSW = parser.ConsumeSByte();
			var m_NumFaces = parser.ConsumeUInt32();
			var m_FaceIDs = parser.ConsumeUInt16Array((int)m_NumFaces);
			//bool m_WorldSet;     /** True if this set is a world file only set */
		}
		/// <summary>
		/// Parse binary block.
		/// </summary>
		public Managed Parse(BinaryParser parser)
		{
			var model = this.context.Resolve<Model>();
			model.NameHash = parser.ConsumeUInt32();
			model.Flags = parser.ConsumeUInt32();
			var numVerts = parser.ConsumeUInt32();
			var numVertsUnique = parser.ConsumeUInt32();
			model.Center = parser.ConsumeVector3();
			model.Radius = parser.ConsumeFloat();
			var streamMesh = this.context.Resolve<Mesh>();
			model.Meshes.Add(streamMesh);

			streamMesh.NameHash = parser.ConsumeUInt32();
			//parser.Expect((uint)0x466dbf2a);

			var num = parser.ConsumeUInt32();
			for (; num > 0; --num)
			{
				var type = parser.ConsumeUInt32();

				var name = parser.ConsumeUInt32();
				var size = parser.ConsumeUInt32();
				var numItems = parser.ConsumeUInt32();
				var flags = parser.ConsumeUInt16();

				if (type == Hash.Get("CIwModelBlockGLUVs"))
				{
					this.ParseModelBlockGLUVs(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockCols"))
				{
					this.ParseModelBlockCols(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockGLTriList"))
				{
					this.ParseModelBlockGLTriList(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockNorms"))
				{
					this.ParseModelBlockNorms(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockVerts"))
				{
					this.ParseModelBlockVerts(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockVerts2D"))
				{
					this.ParseModelBlockVerts2D(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockBiTangents"))
				{
					this.ParseModelBlockBiTangents(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockTangents"))
				{
					this.ParseModelBlockTangents(parser, model, name, size, numItems, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelBlockChunk"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockChunkTree"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockChunkVerts"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockCols16"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockFaceFlags"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockGLPrimBase"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockGLRenderEdges"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockGLRenderVerts"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockGLTriStrip"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockGLUVs2"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockIndGroups"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimBase"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimF3"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimF4"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimFT3"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimFT4"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimG3"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimG4"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimGen3"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimGen4"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimGT3"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockPrimGT4"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockRenderEdges"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockRenderVerts"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelBlockSWOptim1"))
				{
					throw new NotImplementedException();
				}

				throw new FormatException("Unknown element");
			}

			num = parser.ConsumeUInt32();
			for (; num > 0; --num)
			{
				var type = parser.ConsumeUInt32();
				var name = parser.ConsumeUInt32();
				var flags = parser.ConsumeUInt32();

				if (type == Hash.Get("CIwModelExtPos"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelExtSelSet"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelExtSelSetEdge"))
				{
					throw new NotImplementedException();
				}
				if (type == Hash.Get("CIwModelExtSelSetFace"))
				{
					this.ParseModelExtSelSetFace(parser, model, name, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelExtSelSetVert"))
				{
					this.ParseModelExtSelSetVert(parser, model, name, flags);
					continue;
				}
				if (type == Hash.Get("CIwModelExtSphere"))
				{
					throw new NotImplementedException();
				}

				throw new FormatException("Unknown element");
			}

			num = parser.ConsumeUInt32();
			uint[] materials = new uint[num];
			for (uint matIndex = 0; matIndex < num; ++matIndex)
			{
				materials[matIndex] = parser.ConsumeUInt32();
			}

			foreach (var mesh in model.Meshes)
			{
				foreach (Surface submesh in mesh.Surfaces)
				{
					submesh.Material.HashReference = materials[submesh.Material.HashReference];
				}
			}

			return model;
		}
		private void ParseModelBlockGLTriList(
			BinaryParser parser, Model model, uint name, uint size, uint numItems, ushort flags)
		{
			var streamMesh = (model.Meshes[0]);
			var streamSubmesh = this.context.Resolve<ModelBlockGLTriList>();
			streamSubmesh.Mesh = streamMesh;
			streamMesh.Surfaces.Add(streamSubmesh);

			streamSubmesh.Material.HashReference = parser.ConsumeUInt32();

			var indices = parser.ConsumeUInt16Array((int)numItems);
			for (int i = 0; i < indices.Length;)
			{
				UInt16 a = indices[i++];
				UInt16 b = indices[i++];
				UInt16 c = indices[i++];
				streamSubmesh.Indices.Add(a);
				streamSubmesh.Indices.Add(b);
				streamSubmesh.Indices.Add(c);
			}
			//if (serialise.IsReading())
			//{
			//    this.m_TupleIDs = new ushort[this.m_NumTupleIDs];
			//    this.prims = new _IwModelPrim[this.numItems];
			//}

			//serialise.Serialise(ref this.m_TupleIDs);

			//for (int i = 0; i < this.numItems; ++i)
			//{
			//    this.prims[i].Serialise(serialise);
			//}
		}
		private Image ParseImage(BinaryParser parser)
		{
			var image = new Image();

			image.Format = (ImageFormat)parser.ConsumeUInt8();

			image.Flags = parser.ConsumeUInt16();

			image.width = parser.ConsumeUInt16();
			image.height = parser.ConsumeUInt16();
			image.pitch = parser.ConsumeUInt16();
			image.palette = parser.ConsumeUInt32();

			byte[] d = new byte[image.height * image.pitch];
			parser.ConsumeArray(d);
			image.data = d;

			switch (image.Format)
			{
				case ImageFormat.ABGR_8888:
				case ImageFormat.BGR_888:
				case ImageFormat.RGB_888:
					return image;
					//case Image.PALETTE4_ABGR_1555:
					//    format = (new Palette4Abgr1555(image.width, image.height, image.pitch));
					//    Debug.WriteLine(string.Format("Image PALETTE4_ABGR_1555 {0}x{1}", image.width, image.height));
					//    break;
					//case Image.PALETTE4_RGB_888:
					//    format = (new Palette4Rgb888(image.width, image.height, image.pitch));
					//    Debug.WriteLine(string.Format("Image PALETTE4_RGB_888 {0}x{1}", image.width, image.height));
					//    break;
					//case Image.PALETTE8_ABGR_1555:
					//    format = (new Palette8Abgr1555(image.width, image.height, image.pitch));
					//    Debug.WriteLine(string.Format("Image PALETTE8_ABGR_1555 {0}x{1}", image.width, image.height));
					//    break;
					//case Image.ABGR_1555:
					//    Debug.WriteLine(string.Format("Image ABGR_1555 {0}x{1}", image.width, image.height));
					//    LoadABGR1555(serialise);
					//    return;
					//case Image.RGBA_6666:
					//    Debug.WriteLine(string.Format("Image RGBA_6666 {0}x{1}", image.width, image.height));
					//    LoadRgba6666(serialise);
					//    return;
				case ImageFormat.PALETTE8_RGB_888:
					image.PaletteData = parser.ConsumeByteArray(256 * 3);
					return image;
				case ImageFormat.PALETTE8_ABGR_8888:
				case ImageFormat.PALETTE8_ARGB_8888:
				case ImageFormat.PALETTE8_RGBA_8888:
					image.PaletteData = parser.ConsumeByteArray(256 * 4);
					return image;
				case ImageFormat.PALETTE4_RGB_888:
					image.PaletteData = parser.ConsumeByteArray(16 * 3);
					return image;
				case ImageFormat.PALETTE4_ABGR_8888:
				case ImageFormat.PALETTE4_ARGB_8888:
				case ImageFormat.PALETTE4_RGBA_8888:
					image.PaletteData = parser.ConsumeByteArray(16 * 4);
					return image;
				default:
					throw new FormatException(string.Format(CultureInfo.CurrentCulture, "Unknown image format 0x{0:x}", image.Format));
			}
		}