/// <summary> /// Initializes a new instance of the <see cref="CAMR"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public CAMR(BaseChunk from) : base(from) { while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "NAME": Name = nextChunk.ReadString(nextChunk.Data.Length); break; case "DATA": //consists of floats only //a float has a size of 4 bytes int len = nextChunk.Data.Length / 4; CameraData = new float[len]; for (int i = 0; i < CameraData.Length; i++) { CameraData[i] = nextChunk.ReadFloat(); } break; } } }
/// <summary> /// Initializes a new instance of the <see cref="MSH2"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public MSH2(BaseChunk from) : base(from) { Models = new List <MODL>(); while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "SINF": SelectionInformation = new SINF(nextChunk); break; case "CAMR": Camera = new CAMR(nextChunk); break; case "MATL": MaterialList = new MATL(nextChunk); break; case "MODL": Models.Add(new MODL(nextChunk)); break; } } }
/// <summary> /// Use this Constructor to create a new Chunk from a given <see cref="BaseChunk" />. This must be overriden by every subclass! /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public BaseChunk(BaseChunk from) { Log.Add("Process Chunk " + from.ChunkName, LogType.Info); ChunkName = from.ChunkName; data.AddRange(from.data); Owner = from.Owner; }
/// <summary> /// Writes a given Chunk into the data stream /// </summary> /// <param name="chunk">The chunk to write</param> public void WriteChunk(BaseChunk chunk) { if (chunk == null) { return; } chunk.WriteData(); chunk.WriteChunkLength(); data.AddRange(chunk.data); chunk.FlushData(); }
/// <summary> /// Initializes a new instance of the <see cref="SINF"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public SINF(BaseChunk from) : base(from) { while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "NAME": Name = nextChunk.ReadString(nextChunk.Data.Length); break; case "FRAM": FrameInformation = new FRAM(nextChunk); break; case "BBOX": BoundingBox = new BBOX(nextChunk); break; } } }
/// <summary> /// Creates a new Chunk from given byte data /// </summary> /// <param name="inputData">The data to read from</param> /// <param name="offset">The offset in the byte array to start reading from</param> /// <returns>The new Chunk</returns> /// <exception cref="EndOfDataException">Unexpected end of Data</exception> /// <exception cref="InvalidChunkException">If Chunk name is not valid or the read chunk length is negative</exception> public static BaseChunk FromData(byte[] inputData, int offset, MSH owner) { if (inputData.Length < 8 || offset + 8 > inputData.Length) { Log.Add("Unexpected end of Data!", LogType.Error); throw new EndOfDataException("Unexpected end of Data!"); } BaseChunk chunk = new BaseChunk(owner); //every chunk starts with a chunk name (4 bytes) chunk.ChunkName = inputData.SubArray(offset, 4).GetString(); offset += 4; //and an Int32 defining the length of the chunk (in bytes) int length = BitConverter.ToInt32(inputData, offset); offset += 4; if (!Regex.Match(chunk.ChunkName, ValidChunkRegEx).Success) { Log.Add(chunk.ChunkName + " is not a valid Chunk Name!", LogType.Error); throw new InvalidChunkException(chunk.ChunkName + " is not a valid Chunk Name!"); } if (length < 0) { Log.Add(length + " is not a valid Chunk Length!", LogType.Error); throw new InvalidChunkException(length + " is not a valid Chunk Length!"); } if (offset + length > inputData.Length) { Log.Add("Unexpected end of Data!", LogType.Error); throw new EndOfDataException("Unexpected end of Data!"); } //create own data chunk.data.AddRange(inputData.SubArray(offset, length)); chunk.ResetPosition(); Log.Add("Valid Chunk " + chunk.ChunkName + " found of length " + chunk.data.Count, LogType.Info); return(chunk); }
/// <summary> /// Initializes a new instance of the <see cref="GEOM"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public GEOM(BaseChunk from) : base(from) { while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "BBOX": BoundingBox = new BBOX(nextChunk); break; case "SEGM": SEGM segm = new SEGM(nextChunk); Segments.Add(segm); break; } } }
/// <summary> /// Reads a chunk from given data /// </summary> /// <returns></returns> /// <exception cref="EndOfStreamException">Unexpected end of Data!</exception> public BaseChunk ReadChunk() { //a new Chunk as to be at least 8 Bytes in size! if (position + 8 > data.Count) { Log.Add("Unexpected end of Data!", LogType.Error); throw new EndOfDataException("Unexpected end of Data!"); } //we just need to pass the data from our current position //The newly created chunk will cut it futher down later //byte[] chunkData = Data.SubArray(position, Data.Length - position); BaseChunk newChunk = FromData(data.ToArray(), position, Owner); //length of the chunk + header size position += newChunk.data.Count + 8; return(newChunk); }
/// <summary> /// Initializes a new instance of the <see cref="MODL"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public MODL(BaseChunk from) : base(from) { while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "MTYP": Type = (MTYP)nextChunk.ReadInt32(); break; case "MNDX": index = nextChunk.ReadInt32(); break; case "NAME": Name = nextChunk.ReadString(nextChunk.Data.Length); break; case "PRNT": parentName = nextChunk.ReadString(nextChunk.Data.Length); break; case "FLGS": Flag = new ModelFlag(true, nextChunk.ReadInt32()); break; case "TRAN": Scale = nextChunk.ReadVector3(); Rotation = nextChunk.ReadVector3(); Translation = nextChunk.ReadVector3(); UnknownTRAN = nextChunk.ReadFloat(); break; case "GEOM": Geometry = new GEOM(nextChunk); break; } } }
/// <summary> /// Initializes a new instance of the <see cref="HEDR"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public HEDR(BaseChunk from) : base(from) { while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "SHVO": Shvo = nextChunk.ReadInt32(); break; case "MSH2": Mesh = new MSH2(nextChunk); break; default: break; } } }
/// <summary> /// Creates a new Chunk from given Stream /// </summary> /// <param name="stream">The Stream to read from</param> /// <returns>The new Chunk</returns> /// <exception cref="EndOfDataException">Unexpected end of Data</exception> /// <exception cref="InvalidChunkException">If Chunk name is not valid or the read chunk length is negative</exception> public static BaseChunk FromData(ChunkStream stream, MSH owner) { BaseChunk chunk = new BaseChunk(owner); //every chunk starts with a chunk name (4 bytes) chunk.ChunkName = stream.ReadString(4); //and an Int32 defining the length of the chunk (in bytes) int length = stream.ReadInt32(); if (!Regex.Match(chunk.ChunkName, ValidChunkRegEx).Success) { Log.Add(chunk.ChunkName + " is not a valid Chunk Name!", LogType.Error); throw new InvalidChunkException(chunk.ChunkName + " is not a valid Chunk Name!"); } if (length < 0) { Log.Add(length + " is not a valid Chunk Length!", LogType.Error); throw new InvalidChunkException(length + " is not a valid Chunk Length!"); } //read all the data byte[] buffer = new byte[length]; try { stream.Read(buffer, 0, length); chunk.data.AddRange(buffer); } catch (ArgumentOutOfRangeException ex) { Log.Add("Unexpected end of Data!", LogType.Error); throw new EndOfDataException("Unexpected end of Data!", ex); } chunk.ResetPosition(); return(chunk); }
/// <summary> /// Initializes a new instance of the <see cref="MATL"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public MATL(BaseChunk from) : base(from) { Materials = new List <MATD>(); //The first four bytes of data contain sa 32-bit integer specifying the number of MATD sections contained in this section. int len = ReadInt32(); while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "MATD": Materials.Add(new MATD(nextChunk)); break; } } if (len != Materials.Count) { Log.Add("The number of expected materials (" + len + ") does not match the number of actually read materials (" + Materials.Count + ")!", LogType.Warning); } }
/// <summary> /// Initializes a new instance of the <see cref="MATD"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public MATD(BaseChunk from) : base(from) { while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); switch (nextChunk.ChunkName) { case "NAME": Name = nextChunk.ReadString(nextChunk.Data.Length); break; case "DATA": Diffuse = nextChunk.ReadColor(); Ambient = nextChunk.ReadColor(); Specular = nextChunk.ReadColor(); SpecularSharpness = nextChunk.ReadFloat(); break; case "ATRB": attribute = nextChunk.ReadInt32(); break; } //catch texture entrys (usually TX0D) Match txMatch = Regex.Match(nextChunk.ChunkName, "TX[0-9]{1}D"); if (txMatch.Success) { //the number sits at the 3rd position = [2] //the symbol "0" ist at position 48 in the ascii table int index = txMatch.Value[2] - 48; Textures[index] = nextChunk.ReadString(nextChunk.Data.Length); } } }
/// <summary> /// Initializes a new instance of the <see cref="SEGM"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public SEGM(BaseChunk from) : base(from) { List <Vector3> verts = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); Polygon currentPoly = new Polygon(vertices); bool lastBoundry = false; while (!EndOfData) { BaseChunk nextChunk = ReadChunk(); int count = 0; switch (nextChunk.ChunkName) { case "MATI": matIndex = nextChunk.ReadInt32(); break; case "POSL": count = nextChunk.ReadInt32(); for (int i = 0; i < count; i++) { verts.Add(nextChunk.ReadVector3()); } break; case "NRML": count = nextChunk.ReadInt32(); for (int i = 0; i < count; i++) { normals.Add(nextChunk.ReadVector3()); } break; case "UV0L": count = nextChunk.ReadInt32(); for (int i = 0; i < count; i++) { uvs.Add(nextChunk.ReadVector2()); } break; case "STRP": count = nextChunk.ReadInt32(); for (int i = 0; i < count; i++) { VertexIndex next = nextChunk.ReadVertexIndex(); if (next.polyBoundary && !lastBoundry) { //polygon finished, add to buffer if (currentPoly.VertexIndices.Count > 0) { polygons.Add(currentPoly); } //start new polygon currentPoly = new Polygon(vertices); //write first index value to polygon currentPoly.VertexIndices.Add(next.index); } else { if (currentPoly != null) { currentPoly.VertexIndices.Add(next.index); } else { //this should never happen Log.Add("Warning: Lone Vertex in Strip Buffer!", LogType.Warning); } } lastBoundry = next.polyBoundary; } break; } } if (uvs.Count > 0) { hasUVs = true; } for (int i = 0; i < verts.Count; i++) { //since uv coordinates are optional, deliver empty ones if non existent Vector2 uv = (i < uvs.Count) ? uvs[i] : new Vector2(); vertices.Add(new Vertex(verts[i], normals[i], uv)); } //Add last Polygon if (currentPoly != null && currentPoly.VertexIndices.Count > 0) { polygons.Add(currentPoly); } }
/// <summary> /// Initializes a new instance of the <see cref="FRAM"/> class. /// </summary> /// <param name="from">The <see cref="BaseChunk" /> to use for creating this Chunk. The given data will be interpreted respectively.</param> public FRAM(BaseChunk from) : base(from) { Start = ReadInt32(); End = ReadInt32(); FrameRate = ReadFloat(); }
public BBOX(BaseChunk from) : base(from) { Rotation = ReadVector4(); Translation = ReadVector3(); Dimension = ReadVector4(); }