Page 3 of 6

Re: Charmesh to OBJ

Posted: Mon Mar 02, 2015 7:54 pm
by Jalmood
Absolutely amazing, Thanks mate for that, would you be interested in creating a parser for the .xac and .xsm files? seems everyone in the modding community for other games are looking for a parser for those format, i would really love to create some nice fighting cgi movies of war characters in 3ds max. you might find these links helpful. Cheers!

.xac format
https://dl.dropboxusercontent.com/u/60681258/xr/xac.txt

.xsm format
https://dl.dropboxusercontent.com/u/60681258/xr/xsm.txt

Re: Charmesh to OBJ

Posted: Wed Mar 04, 2015 8:52 pm
by Londo
They absolutely are helpful! I will try to plug in skeleton and animation information into current parser I wrote.

Getting hands on GameBryo from 2006 would be helpful also. Mythic's asset pipeline was 3d studio -> GameBryo->MYP Packer.

Still have some issues with mythic textures. Its a custom mythic wrapper around DXT1 and DXT5 dds compression formats.

I will change my parser to export FBX instead (includes bone animation). Then it will be just a matter of implementing FBX->GEOM/XAC/XSM and updating *.csv files in /data/gamedata in MYP to add new assets to the game.

Re: Charmesh to OBJ

Posted: Sat Mar 07, 2015 3:50 pm
by Dictator
Londo, i sent you a message private! :)

Re: Charmesh to OBJ

Posted: Mon Apr 13, 2015 7:19 pm
by w4kfu
Interesting thread!

I have been working on the same stuff.

Here are my notes about .geom file format (I didn't finish to figer out everything).

Everything is stored in little-endian.

The header is stored in 0x20 bytes, and have the following specifications:

Header spec:

Code: Select all

+ 0x00 :       signature            [DWORD]         // 0x464c7367 'gsLF'
+ 0x04 :       version              [DWORD]
+ 0x08 :       file_size            [DWORD]
+ 0x0C :       unk_dword_00         [DWORD]         // CRC?
+ 0x10 :       nb_bones             [DWORD]
+ 0x14 :       offset_bones         [DWORD]
+ 0x18 :       nb_meshes            [DWORD]
+ 0x1C :       offset_meshes        [DWORD]
Meshes data are stored in 0x20 bytes (offset of meshes is from the beginning of the file).

Mesh data spec:

Code: Select all

+ 0x00 :       unk_word_00          [WORD]
+ 0x02 :       nb_vertices          [WORD]
+ 0x04 :       offset_vertices      [DWORD]
+ 0x08 :       nb_triangles         [DWORD]
+ 0x0C :       offset_triangles     [DWORD]
+ 0x10 :       unk_dword_00         [DWORD]
+ 0x14 :       unk_dword_01         [DWORD]
+ 0x18 :       unk_dword_02         [DWORD]
+ 0x1C :       unk_dword_03         [DWORD]
Vertex data are stored in 0x20 bytes (offset of vertices are computed from the actual offset of the actual meshes, FileHeader->offset_meshes + Meshes->offset_vertices + num_meshes * sizeof (Meshes)):

Vertex data spec:

Code: Select all

+ 0x00 :       position_x           [DWORD]
+ 0x04 :       position_y           [DWORD]
+ 0x08 :       position_z           [DWORD]
+ 0x0C :       normal_x             [DWORD]
+ 0x10 :       normal_y             [DWORD]
+ 0x14 :       normal_z             [DWORD]
+ 0x18 :       texture_u            [DWORD]
+ 0x1C :       texture_v            [DWORD]
And triangles are stored in 0x6 bytes (offset of triangles are computed from the actual offset of the actual meshes, FileHeader->offset_meshes + Meshes->offset_triangles + num_meshes * sizeof (Meshes)):

Triangle data spec:

Code: Select all

+ 0x00 :       vertex_indice_1      [WORD]
+ 0x02 :       vertex_indice_2      [WORD]
+ 0x04 :       vertex_indice_3      [WORD]
With all thoses informations it is really easy to output (for testing purpose) WaveFront obj file (http://en.wikipedia.org/wiki/Wavefront_.obj_file), bender (http://www.blender.org/) can import them!

I wrote a parser in python for .geom files and another script to convert the data to .obj.
https://github.com/w4kfu/waronline_fun/ ... z/art/geom, Enjoy!

For the actual bones data (maybe 0x6C bytes long), the only field I have identified so far, is the first one, which is an offset to the name of the bone.

If you have more informations regarding .geom, I'm quite interested!

Re: Charmesh to OBJ

Posted: Mon Apr 13, 2015 7:40 pm
by Londo
I load the model (using irrlicht) like this

Code: Select all

     MemoryStream ms = new MemoryStream(File.ReadAllBytes(@"G:\WarExtract\assetdb\charmesh\fg.0.0.cmm_base_beard_b_04.geom"));

            GeomReader reader = new GeomReader();
            reader.Load(ms);

            foreach (Mesh mesh in m.Meshes)
            {
                MeshSceneNode meshSceneNode = null;
                MeshBuffer mb = MeshBuffer.Create(VertexType.Standard, IndexType._16Bit);
                List<Vertex3D> vlist = new List<Vertex3D>();
                List<ushort> indexList = new List<ushort>();
                foreach (p3 vertextInfo in mesh.VertexData.VertexList)
                {
                    float x = vertextInfo.x;
                    float y = vertextInfo.y;
                    float z = vertextInfo.z;

                    float u = vertextInfo.u;
                    float v = vertextInfo.v;
                    float w = 0;// vertextInfo.h;

                    Vertex3D vertex = new Vertex3D(x, y, z);
                    vertex.Color = Color.OpaqueWhite;
                    vertex.TCoords = new IrrlichtLime.Core.Vector2Df(u, v);
                    vlist.Add(vertex);

                }

                for (int i = 0; i < mesh.IndexList.Count; i++)
                {
                    indexList.Add(mesh.IndexList[i].b1);
                }

                mb.Append(vlist.ToArray(), indexList.ToArray());
            
                Mesh newMesh = Mesh.Create();
            
                newMesh.AddMeshBuffer(mb);
                meshSceneNode = device.SceneManager.AddMeshSceneNode(newMesh);


                Material irrMaterial = meshSceneNode.GetMaterial(0);
                meshSceneNode.Scale = new IrrlichtLime.Core.Vector3Df(10, 10, 10);
                meshSceneNode.SetMaterialFlag(MaterialFlag.Lighting, false);
                meshSceneNode.SetMaterialFlag(MaterialFlag.BackFaceCulling, false);
                meshSceneNode.DebugDataVisible = DebugSceneType.BBoxAll;

            }
Here are some of the parsing classing I have (From reversed engineered Machinima Studio, which has complete geom parser)

Code: Select all

 public class GeomReader
    {
        public class GEOMHeader
        {
            public string FileCode = "";
            public uint unk_c;
            public uint unk_d;
            public uint unk_e;
            public uint GeoSetCount;
            public uint GeoSetStartPos;
            public uint MeshCount;
            public uint DataStartPos;

            public void Load(BinaryReader reader)
            {
                FileCode = new String(reader.ReadChars(4));
                if (FileCode != "gsLF")
                    throw new Exception("Expected gsLF file header");

                unk_c = reader.ReadUInt32();
                unk_d = reader.ReadUInt32();
                unk_e = reader.ReadUInt32();
                GeoSetCount = reader.ReadUInt32();
                GeoSetStartPos = reader.ReadUInt32();
                MeshCount = reader.ReadUInt32();
                DataStartPos = reader.ReadUInt32();
            }
        }

        public class Mesh
        {
            public class MeshHeader
            {
                public short a;
                public ushort b;
                public uint c;
                public uint d;
                public uint e;
                public uint f;
                public uint g;
                public uint h;
                public uint i;

                public void Load(BinaryReader reader)
                {
                    a = reader.ReadInt16();
                    b= reader.ReadUInt16();
                    c = reader.ReadUInt32();
                    d = reader.ReadUInt32();
                    e = reader.ReadUInt32();
                    f = reader.ReadUInt32();
                    g = reader.ReadUInt32();
                    h = reader.ReadUInt32();
                    i = reader.ReadUInt32();
                }
            }
            public class UnkInfo1
            {
                public short a;
                public ushort b;
                public uint c;
                public void Load(BinaryReader reader)
                {
                    a = reader.ReadInt16();
                    b = reader.ReadUInt16();
                    c = reader.ReadUInt32();
                }
            }

            public class Vertex
            {
                public float z;
                public float x;
                public float y;
                public float unk1;
                public float unk2;
                public float unk3;
                public float u;
                public float v;
                public void Load(BinaryReader reader)
                {
                    z = reader.ReadSingle();
                    x = reader.ReadSingle();
                    y = reader.ReadSingle();
                    unk1 = reader.ReadSingle();
                    unk2 = reader.ReadSingle();
                    unk3 = reader.ReadSingle();
                    u = reader.ReadSingle();
                    v = reader.ReadSingle();
                }
            }


            public MeshHeader Header = new MeshHeader();
            public List<Vertex> VertexList = new List<Vertex>();
            public List<a12> IndexList = new List<a12>();
            public UnkInfo1 Unk1 = new UnkInfo1();
            public List<aqn> e = new List<aqn>();

            public void Load(BinaryReader reader)
            {
                Header.Load(reader);
            }
        }

        public class GeoSetInfo
        {
            public uint Offset;
            public float[] Unk2 = new float[26];

            public void Load(BinaryReader reader)
            {
                Offset = reader.ReadUInt32();
                for (int i = 0; i < Unk2.Length; i++)
                    Unk2[i] = reader.ReadSingle();
            }
        }

        public GEOMHeader Header = new GEOMHeader();
        public List<GeoSetInfo> GetSetInfo = new List<GeoSetInfo>();
        public List<Mesh> Meshes = new List<Mesh>();

        public void Load(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream);
            Header.Load(reader);
            
            //move to geoset definitions
            stream.Seek(Header.GeoSetStartPos, SeekOrigin.Begin);

            //read geoset info
            for (int i = 0; i < Header.GeoSetCount; i++)
            {
                GeoSetInfo data = new GeoSetInfo();
                data.Load(reader);
                GetSetInfo.Add(data);
            }

            long pos = 0;
            if (GetSetInfo.Count > 0)
                pos = GetSetInfo[0].Offset;
            reader.BaseStream.Seek(pos, SeekOrigin.Begin);


            for (int i = 0; i < Header.MeshCount; i++)
            {
                Mesh mesh = new Mesh();
                mesh.Load(reader);
                Meshes.Add(mesh);
            }

            for (int i = 0; i < Header.MeshCount; i++)
            {
                Mesh mesh = Meshes[i];
                if (mesh.Header.f != 0)
                {
                    mesh.Unk1.Load(reader);
                }
            }

            for (int i = 0; i < this.Header.MeshCount; i++)
            {
                Mesh mesh = Meshes[i];
                long offset = i * 32;
                pos = (this.Header.GeoSetStartPos + mesh.Header.c) + offset;
                reader.BaseStream.Seek(pos, SeekOrigin.Begin);

                Mesh.Vertex vertex = new Mesh.Vertex();
                vertex.Load(reader);
                mesh.VertexList.Add(vertex);

                pos = (this.Header.GeoSetStartPos + mesh.Header.e) + offset; //jump to index
                reader.BaseStream.Seek(pos, SeekOrigin.Begin);

                for (int n = 0; n < (mesh.Header.d * 3); n++)
                {
                    a12 a = new a12();
                    a.b(reader);
                    mesh.IndexList.Add(a);
                }
                for (int num9 = 0; num9 < mesh.d.b; num9++)
                {
                    aqn aqn = new aqn();
                    aqn.b(reader);
                    mesh.e.Add(aqn);
                }
            }

        }
    }

Re: Charmesh to OBJ

Posted: Thu Apr 16, 2015 6:26 am
by Jalmood
Awesome work guys, i hope you figure out the the various game formates, i think with machinima studio, there is no need for a .geom parser, i hope you could work on a diffuse parser and bones with animation, shame to see all these lovely models go to waste. so much talent was invested in creating them. here is a little video i made , just messing with the models in 3ds max. i think there is good possibilty to mod the game given that we have a convertor to geom formate. there are plenty of new unused models and armor sets that may be implemented in the game.


Click here to watch on YouTube

Re: Charmesh to OBJ

Posted: Thu Apr 16, 2015 6:54 am
by Londo
Jalmood wrote:Awesome work guys, i hope you figure out the the various game formates, i think with machinima studio, there is no need for a .geom parser, i hope you could work on a diffuse parser and bones with animation, shame to see all these lovely models go to waste. so much talent was invested in creating them. here is a little video i made , just messing with the models in 3ds max. i think there is good possibilty to mod the game given that we have a convertor to geom formate. there are plenty of new unused models and armor sets that may be implemented in the game.


Click here to watch on YouTube
Nice work!.

It would be nice to add new assets to the game eventually. My more immediate issue is line of sight calculations on the server for AOE damage. I have it almost working (using gpu on the server to load world geometry). Afterwards I can simply cast a ray from caster to target and see if any world geometry is hit.

Here is TOVL loaded into video memory on server
Image

Image

Re: Charmesh to OBJ

Posted: Mon Apr 04, 2016 5:26 am
by slor
Londo have you made your tool available? on Git or such. I dont play WAR anymore, but I'm modding another game and would love to not let these marvelous models go to waste.

Re: Charmesh to OBJ

Posted: Mon Apr 04, 2016 5:32 am
by Toldavf
Well now this is quiet intriguing. Amazing work can't wait to see the fruit it bears.

Re: Charmesh to OBJ

Posted: Mon Apr 04, 2016 7:44 am
by Glorian
Great Stuff! ;)
The apearance junky in me just jumped a meter into the air.