using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using global::System.Drawing; using Bitmap = System.Drawing.Bitmap; using Color = System.Drawing.Color; using Image = System.Drawing.Image; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Text; using global::System.Threading; using System.Threading.Tasks; using global::System.Windows.Forms; using System.Xml.Linq; using Microsoft.VisualBasic; using Microsoft.VisualBasic.CompilerServices; using OpenTK; using OpenTK.Graphics.OpenGL; using Pilz.S3DFileParser; using Pilz.Drawing.Drawing3D.OpenGLFactory.RenderingN; namespace RenderingN { public partial class Renderer { private Object3D obj3d; private Dictionary dicTextureIDs = new Dictionary(); private Dictionary dicColorIDs = new Dictionary(); private Bitmap emptyTexture = null; private Bitmap lineTexture = null; private Bitmap selectedLineTexture = null; public float ModelScaling { get; set; } = 1.0f; public bool HasRendered { get; private set; } = false; public List SelectedElements { get; private set; } private Dictionary VertexBuffers { get; set; } = new Dictionary(); private Dictionary> IndicesBuffers { get; set; } = new Dictionary>(); private Dictionary UVBuffers { get; set; } = new Dictionary(); private Dictionary VertexColorBuffers { get; set; } = new Dictionary(); private Dictionary NormalBuffers { get; set; } = new Dictionary(); public Object3D Model { get { return this.obj3d; } } public Renderer(Object3D obj3d) { this.obj3d = obj3d.ToOneMesh(); // Set Texture used for faces without texture this.emptyTexture = (Bitmap)this.ColorToTexture(Color.LightGray); // Set Texture used for lines this.lineTexture = (Bitmap)this.ColorToTexture(Color.Black); // Set Texture used for lines of selected faces this.selectedLineTexture = (Bitmap)this.ColorToTexture(Color.Orange); } private Image ColorToTexture(Color color) { var tex = new Bitmap(1, 1); tex.SetPixel(0, 0, color); return tex; } /// /// Updates the Data of a Vertex in the buffer. /// /// The Mesh where the Vertex is listed. /// The Vertex to update. public void UpdateVertexData(Mesh m, Vertex v) { GL.BindBuffer(BufferTarget.ArrayBuffer, this.VertexBuffers[m]); var vector = new Vector3((float)v.X, (float)v.Y, (float)v.Z); GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr)((m.Vertices.IndexOf(v)) * (Vector3.SizeInBytes)), Vector3.SizeInBytes, ref vector); } /// /// Updates the Data of a Normal in the buffer. /// /// The Mesh where the Vertex is listed. /// The Normal to update. public void UpdateNormalData(Mesh m, Normal n) { GL.BindBuffer(BufferTarget.ArrayBuffer, this.NormalBuffers[m]); var vector = new Vector3((float)n.X, (float)n.Y, (float)n.Z); GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr)((m.Normals.IndexOf(n)) * (Vector3.SizeInBytes)), Vector3.SizeInBytes, ref vector); } /// /// Updates the Data of a Vertex Color in the buffer. /// /// The Mesh where the Vertex is listed. /// The Vertex Color to update. public void UpdateVertexColorData(Mesh m, VertexColor vc) { GL.BindBuffer(BufferTarget.ArrayBuffer, this.VertexColorBuffers[m]); var vector = new Vector4(vc.R, vc.G, vc.B, vc.A); GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr)((m.VertexColors.IndexOf(vc)) * (Vector4.SizeInBytes)), Vector4.SizeInBytes, ref vector); } /// /// Updates the Data of a UV in the buffer. /// /// The Mesh where the Vertex is listed. /// The UV to update. public void UpdateUVData(Mesh m, UV uv) { GL.BindBuffer(BufferTarget.ArrayBuffer, this.UVBuffers[m]); var vector = new Vector2(uv.U, uv.V); GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr)((m.UVs.IndexOf(uv)) * (Vector2.SizeInBytes)), Vector2.SizeInBytes, ref vector); } /// /// Updates the indicies of a face in the buffer. /// /// The Mesh where the Vertex is listed. /// The Face to update. public void UpdateFaceIndicies(Mesh m, Face f) { int faceIndex = m.Faces.IndexOf(f); byte uintlen = (byte)Strings.Len(new uint()); var indicies = new Vector3(m.Vertices.IndexOf(f.Points[0].Vertex), m.Vertices.IndexOf(f.Points[1].Vertex), m.Vertices.IndexOf(f.Points[2].Vertex)); GL.BindBuffer(BufferTarget.ArrayBuffer, this.IndicesBuffers[m][faceIndex]); GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr)(uintlen * faceIndex), uintlen, ref indicies); } /// /// Replace an Image with a new one. /// /// /// public void UpdateTexture(Image oldImage, Image newImage) { if (this.dicTextureIDs.ContainsKey(oldImage)) { int id = this.dicTextureIDs[oldImage]; this.dicTextureIDs.Remove(oldImage); this.dicTextureIDs.Add(newImage, id); ContentPipe.LoadTexture((Bitmap)newImage, id); } } /// /// Updates an Image. /// /// public void UpdateTexture(Image image) { if (this.dicTextureIDs.ContainsKey(image)) { ContentPipe.LoadTexture(this.dicTextureIDs[image].ToString()); } } /// /// Creates the Buffers and store the requied Data. /// public void RenderModel() { this.ReleaseBuffers(); foreach (Mesh mesh in this.obj3d.Meshes) { var nibo = new List(); global::System.Boolean enablecols = ((mesh.VertexColors.Count) > (0)); global::System.Boolean enablenorms = (((!(enablecols))) && ((mesh.Normals.Count) > (0))); var verts = new List(); var uvs = new List(); var cols = new List(); var norms = new List(); global::System.UInt64 curvi = 0UL; this.IndicesBuffers.Add(mesh, nibo); for (int i = 0, loopTo = (mesh.Faces.Count) - (1); i <= loopTo; i++) { { var withBlock = mesh.Faces[i]; var indices = new List(); foreach (Pilz.S3DFileParser.Point p in withBlock.Points) { indices.Add((global::System.UInt32)curvi); curvi = (global::System.UInt64)(curvi + 1m); if (p.Vertex is object) { verts.Add(new Vector3((float)p.Vertex.X, (float)p.Vertex.Y, (float)p.Vertex.Z)); } else { verts.Add(new Vector3(0, 0, 0)); } if (p.UV is object) { uvs.Add(new Vector2(p.UV.U, p.UV.V)); } else { uvs.Add(new Vector2(0, 0)); } if (((enablecols) && p.VertexColor is object)) { cols.Add(new Vector4(p.VertexColor.R, p.VertexColor.G, p.VertexColor.B, p.VertexColor.A)); } else { cols.Add(new Vector4(1, 1, 1, 1)); } if (((enablenorms) && p.Normal is object)) { norms.Add(new Vector3(p.Normal.X, p.Normal.Y, p.Normal.Z)); } else { norms.Add(new Vector3(1, 1, 1)); } } nibo.Add(GL.GenBuffer()); GL.BindBuffer(BufferTarget.ElementArrayBuffer, nibo[i]); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)((Strings.Len(new uint())) * (indices.Count)), indices.ToArray(), BufferUsageHint.StaticDraw); if (withBlock.Material?.Image is object) { if (!(this.dicTextureIDs.ContainsKey(withBlock.Material.Image))) { this.dicTextureIDs.Add(withBlock.Material.Image, ContentPipe.LoadTexture((Bitmap)withBlock.Material.Image)); } } else if (withBlock.Material?.Color is object) { if (!(this.dicColorIDs.ContainsKey((Color)withBlock.Material.Color))) { this.dicColorIDs.Add((Color)withBlock.Material.Color, ContentPipe.LoadTexture((Bitmap)ColorToTexture((Color)withBlock.Material.Color))); } } else if (!(this.dicTextureIDs.ContainsKey(this.emptyTexture))) { this.dicTextureIDs.Add(this.emptyTexture, ContentPipe.LoadTexture(this.emptyTexture)); } } } int nvbo = GL.GenBuffer(); this.VertexBuffers.Add(mesh, nvbo); GL.BindBuffer(BufferTarget.ArrayBuffer, nvbo); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)((Vector3.SizeInBytes) * (verts.Count)), verts.ToArray(), BufferUsageHint.StaticDraw); int ntbo = GL.GenBuffer(); this.UVBuffers.Add(mesh, ntbo); GL.BindBuffer(BufferTarget.ArrayBuffer, ntbo); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)((Vector2.SizeInBytes) * (uvs.Count)), uvs.ToArray(), BufferUsageHint.StaticDraw); if (enablecols) { int ncbo = GL.GenBuffer(); this.VertexColorBuffers.Add(mesh, ncbo); GL.BindBuffer(BufferTarget.ArrayBuffer, ncbo); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)((Vector4.SizeInBytes) * (cols.Count)), cols.ToArray(), BufferUsageHint.StaticDraw); } if (enablenorms) { int nnbo = GL.GenBuffer(); this.NormalBuffers.Add(mesh, nnbo); GL.BindBuffer(BufferTarget.ArrayBuffer, nnbo); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)((Vector3.SizeInBytes) * (norms.Count)), norms.ToArray(), BufferUsageHint.StaticDraw); } } if (!(this.dicTextureIDs.ContainsKey(this.lineTexture))) { this.dicTextureIDs.Add(this.lineTexture, ContentPipe.LoadTexture(this.lineTexture)); } this.HasRendered = true; } public void DrawModel(RenderMode mode) { DrawModel(mode, Vector3.Zero, Quaternion.Identity, new Vector3(this.ModelScaling, this.ModelScaling, this.ModelScaling)); } public void DrawModel(RenderMode mode, Vector3 pos, Quaternion rot) { DrawModel(mode, pos, rot, new Vector3(this.ModelScaling, this.ModelScaling, this.ModelScaling)); } public void DrawModel(RenderMode mode, Vector3 pos, Quaternion rot, Vector3 scale) { if (((mode) == (RenderMode.None))) return; if (!(this.HasRendered)) return; GL.PushMatrix(); GL.Translate(pos.X, pos.Y, pos.Z); GL.Rotate(rot.X, 1, 0, 0); GL.Rotate(rot.Y, 0, 1, 0); GL.Rotate(rot.Z, 0, 0, 1); GL.Scale(scale); // GL.Scale(scale.X, scale.Y, scale.Z) GL.EnableClientState(ArrayCap.VertexArray); GL.EnableClientState(ArrayCap.TextureCoordArray); foreach (Mesh mesh in this.obj3d.Meshes) { if (this.VertexColorBuffers.ContainsKey(mesh)) { GL.EnableClientState(ArrayCap.ColorArray); } else if (this.NormalBuffers.ContainsKey(mesh)) { GL.EnableClientState(ArrayCap.NormalArray); } GL.BindBuffer(BufferTarget.ArrayBuffer, this.VertexBuffers[mesh]); GL.VertexPointer(3, VertexPointerType.Float, 0, IntPtr.Zero); GL.BindBuffer(BufferTarget.ArrayBuffer, this.UVBuffers[mesh]); GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, IntPtr.Zero); if (this.VertexColorBuffers.ContainsKey(mesh)) { GL.BindBuffer(BufferTarget.ArrayBuffer, this.VertexColorBuffers[mesh]); GL.ColorPointer(4, ColorPointerType.Float, 0, IntPtr.Zero); } else if (this.NormalBuffers.ContainsKey(mesh)) { GL.BindBuffer(BufferTarget.ArrayBuffer, this.NormalBuffers[mesh]); GL.NormalPointer(NormalPointerType.Float, 0, IntPtr.Zero); } for (int i = 0, loopTo = (mesh.Faces.Count) - (1); i <= loopTo; i++) { Face l = mesh.Faces[i]; GL.BindBuffer(BufferTarget.ElementArrayBuffer, this.IndicesBuffers[mesh][i]); global::System.Boolean isEmptyTexture = l.Material?.Image is null; global::System.Boolean isEmptyColor = l.Material?.Color is null; void setMaterialTextureOrColor() { int texID; if (!(isEmptyTexture)) { texID = this.dicTextureIDs[l.Material.Image]; } else if (!(isEmptyColor)) { texID = this.dicColorIDs[(Color)l.Material.Color]; } else { texID = this.dicTextureIDs[this.emptyTexture]; } GL.BindTexture(TextureTarget.Texture2D, texID); }; if ((((((mode) & (RenderMode.Fill)))) == (RenderMode.Fill))) { setMaterialTextureOrColor(); if (!(isEmptyTexture)) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, l.Material.Wrap.X); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, l.Material.Wrap.Y); } GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.DrawElements(PrimitiveType.Triangles, l.Points.Count, DrawElementsType.UnsignedInt, IntPtr.Zero); } if ((((((mode) & (RenderMode.Outline)))) == (RenderMode.Outline))) { if ((((((mode) & (RenderMode.Fill)))) == (RenderMode.Fill))) { GL.BindTexture(TextureTarget.Texture2D, this.dicTextureIDs[this.lineTexture]); } else { setMaterialTextureOrColor(); if (!(isEmptyTexture)) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, l.Material.Wrap.X); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, l.Material.Wrap.Y); } } GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); GL.DrawElements(PrimitiveType.Triangles, l.Points.Count, DrawElementsType.UnsignedInt, IntPtr.Zero); } } GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); // Reset for RenderEngineOld if (this.VertexColorBuffers.ContainsKey(mesh)) { GL.DisableClientState(ArrayCap.ColorArray); } else if (this.NormalBuffers.ContainsKey(mesh)) { GL.DisableClientState(ArrayCap.NormalArray); } } GL.DisableClientState(ArrayCap.VertexArray); GL.DisableClientState(ArrayCap.TextureCoordArray); GL.PopMatrix(); } public void DrawFacePicking() { DrawFacePicking(Vector3.Zero, Quaternion.Identity, new Vector3(this.ModelScaling, this.ModelScaling, this.ModelScaling)); } public void DrawFacePicking(Vector3 pos, Quaternion rot) { DrawFacePicking(pos, rot, new Vector3(this.ModelScaling, this.ModelScaling, this.ModelScaling)); } public void DrawFacePicking(Vector3 pos, Quaternion rot, Vector3 scale) { if (!(this.HasRendered)) return; GL.PushMatrix(); GL.Translate(pos.X, pos.Y, pos.Z); GL.Rotate(rot.X, 1, 0, 0); GL.Rotate(rot.Y, 0, 1, 0); GL.Rotate(rot.Z, 0, 0, 1); GL.Scale(scale); GL.EnableClientState(ArrayCap.VertexArray); for (int iMesh = 0, loopTo = (this.obj3d.Meshes.Count) - (1); iMesh <= loopTo; iMesh++) { Mesh mesh = this.obj3d.Meshes[iMesh]; GL.BindBuffer(BufferTarget.ArrayBuffer, this.VertexBuffers[mesh]); GL.VertexPointer(3, VertexPointerType.Float, 0, IntPtr.Zero); for (int iFace = 0, loopTo1 = (mesh.Faces.Count) - (1); iFace <= loopTo1; iFace++) { Face l = mesh.Faces[iFace]; GL.BindBuffer(BufferTarget.ElementArrayBuffer, this.IndicesBuffers[mesh][iFace]); int colorCode = (((0x20000000) + ((((iMesh) << (16))))) + (iFace)); GL.Color4(Color.FromArgb(colorCode)); // Color: "2f ff xx xx" -> where 'f' = mesh index and where 'x' is face index GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.DrawElements(PrimitiveType.Triangles, l.Points.Count, DrawElementsType.UnsignedInt, IntPtr.Zero); } GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); } GL.DisableClientState(ArrayCap.VertexArray); GL.PopMatrix(); } public void ReleaseBuffers() { if (!(this.HasRendered)) return; foreach (KeyValuePair kvp in this.VertexBuffers) GL.DeleteBuffer(kvp.Value); this.VertexBuffers.Clear(); foreach (KeyValuePair kvp in this.UVBuffers) GL.DeleteBuffer(kvp.Value); this.UVBuffers.Clear(); foreach (KeyValuePair kvp in this.VertexColorBuffers) GL.DeleteBuffer(kvp.Value); this.VertexColorBuffers.Clear(); foreach (KeyValuePair kvp in this.NormalBuffers) GL.DeleteBuffer(kvp.Value); this.NormalBuffers.Clear(); foreach (KeyValuePair> kvp in this.IndicesBuffers) { foreach (int i in kvp.Value) GL.DeleteBuffer(i); kvp.Value.Clear(); } this.IndicesBuffers.Clear(); foreach (KeyValuePair kvp in this.dicTextureIDs) GL.DeleteBuffer(kvp.Value); this.dicTextureIDs.Clear(); foreach (KeyValuePair kvp in this.dicColorIDs) GL.DeleteBuffer(kvp.Value); this.dicColorIDs.Clear(); this.HasRendered = false; } ~Renderer() { // ReleaseBuffers() } } }