Example #1
0
        /// <summary>
        /// Loads a TTModel file from a given SQLite3 DB filepath.
        /// </summary>
        public static TTModel FromDb(FileInfo file, Action <bool, string> loggingFunction = null)
        {
            if (loggingFunction == null)
            {
                loggingFunction = ModelModifiers.NoOp;
            }

            string  connectionString = "Data Source=" + file + ";";
            TTModel model            = new TTModel();

            model.Source = file.FullName;

            // Spawn a DB connection to do the raw queries.
            using (SqliteConnection db = new SqliteConnection(connectionString))
            {
                db.Open();

                // Load Mesh Groups
                string query = "select * from meshes order by mesh asc;";
                using (SqliteCommand cmd = new SqliteCommand(query, db))
                {
                    using (CacheReader reader = new CacheReader(cmd.ExecuteReader()))
                    {
                        while (reader.NextRow())
                        {
                            int meshNum = reader.GetInt32("mesh");

                            // Spawn mesh groups as needed.
                            while (model.MeshGroups.Count <= meshNum)
                            {
                                model.MeshGroups.Add(new TTMeshGroup());
                            }

                            model.MeshGroups[meshNum].Name = reader.GetString("name");
                        }
                    }
                }

                // Load Mesh Parts
                query = "select * from parts order by mesh asc, part asc;";
                using (SqliteCommand cmd = new SqliteCommand(query, db))
                {
                    using (CacheReader reader = new CacheReader(cmd.ExecuteReader()))
                    {
                        while (reader.NextRow())
                        {
                            int meshNum = reader.GetInt32("mesh");
                            int partNum = reader.GetInt32("part");

                            // Spawn mesh groups if needed.
                            while (model.MeshGroups.Count <= meshNum)
                            {
                                model.MeshGroups.Add(new TTMeshGroup());
                            }

                            // Spawn parts as needed.
                            while (model.MeshGroups[meshNum].Parts.Count <= partNum)
                            {
                                model.MeshGroups[meshNum].Parts.Add(new TTMeshPart());
                            }

                            model.MeshGroups[meshNum].Parts[partNum].Name = reader.GetString("name");
                        }
                    }
                }

                // Load Bones
                query = "select * from bones where mesh >= 0 order by mesh asc, bone_id asc;";
                using (SqliteCommand cmd = new SqliteCommand(query, db))
                {
                    using (CacheReader reader = new CacheReader(cmd.ExecuteReader()))
                    {
                        while (reader.NextRow())
                        {
                            int meshId = reader.GetInt32("mesh");
                            model.MeshGroups[meshId].Bones.Add(reader.GetString("name"));
                        }
                    }
                }
            }

            // Loop for each part, to populate their internal data structures.
            for (int mId = 0; mId < model.MeshGroups.Count; mId++)
            {
                TTMeshGroup m = model.MeshGroups[mId];
                for (int pId = 0; pId < m.Parts.Count; pId++)
                {
                    TTMeshPart p = m.Parts[pId];
                    WhereClause where = new WhereClause();
                    WhereClause mWhere = new WhereClause();
                    mWhere.Column = "mesh";
                    mWhere.Value  = mId;
                    WhereClause pWhere = new WhereClause();
                    pWhere.Column = "part";
                    pWhere.Value  = pId;

                    where.Inner.Add(mWhere);
                    where.Inner.Add(pWhere);

                    // Load Vertices
                    // The reader handles coalescing the null types for us.
                    p.Vertices = BuildListFromTable(connectionString, "vertices", where, (reader) =>
                    {
                        TTVertex vertex = new TTVertex();

                        // Positions
                        vertex.Position.X = reader.GetFloat("position_x");
                        vertex.Position.Y = reader.GetFloat("position_y");
                        vertex.Position.Z = reader.GetFloat("position_z");

                        // Normals
                        vertex.Normal.X = reader.GetFloat("normal_x");
                        vertex.Normal.Y = reader.GetFloat("normal_y");
                        vertex.Normal.Z = reader.GetFloat("normal_z");

                        // Vertex Colors - Vertex color is RGBA
                        vertex.VertexColor[0] = (byte)Math.Round(reader.GetFloat("color_r") * 255);
                        vertex.VertexColor[1] = (byte)Math.Round(reader.GetFloat("color_g") * 255);
                        vertex.VertexColor[2] = (byte)Math.Round(reader.GetFloat("color_b") * 255);
                        vertex.VertexColor[3] = (byte)Math.Round(reader.GetFloat("color_a") * 255);

                        // UV Coordinates
                        vertex.UV1.X = reader.GetFloat("uv_1_u");
                        vertex.UV1.Y = reader.GetFloat("uv_1_v");
                        vertex.UV2.X = reader.GetFloat("uv_2_u");
                        vertex.UV2.Y = reader.GetFloat("uv_2_v");

                        // Bone Ids
                        vertex.BoneIds[0] = (byte)reader.GetByte("bone_1_id");
                        vertex.BoneIds[1] = (byte)reader.GetByte("bone_2_id");
                        vertex.BoneIds[2] = (byte)reader.GetByte("bone_3_id");
                        vertex.BoneIds[3] = (byte)reader.GetByte("bone_4_id");

                        // Weights
                        vertex.Weights[0] = (byte)Math.Round(reader.GetFloat("bone_1_weight") * 255);
                        vertex.Weights[1] = (byte)Math.Round(reader.GetFloat("bone_2_weight") * 255);
                        vertex.Weights[2] = (byte)Math.Round(reader.GetFloat("bone_3_weight") * 255);
                        vertex.Weights[3] = (byte)Math.Round(reader.GetFloat("bone_4_weight") * 255);

                        return(vertex);
                    });

                    p.TriangleIndices = BuildListFromTable(connectionString, "indices", where, (reader) =>
                    {
                        try
                        {
                            return(reader.GetInt32("vertex_id"));
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    });
                }
            }

            // Spawn a DB connection to do the raw queries.
            using (SqliteConnection db = new SqliteConnection(connectionString))
            {
                db.Open();

                // Load Shape Verts
                string query = "select * from shape_vertices order by shape asc, mesh asc, part asc, vertex_id asc;";
                using (SqliteCommand cmd = new SqliteCommand(query, db))
                {
                    using (CacheReader reader = new CacheReader(cmd.ExecuteReader()))
                    {
                        while (reader.NextRow())
                        {
                            string shapeName = reader.GetString("shape");
                            int    meshNum   = reader.GetInt32("mesh");
                            int    partNum   = reader.GetInt32("part");
                            int    vertexId  = reader.GetInt32("vertex_id");

                            TTMeshPart part = model.MeshGroups[meshNum].Parts[partNum];

                            // Copy the original vertex and update position.
                            TTVertex vertex = (TTVertex)part.Vertices[vertexId].Clone();
                            vertex.Position.X = reader.GetFloat("position_x");
                            vertex.Position.Y = reader.GetFloat("position_y");
                            vertex.Position.Z = reader.GetFloat("position_z");

                            TTVertex repVert = part.Vertices[vertexId];
                            if (repVert.Position.Equals(vertex.Position))
                            {
                                // Skip morphology which doesn't actually change anything.
                                continue;
                            }

                            if (!part.ShapeParts.ContainsKey(shapeName))
                            {
                                TTShapePart shpPt = new TTShapePart();
                                shpPt.Name = shapeName;
                                part.ShapeParts.Add(shapeName, shpPt);
                            }

                            part.ShapeParts[shapeName].VertexReplacements.Add(vertexId, part.ShapeParts[shapeName].Vertices.Count);
                            part.ShapeParts[shapeName].Vertices.Add(vertex);
                        }
                    }
                }
            }

            // Convert the model to FFXIV's internal weirdness.
            ModelModifiers.MakeImportReady(model, loggingFunction);
            return(model);
        }