Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.IO;
- namespace DromeEd.Drome
- {
- public static class Utils
- {
- public static string ReadStringASCIINT(BinaryReader reader, int length)
- {
- byte[] array = reader.ReadBytes(length);
- int num = 0;
- while (num < length && array[num] != 0)
- {
- num++;
- }
- return Encoding.ASCII.GetString(array, 0, num);
- }
- public static uint EndianSwap(uint input)
- {
- return ((input & 0xFF000000) >> 0x18) | ((input & 0x00FF0000) >> 0x08) | ((input & 0x0000FF00) << 0x08) | ((input & 0x000000FF) << 0x18);
- }
- }
- public struct Vector3
- {
- public float X;
- public float Y;
- public float Z;
- public Vector3(BinaryReader reader)
- {
- X = reader.ReadSingle();
- Y = reader.ReadSingle();
- Z = reader.ReadSingle();
- }
- public Vector3(float x, float y, float z)
- {
- X = x;
- Y = y;
- Z = z;
- }
- public void Normalize()
- {
- float len = (float)Math.Sqrt(X * X + Y * Y + Z * Z);
- X /= len;
- Y /= len;
- Z /= len;
- }
- }
- public struct Vector4
- {
- public float X;
- public float Y;
- public float Z;
- public float W;
- public Vector4(BinaryReader reader)
- {
- X = reader.ReadSingle();
- Y = reader.ReadSingle();
- Z = reader.ReadSingle();
- W = reader.ReadSingle();
- }
- public Vector4(float x, float y, float z, float w)
- {
- X = x;
- Y = y;
- Z = z;
- W = w;
- }
- }
- public class TextureReference
- {
- private const int MaxLength = 256;
- public string Filename = "";
- public Texture.MapType UsageType;
- public int BaseIndex;
- public TextureReference(BinaryReader reader)
- {
- Filename = Utils.ReadStringASCIINT(reader, MaxLength);
- UsageType = (Texture.MapType)reader.ReadUInt32();
- BaseIndex = reader.ReadInt32();
- }
- }
- public class MaterialInfo
- {
- public Vector4 Ambient;
- public Vector4 Diffuse;
- public Vector4 Specular;
- public Vector4 Emissive;
- public float Shininess;
- public float Transparency;
- uint TransparencyType;
- uint PropertyBits;
- string AnimationName;
- public MaterialInfo(BinaryReader reader)
- {
- Ambient = new Vector4(reader);
- Diffuse = new Vector4(reader);
- Specular = new Vector4(reader);
- Emissive = new Vector4(reader);
- Shininess = reader.ReadSingle();
- Transparency = reader.ReadSingle();
- TransparencyType = reader.ReadUInt32();
- PropertyBits = reader.ReadUInt32();
- AnimationName = Utils.ReadStringASCIINT(reader, 12);
- //AnimationName = Encoding.ASCII.GetString(reader.ReadBytes(12));//.TrimEnd(new char[] { (char)0 });
- }
- }
- public class BlockHeader
- {
- // MD2 Model
- public const string MAGIC_MODEL0 = "MDL0";
- public const string MAGIC_MODEL2 = "MDL2";
- public const string MAGIC_MODEL3 = "MDL3";
- public const string MAGIC_SKIN1 = "SKN0"; // Skin data
- public const string MAGIC_SKIN2 = "SKN1"; // PS2 VU1 format skin
- public const string MAGIC_SKIN3 = "SKN2"; // Skin and morph data
- public const string MAGIC_SHADOW1 = "SHA0";
- public const string MAGIC_SHADOWPS2 = "P2S0"; // PS2 VU1 format shadow
- public const string MAGIC_COLLDATA = "COLD";
- public const string MAGIC_GEOMETRY = "GEO0";
- public const string MAGIC_GEOMETRY1 = "GEO1";
- public const string MAGIC_GEOMETRY2 = "GEO2"; // Has render groups with an ID
- public const string MAGIC_GEOMETRYPS2 = "P2G0";
- public const string MAGIC_INDEXPS2 = "P2I0";
- public const string MAGIC_ANCHOR = "ANC0";
- public const string MAGIC_SKINGCN = "SKNG"; // GCN skin data
- public const string MAGIC_GEOMETRYGCN = "GCG0"; // GCN geometry data
- // OLI terrain stuff
- public const string MAGIC_OLI_CMO = "\u0001CMO";
- public const string MAGIC_OLI_COI = "COI0";
- public string Signature { get; }
- public int Length { get; }
- public BlockHeader(string signature, int length)
- {
- Signature = signature;
- Length = length;
- }
- public BlockHeader(BinaryReader reader)
- {
- Signature = Encoding.ASCII.GetString(reader.ReadBytes(4));
- Length = reader.ReadInt32();
- }
- }
- public abstract class Block
- {
- public BlockHeader Header { get; }
- public Block(BlockHeader header)
- {
- Header = header;
- }
- }
- [Flags()]
- public enum BufferAccess : uint
- {
- None = 0,
- Read = 1,
- Write = 2,
- ReadWrite = Read | Write,
- }
- public class MDLBlock : Block
- {
- //public int Size;
- public Vector3 InertiaTensor;
- public float BoundingRadius;
- public bool AllowDistanceFade = false;
- public bool IncludesBoundingBox = false;
- public Vector3 AABBMin;
- public Vector3 AABBMax;
- public Vector3 AABBCenter;
- public float AABBYaw;
- public uint UseUniqueMaterials;
- public uint UseUniqueTextures;
- public uint UseGenericGeometry; // don't load platform specific stuff
- public BufferAccess VertexBufferAccessFlags; // for cVertexBuffer
- public List<TextureReference> TextureReferences = new List<TextureReference>();
- public List<MaterialInfo> Materials = new List<MaterialInfo>();
- public MDLBlock(BinaryReader reader, BlockHeader header) : base(header)
- {
- InertiaTensor = new Vector3(reader);
- BoundingRadius = reader.ReadSingle();
- if (header.Signature != BlockHeader.MAGIC_MODEL0)
- {
- AllowDistanceFade = reader.ReadUInt32() > 0;
- IncludesBoundingBox = reader.ReadUInt32() > 0;
- if (IncludesBoundingBox)
- {
- AABBMin = new Vector3(reader);
- AABBMax = new Vector3(reader);
- AABBCenter = new Vector3(reader);
- AABBYaw = reader.ReadSingle();
- }
- UseUniqueMaterials = reader.ReadUInt32();
- UseUniqueTextures = reader.ReadUInt32();
- UseGenericGeometry = reader.ReadUInt32();
- VertexBufferAccessFlags = (BufferAccess)reader.ReadUInt32();
- reader.ReadBytes(12 * 4);
- }
- else
- {
- AllowDistanceFade = false;
- }
- int textureReferenceCount = reader.ReadInt32();
- for (int i = 0; i < textureReferenceCount; i++)
- {
- TextureReferences.Add(new TextureReference(reader));
- }
- int materialCount = reader.ReadInt32();
- for (int i = 0; i < materialCount; i++)
- {
- Materials.Add(new MaterialInfo(reader));
- }
- }
- }
- /*public class GEO1Block : Block
- {
- public List<LOD> LODs = new List<LOD>();
- public GEO1Block(BinaryReader reader, BlockHeader header) : base(header)
- {
- int LODCount = reader.ReadInt32();
- for (int i = 0; i < LODCount; i++)
- {
- LODs.Add(new LOD(reader));
- }
- }
- }*/
- public class GeometryBlock : Block
- {
- public enum TextureTileParam : byte
- {
- None = 0,
- Tile_U = 1,
- TileV = 2,
- MirrorU = 4,
- MirrorV = 8,
- NoBorders = 16
- }
- public class TextureBlend
- {
- public Texture.MapType Effect;
- public ushort TextureIndex;
- public byte CoordIndex;
- public TextureTileParam TilingInfo;
- public TextureBlend(BinaryReader reader)
- {
- Effect = (Texture.MapType)reader.ReadUInt32();
- TextureIndex = reader.ReadUInt16();
- CoordIndex = reader.ReadByte();
- TilingInfo = (TextureTileParam)reader.ReadByte();
- }
- }
- [Flags()]
- public enum RenderEffects : ushort
- {
- RenderZBiased = 1,
- RenderWireframe = 2,
- RenderNoPolygons = 4,
- RenderNoZTesting = 8,
- RenderNoZWriting = 16,
- RenderNoCulling = 32,
- RenderNoLighting = 64,
- RenderMinimalSetup = 128,
- RenderNoClipping = 256,
- VertexColor = 512,
- }
- public class RenderGroup
- {
- public uint ID; // Dummy
- public ushort PrimitiveCount;
- public ushort VertexCount;
- public ushort Material; // Material Index
- public RenderEffects Effects;
- uint pBumpData; // Dummy
- uint pVertexBuffer; // Dummy
- uint pIndexBuffer; // Dummy
- public const int BlendCount = 4;
- [Flags()]
- public enum VertexComponent : ushort
- {
- Position = 1,
- Normal = 2,
- Color = 4,
- UV = 8,
- BDNormal = 16,
- BSNormal = 32
- }
- // Texture Blends
- public ushort EffectsMask; // Each applied effect is a bit in this variable
- public ushort RendererReference;
- public ushort EffectCount;
- public byte Custom;
- public byte CoordsCount;
- public List<TextureBlend> TextureBlends = new List<TextureBlend>();
- // 'Source' Vertex buffer
- public uint PositionOffset;
- public uint NormalOffset;
- public uint ColorOffset;
- public uint UVOffset;
- public uint VertexSize;
- public uint UVCount;
- public VertexComponent VertexComponents;
- public ushort VertexCount2;
- public ushort ManagedBuffer;
- public ushort CurrentVertex;
- public uint pSourceBuffer; // Dummy
- public uint pVertexOffset; // Dummy
- public byte[] VertexData;
- // Index buffer
- public enum Primitive : uint
- {
- TriangleList,
- TriangleStrip,
- TriangleFan,
- LineList,
- LineStrip,
- PointList,
- PlatformSpecific
- }
- public uint PrimitiveBufferCount;
- public Primitive PrimitiveType;
- public uint IndexCount;
- public byte[] IndexData;
- public RenderGroup(BinaryReader reader)
- {
- if (Context.Current.Game >= Context.NextGenGame.DromeRacers)
- ID = reader.ReadUInt32();
- PrimitiveCount = reader.ReadUInt16();
- VertexCount = reader.ReadUInt16();
- Material = reader.ReadUInt16();
- Effects = (RenderEffects)reader.ReadUInt16();
- pBumpData = reader.ReadUInt32();
- pVertexBuffer = reader.ReadUInt32();
- pIndexBuffer = reader.ReadUInt32();
- EffectsMask = reader.ReadUInt16();
- RendererReference = reader.ReadUInt16();
- EffectCount = reader.ReadUInt16();
- Custom = reader.ReadByte();
- CoordsCount = reader.ReadByte();
- for (int i = 0; i < BlendCount; i++)
- {
- TextureBlends.Add(new TextureBlend(reader));
- }
- PositionOffset = reader.ReadUInt32();
- NormalOffset = reader.ReadUInt32();
- ColorOffset = reader.ReadUInt32();
- UVOffset = reader.ReadUInt32();
- VertexSize = reader.ReadUInt32();
- UVCount = reader.ReadUInt32();
- VertexComponents = (VertexComponent)reader.ReadUInt16();
- VertexCount2 = reader.ReadUInt16();
- ManagedBuffer = reader.ReadUInt16();
- CurrentVertex = reader.ReadUInt16();
- pSourceBuffer = reader.ReadUInt32();
- pVertexOffset = reader.ReadUInt32();
- VertexData = reader.ReadBytes(VertexCount2 * (int)VertexSize);
- PrimitiveBufferCount = reader.ReadUInt32();
- PrimitiveType = (Primitive)reader.ReadUInt32();
- IndexCount = reader.ReadUInt32();
- IndexData = reader.ReadBytes((int)IndexCount * 2); // 2 bytes per index
- }
- }
- public class LOD
- {
- public enum LODLevel : uint
- {
- GeometryFirstLevel,
- GeometrySubdivisionDetail = 0,
- GeometryNormalDetail,
- GeometryReducedDetail,
- GeometrySortedDetail,
- GeometryCollisionMesh,
- GeometryFacialMorphTarget,
- GeometryBlankDetailLevel,
- GeometryNumLevels = 6,
- GeometryAllLevels
- }
- public LODLevel Type;
- public float MaxEdgeLength;
- public uint GroupCount; // 0x00000003
- Vector3[] Positions; // Positions for z-sorting the rendergroups
- public uint PositionsPointer; // 0x00000000 pPositions Just here because the C++ class is literally dumped to the file.
- public uint RenderGroupsPointer; // 0x0212DEA4 pRenderGroups Just here because the C++ class is literally dumped to the file.
- public List<RenderGroup> RenderGroups = new List<RenderGroup>();
- public LOD(BinaryReader reader)
- {
- Type = (LODLevel)reader.ReadUInt32();
- MaxEdgeLength = reader.ReadSingle();
- GroupCount = reader.ReadUInt32();
- PositionsPointer = reader.ReadUInt32();
- //if (Context.Current.Game == Context.NextGenGame.DromeRacers)
- RenderGroupsPointer = reader.ReadUInt32();
- if (PositionsPointer > 0)
- {
- Positions = new Vector3[GroupCount];
- for (int i = 0; i < GroupCount; i++)
- {
- Positions[i] = new Vector3(reader);
- }
- }
- for (int i = 0; i < GroupCount; i++)
- {
- RenderGroups.Add(new RenderGroup(reader));
- }
- }
- }
- public List<LOD> LODs = new List<LOD>();
- public GeometryBlock(BinaryReader reader, BlockHeader header) : base(header)
- {
- int LODCount = reader.ReadInt32();
- for (int i = 0; i < LODCount; i++)
- {
- LODs.Add(new LOD(reader));
- }
- }
- }
- public class Anchor
- {
- private const int NameLength = 0x20;
- private const int PathLength = 0x80;
- public string Name = "";
- public uint AnchorType;
- public uint MaterialIndex;
- public string LinkedFilename = "";
- public Vector3 Position;
- public Vector3 Forward;
- public Vector3 Right;
- public Vector3 Up;
- public Vector3 ModelOffset;
- public Anchor(BinaryReader reader)
- {
- Name = Utils.ReadStringASCIINT(reader, NameLength);
- AnchorType = reader.ReadUInt32();
- MaterialIndex = reader.ReadUInt32();
- LinkedFilename = Utils.ReadStringASCIINT(reader, PathLength);
- Position = new Vector3(reader);
- Forward = new Vector3(reader);
- Right = new Vector3(reader);
- Up = new Vector3(reader);
- ModelOffset = new Vector3(reader);
- }
- public override string ToString()
- {
- return "<" + Position.X + ", " + Position.Y + ", " + Position.Z + ">: " + Name;
- }
- }
- public class AnchorBlock : Block
- {
- public List<Anchor> Anchors = new List<Anchor>();
- public AnchorBlock(BinaryReader reader, BlockHeader header) : base(header)
- {
- byte anchorCount = reader.ReadByte();
- for (int i = 0; i < anchorCount; i++)
- {
- Anchors.Add(new Anchor(reader));
- }
- }
- }
- public class MD2File
- {
- public Dictionary<string, Block> Blocks = new Dictionary<string, Block>();
- public MD2File(BinaryReader reader)
- {
- while (reader.BaseStream.Position < reader.BaseStream.Length - 4)
- {
- BlockHeader header = new BlockHeader(reader);
- long offset = reader.BaseStream.Position;
- System.Console.WriteLine("Reading Block '" + header.Signature + "' : " + ((int)reader.BaseStream.Position).ToString("X8") + " + " + header.Length.ToString("X8") + " bytes");
- Block newBlock = null;
- if (header.Signature == BlockHeader.MAGIC_MODEL0 || header.Signature == BlockHeader.MAGIC_MODEL2 || header.Signature == BlockHeader.MAGIC_MODEL3)
- {
- newBlock = new MDLBlock(reader, header);
- }
- else if (header.Signature == BlockHeader.MAGIC_GEOMETRY ||
- header.Signature == BlockHeader.MAGIC_GEOMETRY1 ||
- header.Signature == BlockHeader.MAGIC_GEOMETRY2)
- {
- newBlock = new GeometryBlock(reader, header);
- }
- else if (header.Signature == BlockHeader.MAGIC_ANCHOR)
- {
- newBlock = new AnchorBlock(reader, header);
- }
- if (newBlock != null)
- {
- Blocks.Add(header.Signature, newBlock);
- }
- reader.BaseStream.Position = offset + header.Length;
- }
- }
- public void ExportOBJ(string filename)
- {
- MDLBlock mdl;// = (Blocks[BlockHeader.MAGIC_MODEL3] ?? Blocks[BlockHeader.MAGIC_MODEL2]) as MDLBlock;
- if (Blocks.ContainsKey(BlockHeader.MAGIC_MODEL2))
- mdl = Blocks[BlockHeader.MAGIC_MODEL2] as MDLBlock;
- else if (Blocks.ContainsKey(BlockHeader.MAGIC_MODEL3))
- mdl = Blocks[BlockHeader.MAGIC_MODEL3] as MDLBlock;
- else
- throw new Exception("No supported MDL block found.");
- GeometryBlock geo;// = Blocks[BlockHeader.MAGIC_GEOMETRY2] as GeometryBlock;
- if (Blocks.ContainsKey(BlockHeader.MAGIC_GEOMETRY1))
- geo = Blocks[BlockHeader.MAGIC_GEOMETRY1] as GeometryBlock;
- else if (Blocks.ContainsKey(BlockHeader.MAGIC_GEOMETRY2))
- geo = Blocks[BlockHeader.MAGIC_GEOMETRY2] as GeometryBlock;
- else
- throw new Exception("No supported GEO block found.");
- using (StreamWriter matwriter = new StreamWriter(Path.ChangeExtension(filename, ".mtl")))
- using (StreamWriter writer = new StreamWriter(filename))
- {
- writer.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(filename) + ".mtl");
- int m = 0;
- int vertexOffset = 0;
- foreach (GeometryBlock.LOD lod in geo.LODs)
- {
- writer.WriteLine("g LOD" + lod.Type.ToString());
- foreach (GeometryBlock.RenderGroup group in lod.RenderGroups)
- {
- // Write a new material
- MaterialInfo mat = mdl.Materials[group.Material];
- matwriter.WriteLine("newmtl " + Path.GetFileNameWithoutExtension(filename) + "_" + m);
- matwriter.WriteLine("Ka " + (mat.Ambient.X + mat.Emissive.X) + " " + (mat.Ambient.Y + mat.Emissive.Y) + " " + (mat.Ambient.Z + mat.Emissive.Z));
- matwriter.WriteLine("Kd " + mat.Diffuse.X + " " + mat.Diffuse.Y + " " + mat.Diffuse.Z);
- matwriter.WriteLine("Ks " + mat.Specular.X + " " + mat.Specular.Y + " " + mat.Specular.Z);
- matwriter.WriteLine("Ns " + mat.Shininess);
- matwriter.WriteLine("d " + (1.0f - mat.Transparency));
- foreach (GeometryBlock.TextureBlend blend in group.TextureBlends)
- {
- if (blend.Effect == Texture.MapType.Base)
- {
- matwriter.WriteLine("map_Kd " + Path.GetFileName(mdl.TextureReferences[blend.TextureIndex].Filename));
- // Write Texture
- if (Program.Filesystem != null)
- {
- using (MemoryStream ms = new MemoryStream(Program.Filesystem.GetFileData(Program.Filesystem.GetFileEntry(mdl.TextureReferences[blend.TextureIndex].Filename.Replace(".tga", ".PC TEXTURE")))))
- using (BinaryReader texReader = new BinaryReader(ms))
- {
- Texture tex = new Texture(texReader);
- tex.DumpTGA(Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(mdl.TextureReferences[blend.TextureIndex].Filename)) + ".tga");
- }
- }
- }
- }
- writer.WriteLine("usemtl " + Path.GetFileNameWithoutExtension(filename) + "_" + m);
- writer.WriteLine("o LOD" + lod.Type.ToString() + "_group" + lod.RenderGroups.IndexOf(group));
- // Write vertices
- for (int v = 0; v < group.VertexCount; v++)
- {
- writer.WriteLine("v " + (Context.Current.Game == Context.NextGenGame.LegoRacers2 ? -1.0f : 1.0f) * ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.PositionOffset) + " " + ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.PositionOffset + 4) + " " + ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.PositionOffset + 8));
- writer.WriteLine("vn " + ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.NormalOffset) + " " + ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.NormalOffset + 4) + " " + ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.NormalOffset + 8));
- writer.WriteLine("vt " + ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.UVOffset) + " " + ParseFloat(group.VertexData, v * (int)group.VertexSize + (int)group.UVOffset + 4));
- }
- for (int i = 0; i < group.IndexCount; i += 3)
- {
- int i1 = BitConverter.ToUInt16(group.IndexData, i * 2) + vertexOffset + 1;
- int i2 = BitConverter.ToUInt16(group.IndexData, i * 2 + 2) + vertexOffset + 1;
- int i3 = BitConverter.ToUInt16(group.IndexData, i * 2 + 4) + vertexOffset + 1;
- /*if (Context.Current.Game == Context.NextGenGame.LegoRacers2)
- {
- // Flip the order of the indices
- int temp = i1;
- i1 = i2;
- i2 = i3;
- i3 = temp;
- }*/
- writer.WriteLine("f " + i1 + "/" + i1 + "/" + i1 + " " + i2 + "/" + i2 + "/" + i2 + " " + i3 + "/" + i3 + "/" + i3);
- }
- vertexOffset += group.VertexCount;
- m++;
- }
- }
- }
- }
- private static float ParseFloat(byte[] buffer, int offset)
- {
- return BitConverter.ToSingle(buffer, offset);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement