Exemple #1
0
        public MdlFileError SetData(byte[] src)
        {
            if (src == null)
            {
                return(MdlFileError.InvalidDataError);
            }
            if (src.Length < 1)
            {
                return(MdlFileError.EmptyFileError);
            }
            if (null != Reader)
            {
                Reader.Close();
                Reader.Dispose();
            }
            Reader  = new CMdlFileNavigator(src);
            IsValid = false;
            if (!HasData())
            {
                return(MdlFileError.EmptyFileError);
            }
            if (!Reader.IsBinVersEqual(MDL_FILE_REV))
            {
                return(MdlFileError.IncompatibleError);
            }
            if (!Reader.HasMore())  // Makes no sense without version check done!
            {
                return(MdlFileError.NoContentError);
            }

            IsValid = true;
            return(MdlFileError.NoError);
        }
Exemple #2
0
        /// <summary>
        /// Takes bytes at current reader position and parses them, assuming it is a block with
        /// frame structure.
        /// Data is parsed even it has no frame structure, make sure the reader is after the
        /// corresponding node tag before this method call.
        /// </summary>
        /// <param name="frme">Contains parsed armature</param>
        /// <returns>Wether the result contains missing data, false if OK</returns>
        public static bool Parse(CMdlFileNavigator reader, out CFrame frme)
        {
            int numVal = 0;

            float[] buff    = new float[16];
            bool    corrupt = false;

            // Read terminated ascii c-string. Bones have a space prepend, rootnode has not.
            string name = reader.ReadText().TrimStart();

            if (String.IsNullOrEmpty(name))
            {
                name    = "Unknown";
                corrupt = true;
            }

            reader.SeekBlockStart();  // Frame start, usually directly following
            if (reader.IsAtTag(mTags[(int)TagInfo.Tags.transform]))
            {
                reader.SeekBlockStart();
                for (; (numVal < buff.Length) && reader.HasMore(4); ++numVal)  // 4B float
                {
                    buff[numVal] = reader.ReadSingle();
                }
                reader.SeekBlockEnd();
            }
            if (numVal != buff.Length)
            {
                frme    = new CFrame(name + "_broken");
                corrupt = true;
                return(false);
            }
            else
            {
                frme = new CFrame(name, buff);
            }
            frme.IsDirty = corrupt;

            while (reader.IsAtTag(mTags[(int)TagInfo.Tags.frame]))
            {
                // Seek frame name. Frames have no block-open.
                reader.MoveCursor(TagInfo.frame.Length);

                corrupt |= Parse(reader, out CFrame child);
                frme.Childs.Add(child);
            }
            reader.SeekBlockEnd();
            return(corrupt);
        }
Exemple #3
0
        }//tryparse

        public static bool TryParseMorph(CMdlFileNavigator reader, out CMorph parsedMorph)
        {
            parsedMorph = null;
            if (null == reader)
            {
                return(false);
            }

            CMorph morph = new CMorph {
                Name = reader.ReadText()
            };

            reader.SeekBlockStart();

            bool   passed = true;
            string meshTag;

            while (passed && !String.IsNullOrEmpty(meshTag = reader.ReadTag(mTags)))
            {
                reader.SeekBlockStart();
                switch (meshTag)
                {
                case TagInfo.vertex:
                {
                    float[] pt3d = new float[3];
                    passed &= reader.TryOnDataSequence(onElement : delegate() {
                            for (int i = 0; i < 3; ++i)
                            {
                                pt3d[i] = reader.ReadSingle();
                            }
                            reader.MoveCursor(4);
                            morph.AddVertex(pt3d);
                        });
                    break;
                }//VRTX

                case TagInfo.normal:
                {
                    float[] pt3d = new float[3];
                    passed &= reader.TryOnDataSequence(onElement : delegate() {
                            for (int i = 0; i < 3; ++i)
                            {
                                pt3d[i] = reader.ReadSingle();
                            }
                            morph.AddNormal(pt3d);
                        });
                    break;
                }//NRML

                case TagInfo.unsupported1:
                    try {
                        int valCnt = reader.ReadInt32();
                        reader.MoveCursor(valCnt * 24);
                    } catch {
                        passed = false;
                    }
                    break;

                default:  // known but unhandled tag
                    passed = false;
                    break;
                }//switch

                reader.SeekBlockEnd();
            }
            reader.SeekBlockEnd();

            if (!morph.IsValid())
            {
                return(false);
            }
            parsedMorph = morph;
            return(passed);
        } //tryparsemorph
Exemple #4
0
        public static bool TryParse(CMdlFileNavigator reader, out CMesh parsedMesh)
        {
            parsedMesh = null;
            if (null == reader)
            {
                return(false);
            }
            CMesh mesh = new CMesh {
                Name = reader.ReadText()
            };
            string meshTag;

            // Data could contain end block symbol.
            // If errors occur, the whole process must be canceled,
            // because reader can be at unexpected position (segmentation fault).
            bool passed = true;

            reader.SeekBlockStart();  // begin mesh
            while (passed && !String.IsNullOrEmpty(meshTag = reader.ReadTag(mTags)))
            {
                reader.SeekBlockStart();  // begin data
                switch (meshTag)
                {
                case TagInfo.vertex:  // repeatedly entering here appends more vertice points to same mesh
                {
                    float[] pt3d = new float[3];
                    passed &= reader.TryOnDataSequence(onElement : delegate() {  // basically a foreach vec3
                            for (int i = 0; i < 3; ++i)
                            {
                                pt3d[i] = reader.ReadSingle();
                            }
                            reader.MoveCursor(4); // we discard the 4th dimension (4B)
                            mesh.AddVertex(pt3d);
                        });
                    break;
                }//VRTX

                case TagInfo.normal:  // repeatedly entering here appends more normals to same mesh
                {
                    float[] pt3d = new float[3];
                    passed &= reader.TryOnDataSequence(onElement : delegate() {
                            for (int i = 0; i < 3; ++i)
                            {
                                pt3d[i] = reader.ReadSingle();
                            }
                            mesh.AddNormal(pt3d); // stores as flipped
                        });
                    break;
                }//NRML

                case TagInfo.textureUV:  // repeatedly entering here appends more coordinates to same mesh
                {
                    float u, v;
                    passed &= reader.TryOnDataSequence(onElement : delegate() {
                            u = reader.ReadSingle();
                            v = reader.ReadSingle();
                            mesh.AddTexCoord(u, v); // expect normalized values and mirrors them
                        });
                    break;
                }//TXUV

                case TagInfo.face:
                {
                    ushort[] idx = new ushort[3];
                    passed &= reader.TryOnDataSequence(onElement : delegate() {
                            for (int i = 0; i < 3; ++i)
                            {
                                idx[i] = reader.ReadUInt16();
                            }
                            mesh.AssignFace(idx);
                        });
                    break;
                }//FACE

                case TagInfo.materials:
                    passed &= ReadInMaterialList(); // MTRL
                    reader.SkipWhitespace();        // \r\n
                    while ('}' != reader.PeekChar())
                    {                               // improve parsing stability on garbage text passages
                        reader.SeekBlockEnd();
                        reader.SkipWhitespace();
                    }
                    break;

                case TagInfo.weight:
                    while (reader.IsAtTag(mBONE_ANSI))
                    {
                        reader.MoveCursor(4);  // skip 'BONE'
                        passed &= ReadInWeights(out VertexGrp influence);
                        if (!influence.IsNullOrEmpty())
                        {
                            mesh.AssignWeight(influence);
                        }
                    }
                    break;

                case TagInfo.unsupported1:
                    try {
                        int valCnt = reader.ReadInt32();
                        reader.MoveCursor(valCnt * 24);
                    } catch {
                        passed = false;
                    }
                    break;

                default:
                    // try to skip with block end (but no error message)
                    //passed = false;
                    break;
                }//switch

                reader.SeekBlockEnd();  // end data
            }
            reader.SeekBlockEnd();  // end mesh

            //if (!mesh.IsValid())
            //{
            //    return false;
            //}
            parsedMesh = mesh;
            return(passed);

            bool ReadInMaterialList()
            {
                // Read material count and index ranges
                uint size = 0;

                uint[] iStart;
                uint[] iStop;
                try{
                    size   = reader.ReadUInt32(); // Empty MTRL bodys might follow that are not counted!
                    iStart = new uint[size];
                    iStop  = new uint[size];
                    for (int i = 0; i < size; i++)
                    {
                        iStart[i] = reader.ReadUInt32();
                        iStop[i]  = reader.ReadUInt32();
                    }
                } catch {
                    return(false);
                }

                // Begin of material description
                string matNam;
                long   currPos;
                int    bindsCnt;

                for (int matN = 0; matN < size; ++matN)
                {
                    reader.SkipWhitespace();
                    if (!reader.IsAtTag(mMTRL_ANSI))
                    {
                        return(false);
                    }
                    reader.MoveCursor(4);

                    // Fetch material name
                    matNam  = null;
                    currPos = reader.ReaderPos;  // right after tag
                    CTextUtil.DoOnNewLine(reader.Data, currPos, onNewLine : delegate(long nLPos) {
                        if (nLPos > currPos)
                        {
                            byte[] lineSeq = new byte[nLPos - currPos - 1]; // exclude '{'
                            Array.Copy(reader.Data, currPos, lineSeq, 0L, lineSeq.Length);
                            matNam  = CTextUtil.AnsiToStr(lineSeq).Trim();  // remove preceeding whitespace
                            currPos = reader.ReaderPos = nLPos + 2;         // after \r\n
                        }
                    });
                    if (String.IsNullOrEmpty(matNam))
                    {
                        return(false);
                    }

                    mesh?.AssignMaterial(matNam, iStart[matN], iStop[matN]);

                    // Determine lenght of description part
                    bindsCnt = 0;
                    reader.SeekBlockStart();          // after SBST{
                    CTextUtil.DoOnNewLine(reader.Data, reader.ReaderPos, delegate(long nLPos) {
                        reader.ReaderPos = nLPos + 2; // in newline
                        if (!Int32.TryParse(CTextUtil.AnsiToStr(reader.PeekLine()).Trim(), out bindsCnt))
                        {
                            bindsCnt = -1;
                        }
                    });
                    if (bindsCnt < 1)
                    {
                        return(false);
                    }

                    // Skip material description
                    do
                    {
                        reader.SeekBlockEnd();  // end of binding block
                        bindsCnt--;
                    } while (bindsCnt > 0);
                    reader.SeekBlockEnd(); // end of material description
                    reader.SeekBlockEnd(); // end of material block
                }//for matN
                return(true);              // may contain no materials
            }

            bool ReadInWeights(out VertexGrp boneInfluence)
            {
                boneInfluence = new VertexGrp();

                // Read bone influence
                reader.SeekBlockStart();
                string boneNam = reader.ReadText();
                uint   size    = 0;

                int[]   ids;
                float[] weights;
                try{
                    size    = reader.ReadUInt32();
                    ids     = new int[size];
                    weights = new float[size];
                    for (uint i = 0; i < size; ++i)
                    {
                        ids[i] = reader.ReadInt32();
                    }
                    for (uint i = 0; i < size; ++i)
                    {
                        weights[i] = reader.ReadSingle();
                    }
                } catch {
                    return(false);
                }

                // Read bind matrix
                float[]      buff   = new float[16];
                int          numVal = 0;
                Transform3DF mat;

                try {
                    for (; (numVal < buff.Length) && reader.HasMore(4); ++numVal)  // 4B float
                    {
                        buff[numVal] = reader.ReadSingle();
                    }
                    mat = new Transform3DF {
                        m00 = buff[0], m01 = buff[4], m02 = buff[8], m03 = buff[12],
                        m10 = buff[1], m11 = buff[5], m12 = buff[9], m13 = buff[13],
                        m20 = buff[2], m21 = buff[6], m22 = buff[10], m23 = buff[14]
                    };
                } catch {
                    if (numVal < 64)
                    {
                        reader.MoveCursor(64 - numVal * 4);  // sizeOf(mat) == 64
                    }
                    mat = Transform3DF.Identity();
                }
                reader.SeekBlockEnd();

                // Assign bone weight map
                if (size > 0)
                {
                    //var weightMap = new System.Collections.Specialized.OrderedDictionary();
                    var weightMap = new Dictionary <int, float>();
                    for (int i = 0; i < size; ++i)
                    {
                        weightMap[ids[i]] = weights[i];  // overwrite if exist, add if not
                    }
                    boneInfluence.groupName  = boneNam;
                    boneInfluence.mapping    = weightMap;
                    boneInfluence.bindMatrix = mat;
                }
                return(true);
            }
        }//tryparse
Exemple #5
0
        //readonly CMdlFile file;


        //private CFileParser()
        //{
        //    throw new NotImplementedException("CFileParser()");  // Not allowed without file
        //}


        //public CFileParser(CMdlFile file)
        //{
        //    this.file = file ?? throw new ArgumentNullException(nameof(file));
        //}


        #region public Methods

        public static bool TryParse(CMdlFile file, ref Entities hierachy)
        {
            if ((null == file) || !file.IsValid)
            {
                return(false);
            }
            //if (null == hierachy.meshes)  // preserve when reading morphs
            //{
            //    hierachy.meshes = new List<Mdl.CMesh>();
            //}

            string            readNode;
            bool              cancel = false;
            CMdlFileNavigator reader = file.Reader;

            // Read nodes
            reader.MoveDataStart();               // in case of restart
            if (TagInfo.root != reader.ReadTag()) // read and seek
            {                                     // Does not start with RootNode
                return(false);
            }
            reader.SkipWhitespace();  // \r\n
            CFrameParser.Parse(reader, out Mdl.CFrame currFrame);
            //int nodeCount = hierachy.rootNode.Childs.Count;
            //if (file.IsMorph && (null != hierachy.rootNode) && nodeCount > 0)
            //{
            //    hierachy.rootNode.Childs.RemoveRange(1, nodeCount - 1);
            //    hierachy.rootNode.Childs.AddRange(currFrame.Childs);
            //} else {
            //    hierachy.rootNode = currFrame;
            //}
            hierachy.rootNode = currFrame;  // morphs have no skeleton at index 0!
            reader.SkipWhitespace();

            // Read mesh data
            var parsedMeshes = new List <Mdl.CMesh>();

            while (!cancel && !String.IsNullOrEmpty(readNode = reader.ReadTag(mTags)))
            {
                switch (readNode)
                {
                case TagInfo.root:
                    cancel = true;
                    break;

                case TagInfo.mesh:
                    Mdl.CMesh currMesh = null;
                    if (file.IsMorph)
                    {
                        if ((cancel = !CMeshParser.TryParseMorph(reader, out Mdl.CMorph morph)) ||
                            (null == hierachy.meshes) || !hierachy.meshes.Any(msh => msh != null))  //< not a reason to cancel
                        {
                            break;
                        }
                        var matches = hierachy.meshes.Where(
                            msh => msh.VerticesCount() == morph.VerticesCount() &&
                            file.Filename.Contains(msh.Name));
                        if (matches.Any())
                        {
                            currMesh = matches.First()?.CreateMorphedMesh(morph);
                        }
                    }
                    else
                    {
                        if (cancel = !CMeshParser.TryParse(reader, out currMesh))
                        {
                            break;
                        }
                        currMesh.OriginName = file.Filename;
                    }
                    if (null != currMesh && currMesh.IsValid())
                    {
                        parsedMeshes.Add(currMesh);
                    }
                    break;

                case TagInfo.collision:  // skip (text block with 4 line body)
                    reader.SeekBlockStart();
                    reader.SeekBlockEnd();
                    break;

                default:
                    cancel = true;  // not implemented
                    break;
                }

                reader.SkipWhitespace();  // \r\n after each data block
            }
            if (!cancel)
            {
                hierachy.meshes = parsedMeshes;
            }
            return(!cancel);
        }