protected static void AddVertexToList(int boneID, Vector2?tex, Vector3?nrm, Vector3 pos, int pos_scale,
                                              Color clr, List <ModelBase.VertexDef> vertexList)
        {
            Vector3 scaledPos = Vector3.Multiply(pos, (1 << pos_scale));

            ModelBase.VertexDef vertex = new ModelBase.VertexDef(scaledPos, tex, nrm, clr, boneID);
            vertexList.Add(vertex);
        }
Example #2
0
        Tuple<ModelBase.FaceListDef, List<int>> GetStripAndIndicesForStartingEvenEdge(
            TriangleLinked start, TriangleEdge startForwardEdge)
        {
            List<int> stripIndices = new List<int>();
            List<TriangleRotation> stripRotations = new List<TriangleRotation>();

            List<TriangleLinked> linked = GetLinked(start)[(int)startForwardEdge];
            TriangleLinked bestNeighbour = DetermineBestNextNeighbour(start, linked, startForwardEdge);

            if (bestNeighbour == null)
                return new Tuple<ModelBase.FaceListDef, List<int>>(new ModelBase.FaceListDef(), new List<int>());

            TriangleRotation startRotation = (TriangleRotation)((int)(startForwardEdge - TriangleEdge.Edge_BC + 3) % 3);

            TriangleLinked t = start;
            TriangleEdge currentEdge = startForwardEdge;
            TriangleRotation currentRotation = startRotation;
            bool even = true;
            int index_t = -1;
            while (t != null && !stripIndices.Contains((index_t = m_Triangles.IndexOf(t))))
            {
                stripIndices.Add(index_t);
                stripRotations.Add(currentRotation);

                linked = GetLinked(t)[(int)currentEdge];
                bestNeighbour = DetermineBestNextNeighbour(t, linked, currentEdge);

                t = bestNeighbour;

                even = !even;

                if (t != null)
                {
                    // Determine rotation and the edge to be used to get the next face

                    ModelBase.FaceDef triangleC_CW = new ModelBase.FaceDef(3);
                    if (even)
                    {
                        triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[0];
                        triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1];
                        triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[2];
                    }
                    else
                    {
                        triangleC_CW.m_Vertices[0] = t.m_Triangle.m_Vertices[2];
                        triangleC_CW.m_Vertices[1] = t.m_Triangle.m_Vertices[1];
                        triangleC_CW.m_Vertices[2] = t.m_Triangle.m_Vertices[0];
                    }

                    // The edge of the vertices which match the preceding triangle's
                    TriangleEdge linkBackEdge = TriangleEdge.Edge_AB;
                    // The vertices which match the preceding triangle's
                    ModelBase.VertexDef[] currentMatchedEdge = new ModelBase.VertexDef[2];
                    TriangleLinked previous = m_Triangles[stripIndices[stripIndices.Count - 1]];
                    currentMatchedEdge[0] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 0) % 3];
                    currentMatchedEdge[1] = previous.m_Triangle.m_Vertices[(int)(currentEdge + 1) % 3];
                    // Find the edge in the current triangle which if odd has been made CW which matches
                    // that from the preceding triangle. This will be set as the current triangle's first,
                    // or 'AB' edge and the next edge (next two vertices) will be used to match the next
                    // triangle.
                    for (int i = 0; i < 3; i++)
                    {
                        ModelBase.VertexDef[] edge = new ModelBase.VertexDef[2];
                        edge[0] = triangleC_CW.m_Vertices[(i + 0) % 3];
                        edge[1] = triangleC_CW.m_Vertices[(i + 1) % 3];
                        if (edge.Except(currentMatchedEdge).Count() == 0)
                        {
                            linkBackEdge = (TriangleEdge)i;
                            break;
                        }
                    }

                    TriangleEdge nextEdgeNoC_CW = (TriangleEdge)((int)(linkBackEdge + 1) % 3);

                    TriangleEdge nextEdge = nextEdgeNoC_CW;
                    if (!even)
                    {
                        // If odd, nextEdgeNoC_CW points to the edge to be used if written CW, however
                        // all triangles have been read in as CCW so need to get the corresponding edge
                        // in CCW version.
                        ModelBase.VertexDef[] nextEdgeNoC_CW_Vertices = new ModelBase.VertexDef[2];
                        nextEdgeNoC_CW_Vertices[0] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 0) % 3];
                        nextEdgeNoC_CW_Vertices[1] = triangleC_CW.m_Vertices[(int)(nextEdgeNoC_CW + 1) % 3];
                        for (int i = 0; i < 3; i++)
                        {
                            ModelBase.VertexDef[] ccwEdge = new ModelBase.VertexDef[2];
                            ccwEdge[0] = t.m_Triangle.m_Vertices[(i + 0) % 3];
                            ccwEdge[1] = t.m_Triangle.m_Vertices[(i + 1) % 3];
                            if (nextEdgeNoC_CW_Vertices.Except(ccwEdge).Count() == 0)
                            {
                                nextEdge = (TriangleEdge)i;
                                break;
                            }
                        }
                    }

                    // Now we need to determine the required rotation of the current triangle so that for
                    // even triangles the new vertex in at index 0 and for odd triangles it occurs at
                    // index 2.
                    ModelBase.VertexDef uniqueVertex = t.m_Triangle.m_Vertices.Except(previous.m_Triangle.m_Vertices).ElementAt(0);
                    int uniqueVertexIndex = Array.IndexOf(t.m_Triangle.m_Vertices, uniqueVertex);
                    TriangleRotation requiredRotation =
                        (even) ? (TriangleRotation)((uniqueVertexIndex - 2 + 3) % 3) :
                        (TriangleRotation)(uniqueVertexIndex);

                    currentRotation = requiredRotation;
                    currentEdge = nextEdge;

                    // To best understand how this works, debug and step-through how the following model is handled:
                    //
                    // An example:
                    // Faces as defined in model (all Counter-Clockwise (CCW)):
                    // f 1 2 3
                    // f 4 1 3
                    // f 4 5 1
                    // Build strip from edge CA.
                    // # 2 3 1 (LS)      <- Need to Left Shift vertices so that CA is the second edge.
                    // #   3 1 4 (4 1 3) <- For odd faces the new vertex must be at index [0]
                    //                      No Rot required, link-back CW: AB, CW forward: AB + 1 = BC,
                    //                      CCW forward: edge in CCW that contains vertices in (CW forward) = AB
                    //                      The next triangle is the one that shares the CCW edge AB (vertices 1 and 4)
                    // #     1 4 5 (RS)  <- Even face the new vertex needs to be in index [2] so need to Right Shift vertices
                    //                      Repeat steps as for above face but don't need to worry about converting between CCW and CW order
                }

            }

            ModelBase.FaceListDef tStrip = new ModelBase.FaceListDef(ModelBase.PolyListType.TriangleStrip);

            even = true;
            for (int i = 0; i < stripIndices.Count; i++)
            {
                TriangleRotation requiredRotation = (TriangleRotation)stripRotations[i];

                ModelBase.FaceDef rotated = new ModelBase.FaceDef(3);
                rotated.m_Vertices[0] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(0 + requiredRotation) % 3)];
                rotated.m_Vertices[1] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(1 + requiredRotation) % 3)];
                rotated.m_Vertices[2] = m_Triangles[stripIndices[i]].m_Triangle.m_Vertices[((int)(2 + requiredRotation) % 3)];

                tStrip.m_Faces.Add(rotated);

                even = !even;
            }

            return new Tuple<ModelBase.FaceListDef, List<int>>(tStrip, stripIndices);
        }
Example #3
0
        public override ModelBase LoadModel(float scale)
        {
            if (m_ModelFileName == null || "".Equals(m_ModelFileName))
            {
                throw new SystemException("You must specify the filename of the model to load via the constructor before " +
                                          "calling LoadModel()");
            }

            Stream       fs = File.OpenRead(m_ModelFileName);
            StreamReader sr = new StreamReader(fs);

            string curmaterial = null;

            bool   foundObjects     = LoadDefaultBones(m_ModelFileName);
            string currentBone      = null;
            int    currentBoneIndex = -1;

            if (!foundObjects)
            {
                currentBone = "default_bone_name";
                ModelBase.BoneDef defaultBone = new ModelBase.BoneDef(currentBone);
                defaultBone.m_Geometries.Add("geometry-0", new ModelBase.GeometryDef("geometry-0"));
                m_Model.m_BoneTree.AddRootBone(defaultBone);
                currentBoneIndex = m_Model.m_BoneTree.GetBoneIndex(defaultBone);
            }

            string curline;

            while ((curline = sr.ReadLine()) != null)
            {
                curline = curline.Trim();

                // skip empty lines and comments
                if (curline.Length < 1)
                {
                    continue;
                }
                if (curline[0] == '#')
                {
                    continue;
                }

                string[] parts = curline.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length < 1)
                {
                    continue;
                }

                switch (parts[0])
                {
                case "mtllib":     // material lib file
                {
                    string filename = curline.Substring(parts[0].Length + 1).Trim();
                    LoadMaterials(m_ModelPath + Path.DirectorySeparatorChar + filename);
                }
                break;

                case "bonelib":     // bone definitions file
                {
                    string filename = curline.Substring(parts[0].Length + 1).Trim();
                    LoadBoneDefinitionsForOBJ(m_ModelPath + Path.DirectorySeparatorChar + filename);
                }
                break;

                case "o":     // object (bone)
                    if (parts.Length < 2)
                    {
                        continue;
                    }
                    currentBone = parts[1];
                    m_Model.m_BoneTree.GetBoneByID(currentBone).m_Geometries.Add(currentBone, new ModelBase.GeometryDef(currentBone));
                    currentBoneIndex = m_Model.m_BoneTree.GetBoneIndex(currentBone);
                    break;

                case "usemtl":     // material name
                    if (parts.Length < 2)
                    {
                        continue;
                    }
                    curmaterial = parts[1];
                    if (!m_Model.m_Materials.ContainsKey(curmaterial))
                    {
                        curmaterial = "default_white";
                        AddWhiteMat(currentBone);
                    }
                    break;

                case "v":     // vertex
                {
                    if (parts.Length < 4)
                    {
                        continue;
                    }
                    float x = Helper.ParseFloat(parts[1]);
                    float y = Helper.ParseFloat(parts[2]);
                    float z = Helper.ParseFloat(parts[3]);
                    float w = 1f;         //(parts.Length < 5) ? 1f : Helper.ParseFloat(parts[4]);

                    m_Vertices.Add(new Vector4(x, y, z, w));
                    m_VertexBoneIDs.Add(currentBoneIndex);
                }
                break;

                case "vt":     // texcoord
                {
                    if (parts.Length < 2)
                    {
                        continue;
                    }
                    float s = Helper.ParseFloat(parts[1]);
                    float t = (parts.Length < 3) ? 0f : Helper.ParseFloat(parts[2]);

                    m_TexCoords.Add(new Vector2(s, t));
                }
                break;

                case "vn":     // normal
                {
                    if (parts.Length < 4)
                    {
                        continue;
                    }
                    float x = Helper.ParseFloat(parts[1]);
                    float y = Helper.ParseFloat(parts[2]);
                    float z = Helper.ParseFloat(parts[3]);

                    Vector3 vec = new Vector3(x, y, z).Normalized();
                    m_Normals.Add(vec);
                }
                break;

                case "vc":     // vertex colour (non-standard "Extended OBJ" Blender plugin only)
                {
                    if (parts.Length < 4)
                    {
                        continue;
                    }
                    float r = Helper.ParseFloat(parts[1]);
                    float g = Helper.ParseFloat(parts[2]);
                    float b = Helper.ParseFloat(parts[3]);

                    Color vcolour = Color.FromArgb((int)(r * 255.0f), (int)(g * 255.0f), (int)(b * 255.0f));
                    m_Colours.Add(vcolour);
                }
                break;

                case "f":     // face
                {
                    if (parts.Length < 4)
                    {
                        continue;
                    }
                    int nvtx = parts.Length - 1;

                    if (curmaterial != null)
                    {
                        // If a new object is defined but a material to use not set, we need to use the previous one and add
                        // it to the current bone and its parent
                        if (!m_Model.m_BoneTree.GetBoneByID(currentBone).GetRoot().m_MaterialsInBranch.Contains(curmaterial))
                        {
                            m_Model.m_BoneTree.GetBoneByID(currentBone).GetRoot().m_MaterialsInBranch.Add(curmaterial);
                        }
                        if (!m_Model.m_BoneTree.GetBoneByID(currentBone).m_MaterialsInBranch.Contains(curmaterial))
                        {
                            m_Model.m_BoneTree.GetBoneByID(currentBone).m_MaterialsInBranch.Add(curmaterial);
                        }
                    }
                    else
                    {
                        // No "usemtl" command before declaring face
                        curmaterial = "default_white";
                        AddWhiteMat(currentBone);
                    }

                    ModelBase.BoneDef     bone    = m_Model.m_BoneTree.GetBoneByID(currentBone);
                    ModelBase.GeometryDef geomDef = bone.m_Geometries.Values.ElementAt(0);
                    string polyListKey            = "polylist-" + curmaterial;
                    ModelBase.PolyListDef polyList;
                    if (!geomDef.m_PolyLists.TryGetValue(polyListKey, out polyList))
                    {
                        polyList = new ModelBase.PolyListDef(polyListKey, curmaterial);
                        polyList.m_FaceLists.Add(new ModelBase.FaceListDef());
                        geomDef.m_PolyLists.Add(polyList.m_ID, polyList);
                    }

                    ModelBase.FaceDef face = new ModelBase.FaceDef(nvtx);

                    for (int i = 0; i < nvtx; i++)
                    {
                        string   vtx  = parts[i + 1];
                        string[] idxs = vtx.Split(new char[] { '/' });

                        ModelBase.VertexDef vert = ModelBase.EMPTY_VERTEX;

                        vert.m_Position = new Vector3(m_Vertices[int.Parse(idxs[0]) - 1].Xyz);
                        if (m_Model.m_Materials[curmaterial].m_TextureDefID != null && idxs.Length >= 2 && idxs[1].Length > 0)
                        {
                            vert.m_TextureCoordinate = m_TexCoords[int.Parse(idxs[1]) - 1];
                        }
                        else
                        {
                            vert.m_TextureCoordinate = null;
                        }
                        if (m_Model.m_Materials[curmaterial].m_Lights.Contains(true) && idxs.Length >= 3 && idxs[2].Trim().Length > 0)
                        {
                            vert.m_Normal = new Vector3(m_Normals[int.Parse(idxs[2]) - 1]);
                        }
                        else
                        {
                            vert.m_Normal = null;
                        }
                        // Vertex colours (non-standard "Extended OBJ" Blender plugin only)
                        if (idxs.Length >= 4 && !idxs[3].Equals(""))
                        {
                            Color tmp = m_Colours[int.Parse(idxs[3]) - 1];
                            vert.m_VertexColour = Color.FromArgb(tmp.A, tmp.R, tmp.G, tmp.B);
                        }
                        else
                        {
                            vert.m_VertexColour = Color.White;
                        }
                        vert.m_VertexBoneIndex = currentBoneIndex;

                        face.m_Vertices[i] = vert;
                    }

                    polyList.m_FaceLists[0].m_Faces.Add(face);
                }
                break;
                }
            }

            int count = 0;

            foreach (ModelBase.BoneDef boneDef in m_Model.m_BoneTree)
            {
                m_Model.m_BoneTransformsMap.Add(boneDef.m_ID, count);
                count++;
            }

            sr.Close();

            m_Model.ScaleModel(scale);

            return(m_Model);
        }
 protected static void AddVertexToList(int boneID, Vector2? tex, Vector3? nrm, Vector3 pos, int pos_scale, 
     Color clr, List<ModelBase.VertexDef> vertexList)
 {
     Vector3 scaledPos = Vector3.Multiply(pos, (1 << pos_scale));
     ModelBase.VertexDef vertex = new ModelBase.VertexDef(scaledPos, tex, nrm, clr, boneID);
     vertexList.Add(vertex);
 }