/// <summary> /// lataa md5 model /// </summary> /// <param name="fileName"></param> public void Load(string fileName) { // Initialize everything string line, textureName = ""; int i; Buffer t = new Buffer(); meshCount = 0; using (System.IO.StreamReader file = new System.IO.StreamReader(Settings.DataDir + fileName)) { { while ((line = file.ReadLine()) != null) { Cleanstring(ref line); // Read number of joints if (ParseLine(ref t, line, "numJoints %d")) { numJoints = t.ibuffer[0]; baseSkel = new MD5Joint[numJoints]; } // Read number os meshes if (ParseLine(ref t, line, "numMeshes %d")) { numMesh = t.ibuffer[0]; model = new MD5Mesh[numMesh]; meshes = new List<Vertex[]>(numMesh); } // Parse model joints if (line.Equals("joints {")) { for (i = 0; i < numJoints; i++) { line = file.ReadLine(); Cleanstring(ref line); ParseLine(ref t, line, "%s %d ( %f %f %f ) ( %f %f %f )"); baseSkel[i].name = t.sbuffer; baseSkel[i].parent = t.ibuffer[0]; baseSkel[i].pos.X = t.fbuffer[0]; baseSkel[i].pos.Y = t.fbuffer[1]; baseSkel[i].pos.Z = t.fbuffer[2]; baseSkel[i].orient = new Quaternion(t.fbuffer[3], t.fbuffer[4], t.fbuffer[5], 1); /* jotain tosi outoa.. toi orient homma ei skulaa.. vaik varaa tilaa new:llä, ei toimi.. eikä orient.X = 1; eikä mikään. miks?? */ MathExt.ComputeW(ref baseSkel[i].orient); } } // Parse model meshes if (line.Equals("mesh {")) { while (!line.Equals("}")) { line = file.ReadLine(); Cleanstring(ref line); // Read texture name if (line.StartsWith("shader")) { string str = line.Substring(7); int lp = str.LastIndexOf("/"); textureName = str.Substring(lp + 1); // texturen nimi lp = fileName.LastIndexOf("/"); string dir = fileName.Substring(0, lp + 1); // md5 tiedoston hakemisto textureName = Settings.DataDir + dir + textureName; textureName = textureName.Replace(",", "."); } // Read mesh data if (ParseLine(ref t, line, "numverts %d")) { model[meshCount].numVert = t.ibuffer[0]; model[meshCount].verts = new MD5Vertex[model[meshCount].numVert]; model[meshCount].texture = Texture.Load(textureName, false); for (i = 0; i < model[meshCount].numVert; i++) { line = file.ReadLine(); ParseLine(ref t, line, "vert %d ( %f %f ) %d %d"); model[meshCount].verts[t.ibuffer[0]].uv.X = t.fbuffer[0]; model[meshCount].verts[t.ibuffer[0]].uv.Y = 1 - t.fbuffer[1]; model[meshCount].verts[t.ibuffer[0]].startw = t.ibuffer[1]; model[meshCount].verts[t.ibuffer[0]].countw = t.ibuffer[2]; } } if (ParseLine(ref t, line, "numtris %d")) { model[meshCount].numTris = t.ibuffer[0]; model[meshCount].faces = new int[model[meshCount].numTris][]; for (i = 0; i < model[meshCount].numTris; i++) { line = file.ReadLine(); ParseLine(ref t, line, "tri %d %d %d %d"); model[meshCount].faces[t.ibuffer[0]] = new int[3]; model[meshCount].faces[t.ibuffer[0]][0] = t.ibuffer[3]; // poly toisin päin model[meshCount].faces[t.ibuffer[0]][1] = t.ibuffer[2]; model[meshCount].faces[t.ibuffer[0]][2] = t.ibuffer[1]; } } if (ParseLine(ref t, line, "numweights %d")) { model[meshCount].numWeights = t.ibuffer[0]; model[meshCount].weights = new MD5Weight[model[meshCount].numWeights]; for (i = 0; i < model[meshCount].numWeights; i++) { line = file.ReadLine(); ParseLine(ref t, line, "weight %d %d %f ( %f %f %f )"); model[meshCount].weights[t.ibuffer[0]].joint = t.ibuffer[1]; model[meshCount].weights[t.ibuffer[0]].bias = t.fbuffer[0]; model[meshCount].weights[t.ibuffer[0]].pos.X = t.fbuffer[1]; model[meshCount].weights[t.ibuffer[0]].pos.Y = t.fbuffer[2]; model[meshCount].weights[t.ibuffer[0]].pos.Z = t.fbuffer[3]; } } } meshCount++; } } } } int maxvert = 0; for (int k = 0; k < numMesh; k++) { if (model[k].numVert > maxvert) maxvert = model[k].numVert; } for (int k = 0; k < numMesh; k++) { finalVert = new Vector3[maxvert]; normals = new Vector3[maxvert]; } skeleton = baseSkel; updateAnimCount = FramesBetweenAnimUpdate; updateNormalsCount = FramesBetweenNormalsUpdate; // prepare model for rendering PrepareMesh(); for (int q = 0; q < numMesh; q++) { Vertex[] v = meshes[q]; int[] ind = new int[v.Length]; for (int w = 0; w < ind.Length; w++) ind[w] = w; // luo vbo ja datat sinne model[q].vbo = new VBO(BufferUsageHint.DynamicDraw); model[q].vbo.DataToVBO(v, ind); } material = new Material("default"); MaterialName = "default"; Log.WriteDebugLine("Model: " + Name); }
/// <summary> /// lataa materiaalitiedot /// </summary> /// <param name="fileName"></param> /// <param name="loadTextures"></param> public void Load(string fileName, bool loadTextures) { using (System.IO.StreamReader file = new System.IO.StreamReader(fileName)) { // tiedosto muistiin string data = file.ReadToEnd(); // pilko se string[] lines = data.Split('\n'); Material tmpmat = null; for (int q = 0; q < lines.Length; q++) { string line = lines[q]; line = line.Trim('\r', '\t', ' '); if (line.StartsWith("#")) continue; string[] ln = line.Split(' '); // pilko datat if (ln[0] == "newmtl") { if (tmpmat != null) materials.Add(tmpmat); tmpmat = new Material(); tmpmat.name = ln[1]; Log.WriteDebugLine("MaterialName: " + tmpmat.name); continue; } // Diffuse color texture map if (ln[0] == "map_Kd") { tmpmat.DiffuseTex = new Texture(); if (loadTextures == true) tmpmat.DiffuseTex = Texture.Load(ln[1].ToLower()); continue; } // Specular color texture map if (ln[0] == "map_Ks") { tmpmat.SpecularTex = new Texture(); if (loadTextures == true) tmpmat.SpecularTex = Texture.Load(ln[1].ToLower()); continue; } // Ambient color texture map TAI shaderin nimi if (ln[0] == "map_Ka") { // esim: Shader_cartoon niin ladataan objektille cartoon.vert ja cartoon.frag shaderit. if (ln[1].Contains("Shader_")) { // ota shaderin nimi tmpmat.ShaderName = ln[1].Substring(7); } else //Ambient color texture { tmpmat.AmbientTex = new Texture(); if (loadTextures == true) tmpmat.AmbientTex = Texture.Load(ln[1].ToLower()); } continue; } // Bump color texture map if (ln[0] == "map_Bump") { tmpmat.BumpTex = new Texture(); if (loadTextures == true) tmpmat.BumpTex = Texture.Load(ln[1].ToLower()); continue; } // Opacity color texture map if (ln[0] == "map_d") { tmpmat.OpacityTex = new Texture(); if (loadTextures == true) tmpmat.OpacityTex = Texture.Load(ln[1].ToLower()); continue; } // Phong SpecularTex component if (ln[0] == "Ns") { tmpmat.PhongSpec = Util.GetFloat(ln[1]); continue; } // Ambient color if (ln[0] == "Ka") { tmpmat.AmbientColor = new Vector4(Util.GetFloat(ln[1]), Util.GetFloat(ln[2]), Util.GetFloat(ln[3]), 1); continue; } // Diffuse color if (ln[0] == "Kd") { tmpmat.DiffuseColor = new Vector4(Util.GetFloat(ln[1]), Util.GetFloat(ln[2]), Util.GetFloat(ln[3]), 1); continue; } // Specular color if (ln[0] == "Ks") { tmpmat.SpecularColor = new Vector4(Util.GetFloat(ln[1]), Util.GetFloat(ln[2]), Util.GetFloat(ln[3]), 1); continue; } // Dissolve factor (pistetty alphaks) if (ln[0] == "d") { // alpha value tmpmat.Dissolve = Util.GetFloat(ln[1]); tmpmat.DiffuseColor.W = tmpmat.Dissolve; tmpmat.AmbientColor.W = tmpmat.Dissolve; tmpmat.SpecularColor.W = tmpmat.Dissolve; continue; } } if (tmpmat != null) materials.Add(tmpmat); } }
/// <summary> /// lataa mesh tiedosto /// </summary> /// <param name="fileName"></param> /// <param name="xs"></param> /// <param name="ys"></param> /// <param name="zs"></param> public void Load(string fileName, float xs, float ys, float zs) { pathData.Clear(); ObjModel mesh = null; List<Vector3> _vertex = new List<Vector3>(); List<Vector3> _normal = new List<Vector3>(); List<Vector2> _uv = new List<Vector2>(); string dir = Settings.DataDir; if (fileName.Contains("\\")) { int l = fileName.LastIndexOf("\\"); dir = dir + fileName.Substring(0, l + 1); } else if (fileName.Contains("/")) { int l = fileName.LastIndexOf("/"); dir = dir + fileName.Substring(0, l + 1); } fileName = Settings.DataDir + fileName; bool path = false; // jos reitti using (System.IO.StreamReader file = new System.IO.StreamReader(fileName)) { // tiedosto muistiin string data = file.ReadToEnd(); data = data.Replace('\r', ' '); // pilko se string[] lines = data.Split('\n'); int numOfFaces = 0; for (int q = 0; q < lines.Length; q++) { string[] ln = lines[q].Split(' '); // pilko datat if (ln[0] == "f") numOfFaces++; } // lue kaikki datat objektiin ja indexit mesheihin for (int q = 0; q < lines.Length; q++) { string line = lines[q]; if (line.StartsWith("#")) continue; string[] ln = line.Split(' '); // pilko datat if (ln[0] == "v") // vertex x y z { float x = (Util.GetFloat(ln[1]) - mesh.Position.X) * xs; float y = (Util.GetFloat(ln[2]) - mesh.Position.Y) * ys; float z = (Util.GetFloat(ln[3]) - mesh.Position.Z) * zs; if (path) pathData.Add(new Vector3(x, y, z)); else _vertex.Add(new Vector3(x, y, z)); continue; } if (ln[0] == "vn") // normal x y z { _normal.Add(new Vector3(Util.GetFloat(ln[1]), Util.GetFloat(ln[2]), Util.GetFloat(ln[3]))); continue; } if (ln[0] == "vt") // texcoord U V { _uv.Add(new Vector2(Util.GetFloat(ln[1]), Util.GetFloat(ln[2]))); continue; } // uusi objekti if (ln[0] == "o" || ln[0] == "g") { if (mesh != null) meshes.Add(mesh); // talteen mesh = new ObjModel(ln[1]); mesh.material = material; // Nimessä voi olla ohjeita mitä muuta halutaan, esim: // * Path_reitti1 jolloin ei ladata objektia mutta reitti jota pitkin kamera/objektit voi kulkea. // * BBox_nimi/BSphere_nimi jolloin tämä onkin nimi-objektin bounding box/sphere. if (mesh.Name.Contains("Path_")) { path = true; } else if (mesh.Name.Contains("BBox_") || mesh.Name.Contains("BSphere_")) { // TODO: bbox_ bsphere_ } continue; } // materiaali if (ln[0] == "usemtl") { // jos kesken meshin materiaali vaihtuu, luodaan uusi obu johon loput facet if (lines[q - 1].StartsWith("f")) { meshes.Add(mesh); Vector3 tmpPos = mesh.Position; mesh = new ObjModel(mesh.Name); mesh.material = material; mesh.Position = tmpPos; // samaa objektia, niin sama Position } mesh.MaterialName = ln[1]; continue; } if (ln[0] == "f") { // ota talteen f rivi: // f vertex/uv/normal vertex/uv/normal vertex/uv/normal // eli esim: f 4/4/2 5/5/3 7/2/4 // tarkistetaan jos ilman texcoordei eli f 4/4 5/4 6/4 tai f 2//3 jne tai ilman / merkkejä. int dv = 0; for (int t = 0; t < line.Length; t++) if (line[t] == '/') dv++; if (line.Contains("//")) dv = 0; // ei ole texindexei line = line.Replace("//", " "); line = line.Replace("/", " "); string[] _ln = line.Split(' '); if (dv == 0 || dv == 3) // luultavasti nyt ei ole texturecoordinaatteja { mesh._vertexInd.Add(Int32.Parse(_ln[1]) - 1); mesh._vertexInd.Add(Int32.Parse(_ln[3]) - 1); mesh._vertexInd.Add(Int32.Parse(_ln[5]) - 1); mesh._normalInd.Add(Int32.Parse(_ln[2]) - 1); mesh._normalInd.Add(Int32.Parse(_ln[4]) - 1); mesh._normalInd.Add(Int32.Parse(_ln[6]) - 1); } else // kaikki mukana { mesh._vertexInd.Add(Int32.Parse(_ln[1]) - 1); mesh._vertexInd.Add(Int32.Parse(_ln[4]) - 1); mesh._vertexInd.Add(Int32.Parse(_ln[7]) - 1); mesh._uvInd.Add(Int32.Parse(_ln[2]) - 1); mesh._uvInd.Add(Int32.Parse(_ln[5]) - 1); mesh._uvInd.Add(Int32.Parse(_ln[8]) - 1); mesh._normalInd.Add(Int32.Parse(_ln[3]) - 1); mesh._normalInd.Add(Int32.Parse(_ln[6]) - 1); mesh._normalInd.Add(Int32.Parse(_ln[9]) - 1); } continue; } // materiaalitiedosto if (ln[0] == "mtllib") { try { // ladataan objektille materiaalitiedot (mesheille otetaan talteen materialname joka viittaa sitten näihin materiaaleihin) material = new Material(); material.Load(dir + ln[1], Texture.LoadTextures); } catch (Exception e) { Log.WriteDebugLine(e.ToString()); } } } if (mesh != null) meshes.Add(mesh); // pathille ei luoda objektia, se on vain kasa vertexejä if (path == false) { int cc = 0; vertices = new Vertex[numOfFaces * 3]; for (int m = 0; m < meshes.Count; m++) { meshes[m].vertices = new Vertex[meshes[m]._vertexInd.Count]; for (int q = 0; q < meshes[m]._vertexInd.Count; q++) { // mesh datat meshes[m].vertices[q].vertex = _vertex[meshes[m]._vertexInd[q]]; meshes[m].vertices[q].normal = _normal[meshes[m]._normalInd[q]]; if (meshes[m]._uvInd.Count != 0) meshes[m].vertices[q].uv_or_color = new Vector4(_uv[meshes[m]._uvInd[q]].X, _uv[meshes[m]._uvInd[q]].Y, _uv[meshes[m]._uvInd[q]].X, _uv[meshes[m]._uvInd[q]].Y); // pistetään myös objektille kaikki vertexit yhteen klimppiin. //TODO Miks? vie vaa muistia nii paljo, mesheissä kumminki nuo datat säilytetään. // jos tää on VAIN collisionia varten, siihe ny o helppo tehdä se et se menee objektin puun läpi // ni sit ei tartte tätä vertices[cc].vertex = _vertex[meshes[m]._vertexInd[q]]; vertices[cc].normal = _normal[meshes[m]._normalInd[q]]; if (meshes[m]._uvInd.Count != 0) vertices[cc].uv_or_color = new Vector4(_uv[meshes[m]._uvInd[q]].X, _uv[meshes[m]._uvInd[q]].Y, _uv[meshes[m]._uvInd[q]].X, _uv[meshes[m]._uvInd[q]].Y); cc++; } // index taulukko meshes[m].indices = new int[meshes[m]._vertexInd.Count]; for (int q = 0; q < meshes[m]._vertexInd.Count; q++) meshes[m].indices[q] = q; meshes[m].vbo = new VBO(); meshes[m].vbo.DataToVBO(meshes[m].vertices, meshes[m].indices); // meshin bounding volume meshes[m].Boundings = new BoundingVolume(); meshes[m].Boundings.CreateBoundingVolume(meshes[m]); // lataa glsl koodit string shader = material.GetMaterial(meshes[m].MaterialName).ShaderName; if (shader != "") { mesh.Shader = new GLSL(); mesh.Shader.Load(shader + ".vert", shader + ".frag"); } if (material.GetMaterial(meshes[m].MaterialName).Dissolve < 1.0f) IsTranslucent = true; } // koko objektin bounding volume IsRendObj = false; // childeissä rendattavat objektit, tässä ei ole rendattavaa, vain paikka Boundings = new BoundingVolume(); Boundings.CreateBoundingVolume(this); // lisätään objektille meshit childeiks for (int q = 0; q < meshes.Count; q++) { Add(meshes[q]); } Log.WriteDebugLine("Object: " + Name + " meshes: " + meshes.Count); } _vertex.Clear(); _normal.Clear(); _uv.Clear(); for (int q = 0; q < meshes.Count; q++) { meshes[q]._vertexInd.Clear(); meshes[q]._normalInd.Clear(); meshes[q]._uvInd.Clear(); } } }