Member Controls

Developers > GMDC Parsing (and possibly rendering...)
Afr0Link to postposted: Tue Aug 07, 2007 12:36 am

Member since:
 2007-08-07
Posts:
 3

Ok, so I have been looking all over the net (especially at the modthesims2.com wiki), searching Google.com for hours etc. in hopes that I am one day going to be able to write my own parser for the GMDC format. And then, after tons of failures, one-off errors and countless hours of debugging, I find the SimPE source SVN.

Now, I realize that I could just use SimPE.GMDCExporter.Base.dll to do the dirtywork of parsing for me, but at this point I am so determined (and also - at least that's what I think - close) to parsing the files I'd really like to have my own parser that I initially set out to make. This is why I've now come to these forums to beg for help! Innocent If Quaxi or someone could take a peek and try to spot any obvious errors in my code, I'd appreciate it alot.

 

Here's my code:

 

</p><p>using System;</p><p>using System.Collections.Generic;</p><p>using System.Linq;</p><p>using System.Text;</p><p>using System.IO;</p><p>using System.Windows.Forms;</p><p>using DataFormatLib.RCOL.GMDC;</p><p>namespace DataFormatLib.RCOL</p><p>{</p><p>public enum RCOLID : uint</p><p>{</p><p>GMDC = 0xAC4F8687,</p><p>GMND = 0x7BA3838C,</p><p>ANIM = 0xFB00791E,</p><p>CINE = 0x4D51F042,</p><p>CRES = 0xE519C933,</p><p>AmLGHT = 0xC9C81B9B, //Lighting (Ambient Light)</p><p>DiLGHT = 0xC9C81BA3, //Lighting (Directional Light)</p><p>PoLGHT = 0xC9C81BA9, //Lighting (Point Light) </p><p>SpLGHT = 0xC9C81BAD, //Lighting (Spot Light)</p><p>LIFO = 0xED534136,</p><p>SHPE = 0xFC6EB1F7,</p><p>TXMT = 0x49596978, //aka MATD - Material Definition</p><p>TXTR = 0x1C4A276C</p><p>}</p><p>public struct FileLink</p><p>{</p><p>public uint GroupID;</p><p>public uint InstanceID;</p><p>public uint ResourceID;</p><p>public uint TypeID;</p><p>}</p><p>public class RCOLFile : BinaryReader</p><p>{</p><p>#region Private Variables</p><p>//Header</p><p>private uint m_NumFileLinks;</p><p>private uint m_StringStyle;</p><p>private uint m_Language;</p><p>private bool m_ReadTGIR = false;</p><p>private List<FileLink> m_FileLinks;</p><p>//Index</p><p>private uint m_ItemCount;</p><p>private List<GMDCFile> m_GMDCFiles;</p><p>#endregion</p><p>public RCOLFile(string FilePath) : base(File.OpenRead(FilePath))</p><p>{</p><p>//Language and StringStyle fields - MAY NOT BE PRESENT!</p><p>uint LanguageStringStyle = ReadUInt32();</p><p>m_NumFileLinks = LanguageStringStyle;</p><p>if (LanguageStringStyle == 0xFFFF0001)</p><p>{</p><p>m_Language = (ushort)(LanguageStringStyle & 0xFFFF0001);</p><p>m_StringStyle = (ushort)((LanguageStringStyle >> 16) & 0x0000ffff);</p><p>m_NumFileLinks = ReadUInt32();</p><p>}</p><p>else</p><p>{</p><p>m_Language = 0;</p><p>m_StringStyle = 0;</p><p>}</p><p>if (m_NumFileLinks > 0)</p><p>{</p><p>m_FileLinks = new List<FileLink>();</p><p>for (int i = 0; i < m_NumFileLinks; i++)</p><p>{</p><p>FileLink Link = new FileLink();</p><p>Link.GroupID = ReadUInt32();</p><p>Link.InstanceID = ReadUInt32();</p><p>if (m_ReadTGIR == true)</p><p>Link.ResourceID = ReadUInt32();</p><p>Link.TypeID = ReadUInt32();</p><p>m_FileLinks.Add(Link);</p><p>}</p><p>}</p><p>m_ItemCount = ReadUInt32();</p><p>m_GMDCFiles = new List<GMDCFile>();</p><p>for (int i = 1; i <= m_ItemCount; i++)</p><p>{</p><p>RCOLID TmpID = (RCOLID)ReadUInt32();</p><p>if (TmpID == RCOLID.GMDC)</p><p>{</p><p>GMDCFile TmpFile = new GMDCFile();</p><p>TmpFile.ReadBlock(this);</p><p>m_GMDCFiles.Add(TmpFile);</p><p>}</p><p>}</p><p>}</p><p>}</p><p>}</p><p>

 

</p><p>using System;</p><p>using System.Collections.Generic;</p><p>using System.Linq;</p><p>using System.Text;</p><p>using System.Windows.Forms;</p><p>using System.IO;</p><p>namespace DataFormatLib.RCOL.GMDC</p><p>{</p><p>class GMDCFile</p><p>{</p><p>#region Private Variables</p><p> </p><p>private uint m_Version;</p><p>private string m_FileName;</p><p>#endregion</p><p>public void ReadBlock(BinaryReader Reader)</p><p>{</p><p>string BlockName = Reader.ReadString();</p><p>if (BlockName.Equals("cGeometryDataContainer"))</p><p>{</p><p>//BlockID</p><p>Reader.ReadUInt32();</p><p>//BlockVersion</p><p>Reader.ReadUInt32();</p><p>/*===========================================*</p><p>* cSGResource</p><p>* ==========================================*/</p><p>//"cSGResource"</p><p>Reader.ReadString();</p><p>//ResourceID - 0</p><p>Reader.ReadUInt32();</p><p>//Version</p><p>m_Version = Reader.ReadUInt32();</p><p>//File name</p><p>m_FileName = Reader.ReadString();</p><p>/*=============================================*</p><p>* Elements Section</p><p>* ============================================*/</p><p>int ElementCount = Reader.ReadInt32();</p><p>for (int i = 0; i < ElementCount; i++)</p><p>{</p><p>GMDCElement TmpElement = new GMDCElement();</p><p>TmpElement.ReadElement(Reader);</p><p>}</p><p>}</p><p>}</p><p>}</p><p>}</p><p>

 

</p><p>using System;</p><p>using System.Collections.Generic;</p><p>using System.Linq;</p><p>using System.Text;</p><p>using System.IO;</p><p>using System.Windows.Forms;</p><p>namespace DataFormatLib.RCOL.GMDC</p><p>{</p><p>public enum ElementID : uint</p><p>{</p><p>BlendIndices = 0x1C4AFC56,</p><p>BlendWeights = 0x5C4AFC5C,</p><p>TargetIndices = 0x7C4DEE82,</p><p>NormalMorphDeltas = 0xCB6F3A6A,</p><p>Colour = 0xCB7206A1,</p><p>ColourDeltas = 0xEB720693,</p><p>NormalsList = 0x3B83078B,</p><p>Vertices = 0x5B830781,</p><p>UVCoordinates = 0xBB8307AB,</p><p>UVCoordinateDeltas = 0xDB830795,</p><p>Binormals = 0x9BB38AFB,</p><p>BoneWeights = 0x3BD70105,</p><p>BoneAssignments = 0xFBD70111,</p><p>BumpMapNormals = 0x89D92BA0,</p><p>BumpMapNormalDeltas = 0x69D92B93,</p><p>MorphVertexDeltas = 0x5CF2CFE1,</p><p>MorphVertexMap = 0xDCF2CFDC,</p><p>VertexID = 0x114113C3, //Only for ExpansionPack 4!</p><p>RegionMask = 0x114113CD, //Only for ExpansionPack 4!</p><p>}</p><p>public enum BlockFormat : int</p><p>{</p><p>SingleFloat = 0x00,</p><p>TwoFloats = 0x01,</p><p>ThreeFloats = 0x02,</p><p>OneUInt = 0x04</p><p>}</p><p>class GMDCElement</p><p>{</p><p>private int m_RefArraySize;</p><p>private ElementID m_ID;</p><p>private int m_IDRepetition;</p><p>private BlockFormat m_BlockFormat;</p><p>private int m_SetFormat;</p><p>public void ReadElement(BinaryReader Reader)</p><p>{</p><p>m_RefArraySize = Reader.ReadInt32();</p><p>m_ID = (ElementID)Reader.ReadInt32();</p><p>m_IDRepetition = Reader.ReadInt32();</p><p>m_BlockFormat = (BlockFormat)Reader.ReadInt32();</p><p>m_SetFormat = Reader.ReadInt32();</p><p>ElementValue Value = DetermineElementValue();</p><p>int SetLength = Reader.ReadInt32() / (4 * Value.Size);</p><p>for (int i = 0; i < SetLength; i++)</p><p>{</p><p>Value = DetermineElementValue();</p><p>Value.Unserialize(Reader);</p><p>}</p><p>}</p><p>/// <summary></p><p>/// Rreturns a new instance of the ElementValue class, based on the value in m_BlockFormat.</p><p>/// </summary></p><p>/// <returns>A new instance of the ElementValue class.</returns></p><p>private ElementValue DetermineElementValue()</p><p>{</p><p>switch (m_BlockFormat)</p><p>{</p><p>case BlockFormat.OneUInt:</p><p>return new ElementValueOneInt();</p><p>case BlockFormat.SingleFloat:</p><p>return new ElementValueOneFloat();</p><p>case BlockFormat.TwoFloats:</p><p>return new ElementValueTwoFloats();</p><p>case BlockFormat.ThreeFloats:</p><p>return new ElementValueThreeFloats();</p><p>}</p><p>return new ElementValueOneFloat();</p><p>}</p><p>}</p><p>}</p><p>

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using System.Windows.Forms;

namespace DataFormatLib.RCOL.GMDC

{

class ElementValue

{

protected float[] m_Data;

public ElementValue()

{

m_Data = new float[Size];

}

/// <summary>

/// Reads data from a stream into this ElementValue instance.

/// </summary>

internal virtual void Unserialize(BinaryReader Reader)

{

for (int i = 0; i < m_Data.Length; i++)

m_Data[i] = Reader.ReadSingle();

}

/// <summary>

/// Returns the number of Float Elements stored here

/// </summary>

internal virtual byte Size

{

get { return 0; }

}

}

class ElementValueOneInt : ElementValue

{

internal ElementValueOneInt() : base() {}

/// <summary>

/// Returns the number of Int Elements stored here

/// </summary>

internal override byte Size

{

get { return 1; }

}

int val;

internal override void Unserialize(BinaryReader Reader)

{

val = Reader.ReadInt32();

m_Data[0] = (float)val;

}

}

class ElementValueOneFloat : ElementValue

{

internal ElementValueOneFloat() : base() {}

/// <summary>

/// Returns the number of Float Elements stored here

/// </summary>

internal override byte Size

{

get { return 1; }

}

}

class ElementValueTwoFloats : ElementValue

{

internal ElementValueTwoFloats() : base() {}

/// <summary>

/// Returns the number of Float Elements stored here

/// </summary>

internal override byte Size

{

get { return 2; }

}

}

class ElementValueThreeFloats : ElementValue

{

internal ElementValueThreeFloats() : base() {}

/// <summary>

/// Returns the number of Float Elements stored here

/// </summary>

internal override byte Size

{

get { return 3; }

}

}

}

 

As one can tell, after I found the SimPE source, I've done numerous changes to my own code to try to make it work based on what I found in SimPE's source. However, there's still alot of my own code there, and if I find out what's wrong with this code, I'm probably going to change some stuff around, see if I can use less classes etc.

 

Just to make things a bit clear; The error I am getting when trying to parse a GMDC file with this code is that the program cannot read beyond the end of the stream. I get the error at this line:

 

for (int i = 0; i < m_Data.Length; i++)

m_Data[i] = Reader.ReadSingle();

 

Also, if someone could perhaps point me to some brief documents that would explain how to properly render GMDCs, that would be lovely! This is not neccessary, as I am sure I can figure that out once I've loaded all data successfully, but it would still be a good headstart. :)

 

Thanks in advance!

 

Edit: The source code feature of the forum seems to be somewhat broken, so I uploaded the source on this link: http://www.savefile.com/files/949685

 

quaxiLink to postposted: Sun Sep 09, 2007 10:35 am
Avator for quaxi

Member since:
 2006-04-28
Posts:
 3154

Well the error message indicates, that you are reading a counter wrong.

 

Did you try to step through the GMDC reading using SimPE in the VS Debugger, and comparing it to the values you get? That might help you locating the source of the error. You also could just compare the counts using the GMDC GUI in SimPE withe the ones you are reading.

 

Sorry that I cannot give you more detailed hlep, but the GMDC is a more complex FileFormat, so that I don't know it off hand and cannot trace an error in your code. 

  

wes_hLink to postposted: Mon Sep 10, 2007 6:04 am
Avator for wes_h

Member since:
 2005-03-08
From:
 Rockdale, TX, USA
Posts:
 62

Well, I know a little about the GMDC format, but I am not sure I can help you much at adapting the SimPE code.

I am also reluctant to download 12 Mb of your rar'd source to look through.

 

Going by what you posted, the part you are having trouble with reads all the data blocks (what we originally called P1), such as the ones with vertices, the ones with normals, and so on. From what you described you may be trying to read one using a value that is not the block size, and consequently trying to read too many bytes. After all the data parts are read in, there are a number of other blocks to be read.

 

I would try tackling this problem with printf() statements. For instance, how many times has that loop been called, and how many bytes is it trying to read?

 

This would help you find where to look next, refining the printf() statements as needed. 

 

I assume you have seen the GMDC format document on the Sims2 wiki? It is quite accurate, if a little geeky.

Additionally, the source for the UniMesh plugins is posted on MTS2, written in C/C++. The importer plugin parses GMDCs completely into data structures before it then converts them into a MilkShape data model. Search for UniMesh Source on MTS2.

 

<* Wes *>

 



viewthread, 0, 0, GMDC-Parsing-and-possibly-rendering