public bool SaveDecalMesh(DMesh dm, string path_to_file, bool silent = false) { try { JObject root = new JObject(); dm.DeconvertPolysToTris(); dm.Serialize(root); string new_file_data = root.ToString(Formatting.Indented); File.WriteAllText(path_to_file, new_file_data); if (!silent) { this.m_filepath_current_decal = path_to_file; this.Text = "Overload DMesh Editor - " + path_to_file; AddOutputText(string.Format("Saved decal: {0}", path_to_file)); AddRecentFile(path_to_file); dm.dirty = false; } return(true); } catch (Exception ex) { Utility.DebugLog("Failed to save decal mesh: " + ex.Message); return(false); } }
public Vector3 ClosestTwoVertsDirection(Vector3 pos, int original_vert, DMesh dmesh) { int v1 = -1, v2 = -1; for (int i = 0; i < num_verts; i++) { if (vert[(i + 1) % num_verts] == original_vert) { v1 = i; } if (vert[(i + num_verts - 1) % num_verts] == original_vert) { v2 = i; } } if (v1 > -1 && v2 > -1) { return(((dmesh.vertex[vert[v1]] - pos).Normalized() + (dmesh.vertex[vert[v2]] - pos).Normalized()).Normalized()); } else { return(Vector3.UnitY); } }
private void button_copy_Click(object sender, EventArgs e) { string name = InputBox.GetInput("Copy Decal", "Enter a name for this decal (must be valid filename)", ""); if (name == null) { return; } if (m_decal_list.IndexOf((string)name) != -1) { MessageBox.Show("Name '" + name + "' already used for a decal."); return; } DMesh src = m_active_dmesh; m_active_dmesh = new DMesh(""); m_active_dmesh.CopyDMesh(src); m_active_dmesh.name = name; SaveDecalMesh(m_active_dmesh); m_dmesh.Add(m_active_dmesh); m_decal_list.Add(m_active_dmesh.name); m_decal_readonly.Add(false); ListboxUpdate(m_active_dmesh.name); UpdateActiveDMesh(); gl_custom.Invalidate(); }
public void ReSortVerts(DMesh dmesh) { List <int> sort_vrt = new List <int>(); List <Vector2> sort_uv = new List <Vector2>(); List <Vector3> sort_norm = new List <Vector3>(); // Sort clockwise for (int i = 0; i < vert.Count; i++) { sort_vrt.Add(vert[i]); } sort_vrt = SortVertsForPlanar(sort_vrt, dmesh); // Get the other properties sorted for (int i = 0; i < sort_vrt.Count; i++) { int idx = FindVertByIndex(sort_vrt[i]); sort_uv.Add(tex_uv[idx]); sort_norm.Add(normal[idx]); } // Copy to the real lists ClearLists(); for (int i = 0; i < sort_vrt.Count; i++) { vert.Add(sort_vrt[i]); tex_uv.Add(sort_uv[i]); normal.Add(sort_norm[i]); } }
public void BuildVertNormals(DMesh dm) { GL.PushMatrix(); GL.DeleteLists(GL_VERT_NORMALS, 1); GL.NewList(GL_VERT_NORMALS, ListMode.Compile); { GL.Color3(Color.Green); for (int i = 0; i < dm.polygon.Count; i++) { if (dm.polygon[i].flags == (int)FaceFlags.NO_COLLIDE) { if (editor.m_vis_type == VisibilityType.NO_RENDER || editor.m_vis_type == VisibilityType.NORMAL_ONLY) { continue; } } else if (dm.polygon[i].flags == (int)FaceFlags.NO_RENDER) { if (editor.m_vis_type == VisibilityType.NO_COLLIDE || editor.m_vis_type == VisibilityType.NORMAL_ONLY) { continue; } } else if (dm.polygon[i].flags == (int)FaceFlags.NO_COLLIDE + (int)FaceFlags.NO_RENDER) { // This is a pointless face } else { } GL.Begin(PrimitiveType.Lines); CreateVertNormals(dm.polygon[i], dm); GL.End(); } } GL.EndList(); GL.PopMatrix(); }
public bool SaveDecalMesh(DMesh dm) { string path_to_file = Path.ChangeExtension(Path.Combine(editor.m_filepath_decals, dm.name), ".dmesh"); try { JObject root = new JObject(); dm.Serialize(root); string new_file_data = root.ToString(Formatting.Indented); if (File.Exists(path_to_file)) { // if the file already exists, and it is the same, do not write it // out - preserving file timestamps try { string old_file_data = File.ReadAllText(path_to_file); if (old_file_data == new_file_data) { // ignore - nothing changed return(true); } } catch { } } File.WriteAllText(path_to_file, new_file_data); return(true); } catch (Exception ex) { Utility.DebugLog("Failed to save decal mesh: " + ex.Message); return(false); } }
// Make sure you reset AddedVert to -1 if doing a new cut (it's meant to cache a vert for cutting multiple edges at once) public void MaybeAddVertBetween(int v1, int v2, DMesh dmesh) { for (int i = 0; i < num_verts; i++) { if (v1 == vert[i]) { if (i > 0 && (vert[i - 1] == v2)) { AddVertBetween(i - 1, i, dmesh); return; } else if (i < num_verts - 1 && vert[i + 1] == v2) { AddVertBetween(i, i + 1, dmesh); return; } else if (i == 0 && v2 == vert[num_verts - 1]) { AddVertBetween(num_verts - 1, 0, dmesh); return; } else if (v2 == vert[0] && i == num_verts - 1) { AddVertBetween(num_verts - 1, 0, dmesh); return; } } } }
public void LoadDecalsInDir(string dir, bool all_dir = false) { if (!Directory.Exists(dir)) { return; } string[] files = Directory.GetFiles(dir, "*.dmesh", (all_dir ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)); m_dmesh = new List <DMesh>(); foreach (string file in files) { // Remove all the extra stuff to get the names string mesh_name = Utility.GetRelativeExtensionlessFilenameFromDirectory(dir, file); m_decal_list.Add(mesh_name); m_decal_readonly.Add(m_builtin_decal_list.Contains(mesh_name) ? true : false); // Load the decal into memory m_active_dmesh = new DMesh(mesh_name); LoadDecalMesh(m_active_dmesh, file); m_active_dmesh.UpdateGLTextures(tex_manager, editor.tm_level); m_dmesh.Add(m_active_dmesh); } UpdateActiveDMesh(); }
public float ClosestTwoVertsArea(Vector3 pos, int original_vert, DMesh dmesh) { int v1 = -1, v2 = -1; for (int i = 0; i < num_verts; i++) { if (vert[(i + 1) % num_verts] == original_vert) { v1 = i; } if (vert[(i + num_verts - 1) % num_verts] == original_vert) { v2 = i; } } if (v1 > -1 && v2 > -1) { return(Utility.AreaOfTriangle(pos, dmesh.vertex[vert[v1]], dmesh.vertex[vert[v2]])); } else { return(9999f); } }
public float ClosestTwoVertsDot(Vector3 pos, int original_vert, DMesh dmesh) { int v1 = -1, v2 = -1; for (int i = 0; i < num_verts; i++) { if (vert[(i + 1) % num_verts] == original_vert) { v1 = i; } if (vert[(i + num_verts - 1) % num_verts] == original_vert) { v2 = i; } } if (v1 > -1 && v2 > -1) { return(Vector3.Dot((dmesh.vertex[vert[v1]] - pos).Normalized(), (dmesh.vertex[vert[v2]] - pos).Normalized())); } else { return(9999f); } }
public void AddLights(DMesh dm, Vector3 offset) { var src_enabled_lights = dm.light.Where(l => l.enabled).ToList(); if (src_enabled_lights.Count == 0) { return; } // Currently, this creates the geometry in World space Matrix4 decal_space_to_segment_space = Matrix4.CreateRotationX(-Utility.RAD_90); Matrix4 decal_space_to_world_space = Matrix4.Mult(decal_space_to_segment_space, this.m_base_rot); foreach (var src_light in src_enabled_lights) { Vector3 world_pos = Vector3.Transform(src_light.position, decal_space_to_world_space) + offset; if (src_light.style == LightStyle.POINT) { AddPointLight(world_pos, src_light.flare, src_light.color_index, src_light.intensity, src_light.range); } else if (src_light.style == LightStyle.POINT_NO_SHADOW) { AddPointLight(world_pos, src_light.flare, src_light.color_index, src_light.intensity, src_light.range, false); } else if (src_light.style == LightStyle.SPOT || src_light.style == LightStyle.SPOT_NO_SHADOW) { Matrix4 world_orient = src_light.rotation * decal_space_to_world_space; AddSpotLight(world_pos, world_orient, src_light.angle, src_light.flare, src_light.color_index, src_light.intensity, src_light.range, src_light.style == LightStyle.SPOT); } } }
public bool LoadDecalMesh(DMesh dm, string path_to_file) { dm.Init(this); try { string file_data = System.IO.File.ReadAllText(path_to_file); JObject root = JObject.Parse(file_data); dm.Deserialize(root); dm.UpdateGLTextures(tm_decal); this.m_filepath_current_decal = path_to_file; this.Text = "Overload DMesh Editor - " + path_to_file; AddOutputText(string.Format("Loaded dmesh: {0}", path_to_file)); AddRecentFile(path_to_file); dm.dirty = false; if (!dm.WasConverted()) { m_dmesh.ConvertTrisToPolysRaw(); dm.dirty = true; } UpdateOptionLabels(); return(true); } catch (Exception ex) { Utility.DebugLog("Failed to load decal mesh: " + ex.Message); return(false); } }
// Find the closest edge (avg pos between two verts) on the selected polygon for the view/pos, returns the first of the verts in the edge public int GetClosestEdgeFV(GLView view, DMesh dmesh, Vector3 pos, int exclude_vert, bool update_cut_pos = false) { int closest_edge = -1; float closest_dist = 9999f; float dist; Vector3 edge_pos; for (int i = 0; i < num_verts; i++) { if (i != exclude_vert) { edge_pos = dmesh.vertex[vert[i]] + dmesh.vertex[vert[(i + 1) % num_verts]]; edge_pos *= 0.5f; edge_pos = Utility.NullifyAxisForView(edge_pos, view.m_view_type); dist = (pos - edge_pos).Length; if (dist < closest_dist) { if (update_cut_pos) { Editor.POLYCUT_POS = edge_pos; } closest_dist = dist; closest_edge = i; } } } return(closest_edge); }
public bool ImportOBJ(DMesh dm, string path_to_file) { dm.Init(this); try { if (!OverloadLevelEditor.ImportOBJ.ImportOBJToDMesh(dm, path_to_file, false, this, tm_decal)) { return(false); } dm.UpdateGLTextures(tm_decal); dm.dirty = false; if (!dm.WasConverted()) { m_dmesh.ConvertTrisToPolysRaw(); dm.dirty = true; } UpdateOptionLabels(); return(true); } catch (Exception ex) { Utility.DebugPopup("Failed to load OBJ: " + ex.Message, "Error"); return(false); } }
// Can you combine this poly with the passed in one public static bool CanCombinePolys(DPoly p1, DPoly p2, DMesh dm) { // First check for two shared verts int count = 0; for (int i = 0; i < p1.num_verts; i++) { for (int j = 0; j < p2.num_verts; j++) { if (p1.vert[i] == p2.vert[j]) { count += 1; } } } if (count != 2) { return(false); } // Check for normals that align Vector3 n1 = CalculatePolyNormal(p1, dm); Vector3 n2 = CalculatePolyNormal(p2, dm); if (Vector3.Dot(n1, n2) >= 0.995f) { return(true); } else { return(false); } }
public void BuildDecalMeshOutline(DMesh dm) { GL.PushMatrix(); GL.DeleteLists(GL_DECAL_OUTLINE, 1); GL.NewList(GL_DECAL_OUTLINE, ListMode.Compile); { for (int i = 0; i < dm.polygon.Count; i++) { if (dm.polygon[i].flags == (int)FaceFlags.NO_COLLIDE) { if (editor.m_vis_type == VisibilityType.NO_RENDER || editor.m_vis_type == VisibilityType.NORMAL_ONLY) { continue; } } else if (dm.polygon[i].flags == (int)FaceFlags.NO_RENDER) { if (editor.m_vis_type == VisibilityType.NO_COLLIDE || editor.m_vis_type == VisibilityType.NORMAL_ONLY) { continue; } } GL.Begin(PrimitiveType.Polygon); CreatePolygon(dm.polygon[i], dm); GL.End(); } } GL.EndList(); GL.PopMatrix(); }
// Create a polygon from a list of verts and the DMesh reference public DPoly(List <int> vrts, int tex_idx, DMesh dmesh, bool sort = false) { if (sort) { vrts = SortVertsForPlanar(vrts, dmesh); } num_verts = vrts.Count; ClearLists(); for (int i = 0; i < num_verts; i++) { vert.Add(vrts[i]); normal.Add(Vector3.UnitY); tex_uv.Add(Vector2.Zero); } tex_index = tex_idx; flags = 0; marked = false; // Calculate the properties Vector3 n = CalculatePolyNormal(this, dmesh); for (int i = 0; i < num_verts; i++) { normal[i] = n; } DefaultAlignment(dmesh); }
// Note: Assumes a (mostly?) convex polygon public List <int> SortVertsForPlanar(List <int> orig_list, DMesh dmesh) { Vector3 center = FindCenter(orig_list, dmesh); Vector3 normal = Utility.FindNormal(dmesh.vertex[orig_list[0]], dmesh.vertex[orig_list[1]], dmesh.vertex[orig_list[2]]); Vector3 v0 = (Utility.ProjectOntoPlane(dmesh.vertex[orig_list[0]], center, normal) - center).Normalized(); Vector3 cross = Vector3.Cross(normal, v0); // We're basically getting polar co-ordinates for each vertex relative to the center of the face // and the first vertex of the face. We can then sort the vertex list in ascending order of angle. // (The previous system was not resilient to "spiral" vertex orders.) var vertAngles = new SortedDictionary <int, float>(); foreach (int vertex in orig_list) { Vector3 v = (Utility.ProjectOntoPlane(dmesh.vertex[vertex], center, normal) - center).Normalized(); float x = Vector3.Dot(v, v0); float y = Vector3.Dot(v, cross); float angle = (float)Math.Atan2(y, x); if (angle < 0) { angle += (float)(2 * Math.PI); } vertAngles[vertex] = angle; } return(orig_list.OrderBy(vert => vertAngles[vert]).ToList()); }
public void ImportOBJToDecalDialog(bool replace) { int old_active_dmesh_index = m_decal_list.IndexOf((string)m_active_dmesh.name); using (OpenFileDialog od = new OpenFileDialog()) { od.AddExtension = true; od.CheckFileExists = true; od.CheckPathExists = true; od.DefaultExt = ".obj"; od.Filter = "OBJ mesh files (*.obj) | *.obj"; od.Multiselect = false; od.Title = "Import an OBJ mesh file"; od.InitialDirectory = editor.m_filepath_decals + "\\OBJ"; DialogResult res = od.ShowDialog(); if (res != DialogResult.OK) { return; } m_active_dmesh = new DMesh(replace ? m_active_dmesh.name : ""); bool saved = ImportOBJToDecal(od.FileName); if (!saved) { listbox.SetSelected(old_active_dmesh_index, true); return; } if (replace) { m_dmesh[m_cur_dmesh] = m_active_dmesh; } else { string name = InputBox.GetInput("Import Decal Mesh", "Enter a name for this decal (must be valid filename)", ""); if (name == null) { listbox.SetSelected(old_active_dmesh_index, true); return; } if (m_decal_list.IndexOf((string)name) != -1) { MessageBox.Show("Name '" + name + "' already used for a decal."); listbox.SetSelected(old_active_dmesh_index, true); return; } m_active_dmesh.name = name; SaveDecalMesh(m_active_dmesh); m_dmesh.Add(m_active_dmesh); m_decal_list.Add(m_active_dmesh.name); m_decal_readonly.Add(false); ListboxUpdate(m_active_dmesh.name); } UpdateActiveDMesh(); gl_custom.Invalidate(); } }
public void CreateTriangle(DTriangle tri, DMesh mesh) { for (int i = 0; i < 3; i++) { GL.TexCoord2(tri.tex_uv[i]); GL.Normal3(tri.normal[i]); GL.Vertex3(mesh.vertex[tri.vert[i]]); } }
public void CreateVertNormals(DPoly poly, DMesh mesh) { Vector3 v; for (int i = 0; i < poly.num_verts; i++) { v = mesh.vertex[poly.vert[i]]; CreateLine(v, v + poly.normal[i] * 0.1f); } }
public void CreatePolygon(DPoly poly, DMesh mesh) { for (int i = 0; i < poly.num_verts; i++) { GL.TexCoord2(poly.tex_uv[i]); GL.Normal3(poly.normal[i]); GL.Vertex3(mesh.vertex[poly.vert[i]]); } }
public static Vector3 CalculatePolyNormal(DPoly p, DMesh dm) { Vector3 n = Vector3.Zero; n = Utility.FindNormal(dm.vertex[p.vert[0]], dm.vertex[p.vert[1]], dm.vertex[p.vert[2]]); return(n); }
public void UndoInit() { for (int i = 0; i < MAX_UNDOS; i++) { m_undo_dmesh[i] = new DMesh("undo_dmesh" + i.ToString()); m_undo_name[i] = ""; } }
public void CopyMarkedPolys(DMesh src, bool all = false, bool tag_new = false) { // Tag all the src verts in marked polys List <int> old_vert_index = new List <int>(); List <int> new_vert_index = new List <int>(); src.TagAllVerts(false); ClearAllMarkedPoly(); foreach (DPoly dp in src.polygon) { if (dp.marked || all) { for (int i = 0; i < dp.num_verts; i++) { src.vert_info[dp.vert[i]].tag = true; } } } // Copy all tagged verts to me // - And create lists for conversion for (int i = 0; i < src.vertex.Count; i++) { if (src.vert_info[i].tag) { old_vert_index.Add(i); new_vert_index.Add(vertex.Count); vertex.Add(src.vertex[i]); vert_info.Add(new DVert()); } } // Copy all marked polys to me (converting vert idxs in process) foreach (DPoly old_dp in src.polygon) { if (old_dp.marked || all) { DPoly new_dp = new DPoly(old_dp); polygon.Add(new_dp); new_dp.marked = true; new_dp.tag = tag_new; for (int i = 0; i < new_dp.num_verts; i++) { int old_index = new_dp.vert[i]; old_index = FindIdxInList(old_index, old_vert_index); if (old_index > -1 && old_index < new_vert_index.Count) { new_dp.vert[i] = new_vert_index[old_index]; } else { Utility.DebugPopup("This is bad, copy-paste failed", "ERROR!"); } } } } }
public void CreateLinesFromVertNormals(DTriangle tri, DMesh mesh) { GL.Vertex3(mesh.vertex[tri.vert[0]]); GL.Vertex3(mesh.vertex[tri.vert[0]] + tri.normal[0] * 0.1f); GL.Vertex3(mesh.vertex[tri.vert[1]]); GL.Vertex3(mesh.vertex[tri.vert[1]] + tri.normal[1] * 0.1f); GL.Vertex3(mesh.vertex[tri.vert[2]]); GL.Vertex3(mesh.vertex[tri.vert[2]] + tri.normal[2] * 0.1f); }
public void CreateLinesFromTriangle(DTriangle tri, DMesh mesh) { GL.Vertex3(mesh.vertex[tri.vert[0]]); GL.Vertex3(mesh.vertex[tri.vert[1]]); GL.Vertex3(mesh.vertex[tri.vert[1]]); GL.Vertex3(mesh.vertex[tri.vert[2]]); GL.Vertex3(mesh.vertex[tri.vert[2]]); GL.Vertex3(mesh.vertex[tri.vert[0]]); }
public void RecalculateNormal(DMesh dm) { should_normalize = false; face_normal = CalculatePolyNormal(this, dm); for (int i = 0; i < num_verts; i++) { normal[i] = face_normal; } }
public static string DMeshToString(DMesh dm, string file_name) { StringBuilder sb = new StringBuilder(); sb.Append("g ").Append(Utility.GetPathlessFilename(file_name).Split('.')[0]).Append("\n"); foreach (Vector3 v in dm.vertex) { sb.Append(string.Format("v {0} {1} {2}\n", v.X, v.Y, v.Z)); } sb.Append("\n"); // Output the vert normals/UVs in order int idx = 0; foreach (DPoly dp in dm.polygon) { dp.export_list_idx.Clear(); for (int i = 0; i < dp.num_verts; i++) { sb.Append(string.Format("vn {0} {1} {2}\n", dp.normal[i].X, dp.normal[i].Y, dp.normal[i].Z)); sb.Append(string.Format("vt {0} {1}\n", dp.tex_uv[i].X, dp.tex_uv[i].Y)); dp.export_list_idx.Add(idx); idx += 1; } } idx = 0; foreach (String tx_name in dm.tex_name) { sb.Append("\n"); string short_tex_name = Utility.GetPathlessFilename(tx_name); sb.Append("usemtl ").Append(short_tex_name + "\n"); sb.Append("usemap ").Append(short_tex_name + "\n"); foreach (DPoly dp in dm.polygon) { if (dp.tex_index == idx) { sb.Append("f "); for (int i = 0; i < dp.num_verts; i++) { sb.Append(string.Format("{0}/{1}/{1} ", dp.vert[i] + 1, dp.export_list_idx[i] + 1)); } sb.Append("\n"); } } idx += 1; } return(sb.ToString()); }
public Vector3 FindCenter(DMesh dmesh) { Vector3 center = Vector3.Zero; for (int i = 0; i < vert.Count; i++) { center += dmesh.vertex[vert[i]]; } if (vert.Count > 0) { center /= vert.Count; } return(center); }