Imports System.Drawing Imports System.Threading Imports System.Windows.Forms Imports OpenTK Imports OpenTK.Graphics.OpenGL Imports Pilz.S3DFileParser Imports Bitmap = System.Drawing.Bitmap Imports Color = System.Drawing.Color Imports Image = System.Drawing.Image Namespace RenderingN Public Class Renderer Private obj3d As Object3D Private dicTextureIDs As New Dictionary(Of Image, Integer) Private dicColorIDs As New Dictionary(Of Color, Integer) Private emptyTexture As Bitmap = Nothing Private lineTexture As Bitmap = Nothing Private selectedLineTexture As Bitmap = Nothing Public Property ModelScaling As Single = 1.0F Public ReadOnly Property HasRendered As Boolean = False Public ReadOnly Property SelectedElements As List(Of Object) Private ReadOnly Property VertexBuffers As New Dictionary(Of Mesh, Integer) Private ReadOnly Property IndicesBuffers As New Dictionary(Of Mesh, List(Of Integer)) Private ReadOnly Property UVBuffers As New Dictionary(Of Mesh, Integer) Private ReadOnly Property VertexColorBuffers As New Dictionary(Of Mesh, Integer) Private ReadOnly Property NormalBuffers As New Dictionary(Of Mesh, Integer) Public ReadOnly Property Model As Object3D Get Return obj3d End Get End Property Public Sub New(obj3d As Object3D) Me.obj3d = obj3d.ToOneMesh 'Set Texture used for faces without texture emptyTexture = ColorToTexture(Color.LightGray) 'Set Texture used for lines lineTexture = ColorToTexture(Color.Black) 'Set Texture used for lines of selected faces selectedLineTexture = ColorToTexture(Color.Orange) End Sub Private Function ColorToTexture(color As Color) As Image Dim tex As New Bitmap(1, 1) tex.SetPixel(0, 0, color) Return tex End Function ''' ''' Updates the Data of a Vertex in the buffer. ''' ''' The Mesh where the Vertex is listed. ''' The Vertex to update. Public Sub UpdateVertexData(m As Mesh, v As Vertex) GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBuffers(m)) GL.BufferSubData(BufferTarget.ArrayBuffer, CType(m.Vertices.IndexOf(v) * Vector3.SizeInBytes, IntPtr), Vector3.SizeInBytes, New Vector3(v.X, v.Y, v.Z)) End Sub ''' ''' Updates the Data of a Normal in the buffer. ''' ''' The Mesh where the Vertex is listed. ''' The Normal to update. Public Sub UpdateNormalData(m As Mesh, n As Normal) GL.BindBuffer(BufferTarget.ArrayBuffer, NormalBuffers(m)) GL.BufferSubData(BufferTarget.ArrayBuffer, CType(m.Normals.IndexOf(n) * Vector3.SizeInBytes, IntPtr), Vector3.SizeInBytes, New Vector3(n.X, n.Y, n.Z)) End Sub ''' ''' Updates the Data of a Vertex Color in the buffer. ''' ''' The Mesh where the Vertex is listed. ''' The Vertex Color to update. Public Sub UpdateVertexColorData(m As Mesh, vc As VertexColor) GL.BindBuffer(BufferTarget.ArrayBuffer, VertexColorBuffers(m)) GL.BufferSubData(BufferTarget.ArrayBuffer, CType(m.VertexColors.IndexOf(vc) * Vector4.SizeInBytes, IntPtr), Vector4.SizeInBytes, New Vector4(vc.R, vc.G, vc.B, vc.A)) End Sub ''' ''' Updates the Data of a UV in the buffer. ''' ''' The Mesh where the Vertex is listed. ''' The UV to update. Public Sub UpdateUVData(m As Mesh, uv As UV) GL.BindBuffer(BufferTarget.ArrayBuffer, UVBuffers(m)) GL.BufferSubData(BufferTarget.ArrayBuffer, CType(m.UVs.IndexOf(uv) * Vector2.SizeInBytes, IntPtr), Vector2.SizeInBytes, New Vector2(uv.U, uv.V)) End Sub ''' ''' Updates the indicies of a face in the buffer. ''' ''' The Mesh where the Vertex is listed. ''' The Face to update. Public Sub UpdateFaceIndicies(m As Mesh, f As Face) Dim faceIndex As Integer = m.Faces.IndexOf(f) Dim uintlen As Byte = Len(New UInteger) Dim indicies As 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, IndicesBuffers(m)(faceIndex)) GL.BufferSubData(BufferTarget.ArrayBuffer, CType(uintlen * faceIndex, IntPtr), uintlen, indicies) End Sub ''' ''' Replace an Image with a new one. ''' ''' ''' Public Sub UpdateTexture(oldImage As Image, newImage As Image) If dicTextureIDs.ContainsKey(oldImage) Then Dim id As Integer = dicTextureIDs(oldImage) dicTextureIDs.Remove(oldImage) dicTextureIDs.Add(newImage, id) ContentPipe.LoadTexture(newImage, id) End If End Sub ''' ''' Updates an Image. ''' ''' Public Sub UpdateTexture(image As Image) If dicTextureIDs.ContainsKey(image) Then ContentPipe.LoadTexture(dicTextureIDs(image)) End If End Sub ''' ''' Creates the Buffers and store the requied Data. ''' Public Sub RenderModel() ReleaseBuffers() For Each mesh As Mesh In obj3d.Meshes Dim nibo As New List(Of Integer) Dim enablecols As Boolean = mesh.VertexColors.Count > 0 Dim enablenorms As Boolean = (Not enablecols) AndAlso mesh.Normals.Count > 0 Dim verts As New List(Of Vector3) Dim uvs As New List(Of Vector2) Dim cols As New List(Of Vector4) Dim norms As New List(Of Vector3) Dim curvi As ULong = 0 IndicesBuffers.Add(mesh, nibo) For i As Integer = 0 To mesh.Faces.Count - 1 With mesh.Faces(i) Dim indices As New List(Of UInteger) For Each p As S3DFileParser.Point In .Points indices.Add(curvi) curvi += 1 If p.Vertex IsNot Nothing Then verts.Add(New Vector3(p.Vertex.X, p.Vertex.Y, p.Vertex.Z)) Else verts.Add(New Vector3(0, 0, 0)) End If If p.UV IsNot Nothing Then uvs.Add(New Vector2(p.UV.U, p.UV.V)) Else uvs.Add(New Vector2(0, 0)) End If If enablecols AndAlso p.VertexColor IsNot Nothing Then 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)) End If If enablenorms AndAlso p.Normal IsNot Nothing Then norms.Add(New Vector3(p.Normal.X, p.Normal.Y, p.Normal.Z)) Else norms.Add(New Vector3(1, 1, 1)) End If Next nibo.Add(GL.GenBuffer) GL.BindBuffer(BufferTarget.ElementArrayBuffer, nibo(i)) GL.BufferData( BufferTarget.ElementArrayBuffer, CType(Len(New UInteger) * indices.Count, IntPtr), indices.ToArray, BufferUsageHint.StaticDraw) If .Material?.Image IsNot Nothing Then If Not dicTextureIDs.ContainsKey(.Material.Image) Then dicTextureIDs.Add(.Material.Image, ContentPipe.LoadTexture(.Material.Image)) End If ElseIf .Material?.Color IsNot Nothing Then If Not dicColorIDs.ContainsKey(.Material.Color) Then dicColorIDs.Add(.Material.Color, ContentPipe.LoadTexture(ColorToTexture(.Material.Color))) End If Else If Not dicTextureIDs.ContainsKey(emptyTexture) Then dicTextureIDs.Add(emptyTexture, ContentPipe.LoadTexture(emptyTexture)) End If End If End With Next Dim nvbo As Integer = GL.GenBuffer VertexBuffers.Add(mesh, nvbo) GL.BindBuffer(BufferTarget.ArrayBuffer, nvbo) GL.BufferData( BufferTarget.ArrayBuffer, CType(Vector3.SizeInBytes * verts.Count, IntPtr), verts.ToArray, BufferUsageHint.StaticDraw ) Dim ntbo As Integer = GL.GenBuffer UVBuffers.Add(mesh, ntbo) GL.BindBuffer(BufferTarget.ArrayBuffer, ntbo) GL.BufferData( BufferTarget.ArrayBuffer, CType(Vector2.SizeInBytes * uvs.Count, IntPtr), uvs.ToArray, BufferUsageHint.StaticDraw ) If enablecols Then Dim ncbo As Integer = GL.GenBuffer VertexColorBuffers.Add(mesh, ncbo) GL.BindBuffer(BufferTarget.ArrayBuffer, ncbo) GL.BufferData( BufferTarget.ArrayBuffer, CType(Vector4.SizeInBytes * cols.Count, IntPtr), cols.ToArray, BufferUsageHint.StaticDraw ) End If If enablenorms Then Dim nnbo As Integer = GL.GenBuffer NormalBuffers.Add(mesh, nnbo) GL.BindBuffer(BufferTarget.ArrayBuffer, nnbo) GL.BufferData( BufferTarget.ArrayBuffer, CType(Vector3.SizeInBytes * norms.Count, IntPtr), norms.ToArray, BufferUsageHint.StaticDraw ) End If Next If Not dicTextureIDs.ContainsKey(lineTexture) Then dicTextureIDs.Add(lineTexture, ContentPipe.LoadTexture(lineTexture)) End If _HasRendered = True End Sub Public Sub DrawModel(mode As RenderMode) DrawModel(mode, Vector3.Zero, Quaternion.Identity, New Vector3(ModelScaling, ModelScaling, ModelScaling)) End Sub Public Sub DrawModel(mode As RenderMode, pos As Vector3, rot As Quaternion) DrawModel(mode, pos, rot, New Vector3(ModelScaling, ModelScaling, ModelScaling)) End Sub Public Sub DrawModel(mode As RenderMode, pos As Vector3, rot As Quaternion, scale As Vector3) If mode = RenderMode.None Then Return If Not _HasRendered Then 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) For Each mesh As Mesh In obj3d.Meshes If VertexColorBuffers.ContainsKey(mesh) Then GL.EnableClientState(ArrayCap.ColorArray) ElseIf NormalBuffers.ContainsKey(mesh) Then GL.EnableClientState(ArrayCap.NormalArray) End If GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBuffers(mesh)) GL.VertexPointer(3, VertexPointerType.Float, 0, IntPtr.Zero) GL.BindBuffer(BufferTarget.ArrayBuffer, UVBuffers(mesh)) GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, IntPtr.Zero) If VertexColorBuffers.ContainsKey(mesh) Then GL.BindBuffer(BufferTarget.ArrayBuffer, VertexColorBuffers(mesh)) GL.ColorPointer(4, ColorPointerType.Float, 0, IntPtr.Zero) ElseIf NormalBuffers.ContainsKey(mesh) Then GL.BindBuffer(BufferTarget.ArrayBuffer, NormalBuffers(mesh)) GL.NormalPointer(NormalPointerType.Float, 0, IntPtr.Zero) End If For i As Integer = 0 To mesh.Faces.Count - 1 Dim l As Face = mesh.Faces(i) GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndicesBuffers(mesh)(i)) Dim isEmptyTexture As Boolean = l.Material?.Image Is Nothing Dim isEmptyColor As Boolean = l.Material?.Color Is Nothing Dim setMaterialTextureOrColor = Sub() Dim texID As Integer If Not isEmptyTexture Then texID = dicTextureIDs(l.Material.Image) ElseIf Not isEmptyColor Then texID = dicColorIDs(l.Material.Color) Else texID = dicTextureIDs(emptyTexture) End If GL.BindTexture(TextureTarget.Texture2D, texID) End Sub If (mode And RenderMode.Fill) = RenderMode.Fill Then setMaterialTextureOrColor() If Not isEmptyTexture Then GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, l.Material.Wrap.X) GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, l.Material.Wrap.Y) End If GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill) GL.DrawElements(PrimitiveType.Triangles, l.Points.Count, DrawElementsType.UnsignedInt, IntPtr.Zero) End If If (mode And RenderMode.Outline) = RenderMode.Outline Then If (mode And RenderMode.Fill) = RenderMode.Fill Then GL.BindTexture(TextureTarget.Texture2D, dicTextureIDs(lineTexture)) Else setMaterialTextureOrColor() If Not isEmptyTexture Then GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, l.Material.Wrap.X) GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, l.Material.Wrap.Y) End If End If GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line) GL.DrawElements(PrimitiveType.Triangles, l.Points.Count, DrawElementsType.UnsignedInt, IntPtr.Zero) End If Next GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill) 'Reset for RenderEngineOld If VertexColorBuffers.ContainsKey(mesh) Then GL.DisableClientState(ArrayCap.ColorArray) ElseIf NormalBuffers.ContainsKey(mesh) Then GL.DisableClientState(ArrayCap.NormalArray) End If Next GL.DisableClientState(ArrayCap.VertexArray) GL.DisableClientState(ArrayCap.TextureCoordArray) GL.PopMatrix() End Sub Public Sub DrawFacePicking() DrawFacePicking(Vector3.Zero, Quaternion.Identity, New Vector3(ModelScaling, ModelScaling, ModelScaling)) End Sub Public Sub DrawFacePicking(pos As Vector3, rot As Quaternion) DrawFacePicking(pos, rot, New Vector3(ModelScaling, ModelScaling, ModelScaling)) End Sub Public Sub DrawFacePicking(pos As Vector3, rot As Quaternion, scale As Vector3) If Not _HasRendered Then 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 iMesh As Integer = 0 To obj3d.Meshes.Count - 1 Dim mesh As Mesh = obj3d.Meshes(iMesh) GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBuffers(mesh)) GL.VertexPointer(3, VertexPointerType.Float, 0, IntPtr.Zero) For iFace As Integer = 0 To mesh.Faces.Count - 1 Dim l As Face = mesh.Faces(iFace) GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndicesBuffers(mesh)(iFace)) Dim colorCode As Integer = &H20000000 + (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) Next GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill) Next GL.DisableClientState(ArrayCap.VertexArray) GL.PopMatrix() End Sub Public Sub ReleaseBuffers() If Not HasRendered Then Return For Each kvp As KeyValuePair(Of Mesh, Integer) In VertexBuffers GL.DeleteBuffer(kvp.Value) Next VertexBuffers.Clear() For Each kvp As KeyValuePair(Of Mesh, Integer) In UVBuffers GL.DeleteBuffer(kvp.Value) Next UVBuffers.Clear() For Each kvp As KeyValuePair(Of Mesh, Integer) In VertexColorBuffers GL.DeleteBuffer(kvp.Value) Next VertexColorBuffers.Clear() For Each kvp As KeyValuePair(Of Mesh, Integer) In NormalBuffers GL.DeleteBuffer(kvp.Value) Next NormalBuffers.Clear() For Each kvp As KeyValuePair(Of Mesh, List(Of Integer)) In IndicesBuffers For Each i As Integer In kvp.Value GL.DeleteBuffer(i) Next kvp.Value.Clear() Next IndicesBuffers.Clear() For Each kvp As KeyValuePair(Of Image, Integer) In dicTextureIDs GL.DeleteBuffer(kvp.Value) Next dicTextureIDs.Clear() For Each kvp As KeyValuePair(Of Color, Integer) In dicColorIDs GL.DeleteBuffer(kvp.Value) Next dicColorIDs.Clear() _HasRendered = False End Sub Protected Overrides Sub Finalize() 'ReleaseBuffers() End Sub End Class End Namespace