diff --git a/Pilz.Collections/SimpleHistory/SimpleHistory.vb b/Pilz.Collections/SimpleHistory/SimpleHistory.vb
index 46dc39d..74c7339 100644
--- a/Pilz.Collections/SimpleHistory/SimpleHistory.vb
+++ b/Pilz.Collections/SimpleHistory/SimpleHistory.vb
@@ -7,6 +7,16 @@ Namespace SimpleHistory
Private stackPast As New Stack(Of HistoryPoint)
Private stackFuture As New Stack(Of HistoryPoint)
+ '''
+ ''' Gets the count of history points.
+ '''
+ '''
+ Public ReadOnly Property ChangesCount As Boolean
+ Get
+ Return stackPast.Count
+ End Get
+ End Property
+
'''
''' Checks if the History has past changes.
'''
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/Camera.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/Camera.vb
new file mode 100644
index 0000000..9ca19d2
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/Camera.vb
@@ -0,0 +1,570 @@
+Imports System.Windows.Forms
+Imports OpenTK
+
+Namespace CameraN
+
+ Public Class Camera
+
+ Public Event NeedSelectedObject(e As NeedSelectedObjectEventArgs)
+
+ 'P R I V A T E F I E L D S
+
+ Private ReadOnly TAU As Single = Math.PI * 2
+ Private myCamMode As CameraMode = CameraMode.FLY
+ Private pos As New Vector3(-5000.0F, 3000.0F, 4000.0F)
+ Private myLookat As New Vector3(0F, 0F, 0F)
+ Private myFarPoint As New Vector3(0F, 0F, 0F)
+ Private myNearPoint As New Vector3(0F, 0F, 0F)
+ Private lastMouseX As Integer = -1, lastMouseY As Integer = -1
+ Private CamAngleX As Single = 0F, CamAngleY As Single = -(Math.PI / 2)
+ Private resetMouse As Boolean = True
+
+ Private orbitDistance As Single = 500.0F
+ Private orbitTheta As Single = 0.0F, orbitPhi As Single = 0.0F
+
+ Private currentLookDirection As LookDirection
+ Private lookPositions() As Vector3 = {
+ New Vector3(0, 12500, 0),
+ New Vector3(0, -12500, 0),
+ New Vector3(-12500, 0, 0),
+ New Vector3(12500, 0, 0),
+ New Vector3(0, 0, 12500),
+ New Vector3(0, 0, -12500)
+ }
+
+ 'A U T O M A T I C P R O P E R T I E S
+
+ Public Property CamSpeedMultiplier As Single = 1
+
+ 'P R O P E R T I E S
+
+ Public ReadOnly Property CamMode As CameraMode
+ Get
+ Return myCamMode
+ End Get
+ End Property
+
+ Public ReadOnly Property Yaw As Single
+ Get
+ Return CamAngleX
+ End Get
+ End Property
+
+ Public ReadOnly Property Pitch As Single
+ Get
+ Return CamAngleY
+ End Get
+ End Property
+
+ Public ReadOnly Property Yaw_Degrees As Single
+ Get
+ Return CamAngleX * (180.0F / 3.14159274F)
+ End Get
+ End Property
+
+ Public ReadOnly Property Pitch_Degrees As Single
+ Get
+ Return CamAngleY * (180.0F / 3.14159274F)
+ End Get
+ End Property
+
+ Public Property Position As Vector3
+ Get
+ Return pos
+ End Get
+ Set(value As Vector3)
+ pos = value
+ End Set
+ End Property
+
+ Public Property LookAt As Vector3
+ Get
+ Return myLookat
+ End Get
+ Set(value As Vector3)
+ myLookat = value
+ End Set
+ End Property
+
+ Public Property NearPoint As Vector3
+ Get
+ Return myNearPoint
+ End Get
+ Set(value As Vector3)
+ myNearPoint = value
+ End Set
+ End Property
+
+ Public Property FarPoint As Vector3
+ Get
+ Return myFarPoint
+ End Get
+ Set(value As Vector3)
+ myFarPoint = value
+ End Set
+ End Property
+
+ 'C O N S T R U C T O R
+
+ Public Sub New()
+ SetRotationFromLookAt()
+ End Sub
+
+ 'F E A T U R E S
+
+ Private Function Clampf(value As Single, min As Single, max As Single) As Single
+ Return If(value > max, max, If(value < min, min, value))
+ End Function
+
+ Private Sub OrientateCam(ang As Single, ang2 As Single)
+ Dim CamLX As Single = CSng(Math.Sin(ang)) * CSng(Math.Sin(-ang2))
+ Dim CamLY As Single = CSng(Math.Cos(ang2))
+ Dim CamLZ As Single = CSng(-Math.Cos(ang)) * CSng(Math.Sin(-ang2))
+
+ myLookat.X = pos.X + (-CamLX) * 100.0F
+ myLookat.Y = pos.Y + (-CamLY) * 100.0F
+ myLookat.Z = pos.Z + (-CamLZ) * 100.0F
+ End Sub
+
+ Private Sub OffsetCam(xAmt As Integer, yAmt As Integer, zAmt As Integer)
+ Dim pitch_Renamed As Double = CamAngleY - (Math.PI / 2)
+ Dim CamLX As Single = CSng(Math.Sin(CamAngleX)) * CSng(Math.Cos(-pitch_Renamed))
+ Dim CamLY As Single = CSng(Math.Sin(pitch_Renamed))
+ Dim CamLZ As Single = CSng(-Math.Cos(CamAngleX)) * CSng(Math.Cos(-pitch_Renamed))
+ pos.X = pos.X + xAmt * (CamLX) * CamSpeedMultiplier
+ pos.Y = pos.Y + yAmt * (CamLY) * CamSpeedMultiplier
+ pos.Z = pos.Z + zAmt * (CamLZ) * CamSpeedMultiplier
+ End Sub
+
+ Public Sub Move(y As Single, ByRef camMtx As Matrix4)
+ OffsetCam(0, y, 0)
+ OrientateCam(CamAngleX, CamAngleY)
+ UpdateMatrix(camMtx)
+ End Sub
+
+ Public Sub Move(x As Single, z As Single, ByRef camMtx As Matrix4)
+ UpdateCameraOffsetDirectly(x, z, camMtx)
+ OrientateCam(CamAngleX, CamAngleY)
+ UpdateMatrix(camMtx)
+ End Sub
+
+ Public Sub SetRotationFromLookAt()
+ Dim x_diff As Single = myLookat.X - pos.X
+ Dim y_diff As Single = myLookat.Y - pos.Y
+ Dim z_diff As Single = myLookat.Z - pos.Z
+ Dim dist As Single = CSng(Math.Sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff))
+ If z_diff = 0 Then
+ z_diff = 0.001F
+ End If
+ Dim nxz_ratio As Single = -x_diff / z_diff
+ If z_diff < 0 Then
+ CamAngleX = CSng(Math.Atan(nxz_ratio) + Math.PI)
+ Else
+ CamAngleX = CSng(Math.Atan(nxz_ratio))
+ End If
+ CamAngleY = -3.1459F - (CSng(Math.Asin(y_diff / dist)) - 1.57F)
+ End Sub
+
+ Public Sub ResetOrbitToSelectedObject()
+ Dim objs As ICameraPoint() = GetSelectedObject()
+ If objs?.Length > 0 Then
+ orbitTheta = -(CalculateCenterYRotationOfObjects(objs) * (CSng(Math.PI) / 180.0F))
+ orbitPhi = -0.3F
+ orbitDistance = 1200.0F
+ End If
+ End Sub
+
+ Public Sub UpdateOrbitCamera(ByRef cameraMatrix As Matrix4)
+ If myCamMode = CameraMode.ORBIT Then
+ Dim objs As ICameraPoint() = GetSelectedObject()
+ If objs?.Length > 0 Then
+ Dim centerPos As Numerics.Vector3 = CalculateCenterPositionOfObjects(objs)
+ pos.X = centerPos.X + CSng(Math.Cos(orbitPhi) * -Math.Sin(orbitTheta) * orbitDistance)
+ pos.Y = centerPos.Y + CSng(-Math.Sin(orbitPhi) * orbitDistance)
+ pos.Z = centerPos.Z + CSng(Math.Cos(orbitPhi) * Math.Cos(orbitTheta) * orbitDistance)
+ myLookat.X = centerPos.X
+ myLookat.Y = centerPos.Y
+ myLookat.Z = centerPos.Z
+ UpdateMatrix(cameraMatrix)
+ SetRotationFromLookAt()
+ End If
+ End If
+ End Sub
+
+ Public Function IsOrbitCamera() As Boolean
+ Return myCamMode = CameraMode.ORBIT
+ End Function
+
+ Public Sub SetCameraMode(mode As CameraMode, ByRef cameraMatrix As Matrix4)
+ myCamMode = mode
+ If IsOrbitCamera() Then
+ ResetOrbitToSelectedObject()
+ UpdateOrbitCamera(cameraMatrix)
+ End If
+ End Sub
+
+ Public Sub SetCameraMode_LookDirection(dir As LookDirection, ByRef cameraMatrix As Matrix4)
+ myCamMode = CameraMode.LOOK_DIRECTION
+ currentLookDirection = dir
+ Select Case currentLookDirection
+ Case LookDirection.Top
+ pos = lookPositions(CInt(LookDirection.Top))
+ myLookat = New Vector3(pos.X, -25000, pos.Z - 1)
+ UpdateMatrix(cameraMatrix)
+ SetRotationFromLookAt()
+ Case LookDirection.Bottom
+ pos = lookPositions(CInt(LookDirection.Bottom))
+ myLookat = New Vector3(pos.X, 25000, pos.Z + 1)
+ UpdateMatrix(cameraMatrix)
+ SetRotationFromLookAt()
+ Case LookDirection.Left
+ pos = lookPositions(CInt(LookDirection.Left))
+ myLookat = New Vector3(25000, pos.Y, pos.Z)
+ UpdateMatrix(cameraMatrix)
+ SetRotationFromLookAt()
+ Case LookDirection.Right
+ pos = lookPositions(CInt(LookDirection.Right))
+ myLookat = New Vector3(-25000, pos.Y, pos.Z)
+ UpdateMatrix(cameraMatrix)
+ SetRotationFromLookAt()
+ Case LookDirection.Front
+ pos = lookPositions(CInt(LookDirection.Front))
+ myLookat = New Vector3(pos.X, pos.Y, -25000)
+ UpdateMatrix(cameraMatrix)
+ SetRotationFromLookAt()
+ Case LookDirection.Back
+ pos = lookPositions(CInt(LookDirection.Back))
+ myLookat = New Vector3(pos.X, pos.Y, 25000)
+ UpdateMatrix(cameraMatrix)
+ SetRotationFromLookAt()
+ End Select
+ End Sub
+
+ Public Sub UpdateCameraMatrixWithMouse(mouseX As Integer, mouseY As Integer, ByRef cameraMatrix As Matrix4)
+ If myCamMode = CameraMode.ORBIT AndAlso GetSelectedObject() IsNot Nothing Then
+ UpdateCameraMatrixWithMouse_ORBIT(mouseX, mouseY, cameraMatrix)
+ ElseIf myCamMode = CameraMode.LOOK_DIRECTION Then
+ UpdateCameraMatrixWithMouse_LOOK(pos, mouseX, mouseY, cameraMatrix)
+ Else
+ UpdateCameraMatrixWithMouse_FLY(mouseX, mouseY, cameraMatrix)
+ End If
+ End Sub
+
+ Public Sub UpdateCameraOffsetWithMouse(orgPos As Vector3, mouseX As Integer, mouseY As Integer, w As Integer, h As Integer, ByRef cameraMatrix As Matrix4)
+ If myCamMode = CameraMode.ORBIT AndAlso GetSelectedObject() IsNot Nothing Then
+ UpdateCameraOffsetWithMouse_ORBIT(mouseX, mouseY, cameraMatrix)
+ ElseIf myCamMode = CameraMode.LOOK_DIRECTION Then
+ UpdateCameraMatrixWithMouse_LOOK(pos, mouseX, mouseY, cameraMatrix)
+ Else
+ UpdateCameraOffsetWithMouse_FLY(orgPos, mouseX, mouseY, w, h, cameraMatrix)
+ End If
+ End Sub
+
+ Public Sub UpdateCameraMatrixWithScrollWheel(amt As Integer, ByRef cameraMatrix As Matrix4)
+ If myCamMode = CameraMode.ORBIT AndAlso GetSelectedObject() IsNot Nothing Then
+ UpdateCameraMatrixWithScrollWheel_ORBIT(amt, cameraMatrix)
+ ElseIf myCamMode = CameraMode.LOOK_DIRECTION Then
+ UpdateCameraMatrixWithScrollWheel_LOOK(amt, cameraMatrix)
+ Else
+ UpdateCameraMatrixWithScrollWheel_FLY(amt, cameraMatrix)
+ End If
+ End Sub
+
+ Private Sub UpdateCameraMatrixWithScrollWheel_FLY(amt As Integer, ByRef cameraMatrix As Matrix4)
+ OffsetCam(amt, amt, amt)
+ OrientateCam(CamAngleX, CamAngleY)
+ UpdateMatrix(cameraMatrix)
+ End Sub
+
+ Public Sub UpdateMatrix(ByRef cameraMatrix As Matrix4)
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, myLookat.X, myLookat.Y, myLookat.Z, 0, 1, 0)
+ End Sub
+
+ Private Sub UpdateCameraMatrixWithScrollWheel_LOOK(amt As Integer, ByRef cameraMatrix As Matrix4)
+ OffsetCam(amt, amt, amt)
+ OrientateCam(CamAngleX, CamAngleY)
+ Select Case currentLookDirection
+ Case LookDirection.Top
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, myLookat.X, myLookat.Y, myLookat.Z - 1, 0, 1, 0)
+ Case LookDirection.Bottom
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, myLookat.X, myLookat.Y, myLookat.Z + 1, 0, 1, 0)
+ Case Else
+ UpdateMatrix(cameraMatrix)
+ End Select
+ End Sub
+
+ Private Sub UpdateCameraMatrixWithMouse_LOOK(orgPos As Vector3, mouseX As Integer, mouseY As Integer, ByRef cameraMatrix As Matrix4)
+ If resetMouse Then
+ lastMouseX = mouseX
+ lastMouseY = mouseY
+ resetMouse = False
+ End If
+ Dim MousePosX As Integer = mouseX - lastMouseX
+ Dim MousePosY As Integer = mouseY - lastMouseY
+
+ Dim pitch_Renamed As Double = CamAngleY - (Math.PI / 2)
+ Dim yaw_Renamed As Double = CamAngleX - (Math.PI / 2)
+ Dim CamLX As Single = CSng(Math.Sin(yaw_Renamed))
+ Dim CamLY As Single = CSng(Math.Cos(pitch_Renamed))
+ Dim CamLZ As Single = CSng(-Math.Cos(yaw_Renamed))
+
+ Dim m As Single = 8.0F
+
+ Select Case currentLookDirection
+ Case LookDirection.Top
+ pos.X = orgPos.X - ((MousePosX * CamSpeedMultiplier) * (CamLX) * m) - ((MousePosY * CamSpeedMultiplier) * (CamLZ) * m)
+ pos.Z = orgPos.Z - ((MousePosX * CamSpeedMultiplier) * (CamLZ) * m) - ((MousePosY * CamSpeedMultiplier) * (CamLX) * m)
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y - 1000, pos.Z - 1, 0, 1, 0)
+ lookPositions(CInt(currentLookDirection)) = pos
+ Case LookDirection.Bottom
+ pos.X = orgPos.X - ((MousePosX * CamSpeedMultiplier) * (CamLX) * m) + ((MousePosY * CamSpeedMultiplier) * (CamLZ) * m)
+ pos.Z = orgPos.Z - ((MousePosX * CamSpeedMultiplier) * (CamLZ) * m) + ((MousePosY * CamSpeedMultiplier) * (CamLX) * m)
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y + 1000, pos.Z + 1, 0, 1, 0)
+ lookPositions(CInt(currentLookDirection)) = pos
+ Case LookDirection.Left
+ pos.X = orgPos.X - ((MousePosX * CamSpeedMultiplier) * (CamLX) * m)
+ pos.Y = orgPos.Y - ((MousePosY * CamSpeedMultiplier) * (-1.0F) * m)
+ pos.Z = orgPos.Z - ((MousePosX * CamSpeedMultiplier) * (CamLZ) * m)
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X + 12500, pos.Y, pos.Z, 0, 1, 0)
+ lookPositions(CInt(currentLookDirection)) = pos
+ Case LookDirection.Right
+ pos.X = orgPos.X - ((MousePosX * CamSpeedMultiplier) * (CamLX) * m)
+ pos.Y = orgPos.Y - ((MousePosY * CamSpeedMultiplier) * (-1.0F) * m)
+ pos.Z = orgPos.Z - ((MousePosX * CamSpeedMultiplier) * (CamLZ) * m)
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X - 12500, pos.Y, pos.Z, 0, 1, 0)
+ lookPositions(CInt(currentLookDirection)) = pos
+ Case LookDirection.Front
+ pos.X = orgPos.X - ((MousePosX * CamSpeedMultiplier) * (CamLX) * m)
+ pos.Y = orgPos.Y - ((MousePosY * CamSpeedMultiplier) * (-1.0F) * m)
+ pos.Z = orgPos.Z - ((MousePosX * CamSpeedMultiplier) * (CamLZ) * m)
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y, pos.Z - 12500, 0, 1, 0)
+ lookPositions(CInt(currentLookDirection)) = pos
+ Case LookDirection.Back
+ pos.X = orgPos.X - ((MousePosX * CamSpeedMultiplier) * (CamLX) * m)
+ pos.Y = orgPos.Y - ((MousePosY * CamSpeedMultiplier) * (-1.0F) * m)
+ pos.Z = orgPos.Z - ((MousePosX * CamSpeedMultiplier) * (CamLZ) * m)
+ cameraMatrix = Matrix4.LookAt(pos.X, pos.Y, pos.Z, pos.X, pos.Y, pos.Z + 12500, 0, 1, 0)
+ lookPositions(CInt(currentLookDirection)) = pos
+ End Select
+
+ lastMouseX = mouseX
+ lastMouseY = mouseY
+ 'Console.WriteLine("CamAngleX = " + CamAngleX + ", CamAngleY = " + CamAngleY);
+ 'setRotationFromLookAt();
+ End Sub
+
+ Private Sub UpdateCameraMatrixWithMouse_FLY(mouseX As Integer, mouseY As Integer, ByRef cameraMatrix As Matrix4)
+ If resetMouse Then
+ lastMouseX = mouseX
+ lastMouseY = mouseY
+ resetMouse = False
+ End If
+ Dim MousePosX As Integer = mouseX - lastMouseX
+ Dim MousePosY As Integer = mouseY - lastMouseY
+ CamAngleX = CamAngleX + (0.01F * MousePosX)
+ ' This next part isn't neccessary, but it keeps the Yaw rotation value within [0, 2*pi] which makes debugging simpler.
+ If CamAngleX > TAU Then
+ CamAngleX -= TAU
+ ElseIf CamAngleX < 0 Then
+ CamAngleX += TAU
+ End If
+
+ ' Lock pitch rotation within the bounds of [-3.1399.0, -0.0001], otherwise the LookAt function will snap to the
+ ' opposite side and reverse mouse looking controls.
+ CamAngleY = Clampf((CamAngleY + (0.01F * MousePosY)), -3.1399F, -0.0001F)
+
+ lastMouseX = mouseX
+ lastMouseY = mouseY
+ OrientateCam(CamAngleX, CamAngleY)
+ UpdateMatrix(cameraMatrix)
+ 'Console.WriteLine("CamAngleX = " + CamAngleX + ", CamAngleY = " + CamAngleY);
+ 'setRotationFromLookAt();
+ End Sub
+
+ Private Sub UpdateCameraOffsetWithMouse_FLY(orgPos As Vector3, mouseX As Integer, mouseY As Integer, w As Integer, h As Integer, ByRef cameraMatrix As Matrix4)
+ If resetMouse Then
+ lastMouseX = mouseX
+ lastMouseY = mouseY
+ resetMouse = False
+ End If
+ Dim MousePosX As Integer = (-mouseX) + lastMouseX
+ Dim MousePosY As Integer = (-mouseY) + lastMouseY
+ Dim pitch_Renamed As Double = CamAngleY - (Math.PI / 2)
+ Dim yaw_Renamed As Double = CamAngleX - (Math.PI / 2)
+ Dim CamLX As Single = Math.Sin(yaw_Renamed)
+ Dim CamLZ As Single = -Math.Cos(yaw_Renamed)
+ pos.X = orgPos.X - ((MousePosX * CamSpeedMultiplier) * (CamLX) * 6.0F)
+ pos.Y = orgPos.Y - ((MousePosY * CamSpeedMultiplier) * (-1.0F) * 6.0F)
+ pos.Z = orgPos.Z - ((MousePosX * CamSpeedMultiplier) * (CamLZ) * 6.0F)
+
+ OrientateCam(CamAngleX, CamAngleY)
+ UpdateMatrix(cameraMatrix)
+ End Sub
+
+ Public Sub UpdateCameraOffsetDirectly(horz_amount As Integer, vert_amount As Integer, ByRef cameraMatrix As Matrix4)
+ If myCamMode = CameraMode.ORBIT Then
+ UpdateCameraOffsetDirectly_ORBIT(horz_amount / 5, vert_amount / 5, cameraMatrix)
+ Else
+ 'Console.WriteLine(MousePosX+","+ MousePosY);
+ Dim pitch_Renamed As Double = CamAngleY - (Math.PI / 2)
+ Dim yaw_Renamed As Double = CamAngleX - (Math.PI / 2)
+ Dim CamLX As Single = CSng(Math.Sin(yaw_Renamed))
+ ' float CamLY = (float)Math.Cos(pitch);
+ Dim CamLZ As Single = CSng(-Math.Cos(yaw_Renamed))
+ pos.X += ((horz_amount * CamSpeedMultiplier) * (CamLX))
+ pos.Y += ((vert_amount * CamSpeedMultiplier) * (-1.0F))
+ pos.Z += ((horz_amount * CamSpeedMultiplier) * (CamLZ))
+
+ OrientateCam(CamAngleX, CamAngleY)
+ UpdateMatrix(cameraMatrix)
+ End If
+ End Sub
+
+ Private Sub UpdateCameraOffsetDirectly_ORBIT(moveSpeedX As Integer, moveSpeedY As Integer, ByRef cameraMatrix As Matrix4)
+ Dim MousePosX As Integer = moveSpeedX
+ Dim MousePosY As Integer = moveSpeedY
+ orbitTheta += MousePosX * 0.01F * CamSpeedMultiplier
+ orbitPhi -= MousePosY * 0.01F * CamSpeedMultiplier
+ orbitPhi = Clampf(orbitPhi, -1.57F, 1.57F)
+ UpdateOrbitCamera(cameraMatrix)
+ End Sub
+
+ Private Sub UpdateCameraMatrixWithMouse_ORBIT(mouseX As Integer, mouseY As Integer, ByRef cameraMatrix As Matrix4)
+ UpdateCameraOffsetWithMouse_ORBIT(mouseX, mouseY, cameraMatrix)
+ End Sub
+
+ Private Sub UpdateCameraOffsetWithMouse_ORBIT(mouseX As Integer, mouseY As Integer, ByRef cameraMatrix As Matrix4)
+ If resetMouse Then
+ lastMouseX = mouseX
+ lastMouseY = mouseY
+ resetMouse = False
+ End If
+ Dim MousePosX As Integer = (-mouseX) + lastMouseX
+ Dim MousePosY As Integer = (-mouseY) + lastMouseY
+ orbitTheta += MousePosX * 0.01F * CamSpeedMultiplier
+ orbitPhi -= MousePosY * 0.01F * CamSpeedMultiplier
+ orbitPhi = Clampf(orbitPhi, -1.57F, 1.57F)
+ UpdateOrbitCamera(cameraMatrix)
+ lastMouseX = mouseX
+ lastMouseY = mouseY
+ End Sub
+
+ Private Sub UpdateCameraMatrixWithScrollWheel_ORBIT(amt As Integer, ByRef cameraMatrix As Matrix4)
+ orbitDistance -= amt
+ If orbitDistance < 300.0F Then
+ orbitDistance = 300.0F
+ End If
+ UpdateOrbitCamera(cameraMatrix)
+ End Sub
+
+ Public Sub ResetMouseStuff()
+ resetMouse = True
+ End Sub
+
+ Private Function CalculateCenterPositionOfObjects(objs As ICameraPoint()) As Numerics.Vector3
+ If objs.Length <= 1 Then
+ Dim obj As ICameraPoint = objs.FirstOrDefault
+ If obj Is Nothing Then
+ Return Numerics.Vector3.Zero
+ Else
+ Return New Numerics.Vector3(obj.Position.X,
+ obj.Position.Y,
+ obj.Position.Z)
+ End If
+ End If
+
+ Dim maxX As Single? = Nothing
+ Dim maxY As Single? = Nothing
+ Dim maxZ As Single? = Nothing
+ Dim minX As Single? = Nothing
+ Dim minY As Single? = Nothing
+ Dim minZ As Single? = Nothing
+
+ For Each obj As ICameraPoint In objs
+ Dim pos As Numerics.Vector3 = obj.Position
+ If maxX Is Nothing OrElse pos.X > maxX Then maxX = pos.X
+ If maxY Is Nothing OrElse pos.Y > maxY Then maxY = pos.Y
+ If maxZ Is Nothing OrElse pos.Z > maxZ Then maxZ = pos.Z
+ If minX Is Nothing OrElse pos.X < minX Then minX = pos.X
+ If minY Is Nothing OrElse pos.Y < minY Then minY = pos.Y
+ If minZ Is Nothing OrElse pos.Z < minZ Then minZ = pos.Z
+ Next
+
+ If maxX Is Nothing Then maxX = 0
+ If maxY Is Nothing Then maxY = 0
+ If maxZ Is Nothing Then maxZ = 0
+ If minX Is Nothing Then minX = 0
+ If minY Is Nothing Then minY = 0
+ If minZ Is Nothing Then minZ = 0
+
+ Dim upper As New Numerics.Vector3(maxX, maxY, maxZ)
+ Dim lower As New Numerics.Vector3(minX, minY, minZ)
+
+ Dim middle As Numerics.Vector3 = (upper + lower) / 2
+
+ Return middle
+ End Function
+
+ Private Function CalculateCenterYRotationOfObjects(objs As ICameraPoint()) As Single
+ If objs.Length <= 1 Then
+ Dim obj As ICameraPoint = objs.FirstOrDefault
+ If obj Is Nothing Then
+ Return 0
+ Else
+ Return obj.Rotation.Y
+ End If
+ End If
+
+ Dim yRot As New List(Of Single)
+
+ For Each obj As ICameraPoint In objs
+ yRot.Add(obj.Rotation.Y)
+ Next
+
+ Return yRot.Average
+ End Function
+
+ Private Function GetSelectedObject() As ICameraPoint()
+ Dim e As New NeedSelectedObjectEventArgs
+ RaiseEvent NeedSelectedObject(e)
+
+ Dim stopw As New Stopwatch
+ stopw.Start()
+
+ Do Until e.HasObjectSetted OrElse stopw.ElapsedMilliseconds > 1000
+ Application.DoEvents()
+ Loop
+
+ stopw.Stop()
+
+ Return e.Points
+ End Function
+
+ 'C A P S E L T C L A S S E S
+
+ Public Class NeedSelectedObjectEventArgs
+ Inherits EventArgs
+
+ Private _HasObjectSetted As Boolean = False
+ Public ReadOnly Property HasObjectSetted As Boolean
+ Get
+ Return _HasObjectSetted
+ End Get
+ End Property
+
+ Private _Points As ICameraPoint() = Nothing
+ Public Property Points As ICameraPoint()
+ Get
+ Return _Points
+ End Get
+ Set(value As ICameraPoint())
+ _Points = value
+ _HasObjectSetted = True
+ End Set
+ End Property
+
+ End Class
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/CameraMode.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/CameraMode.vb
new file mode 100644
index 0000000..57564c6
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/CameraMode.vb
@@ -0,0 +1,9 @@
+Namespace CameraN
+
+ Public Enum CameraMode
+ FLY = 0
+ ORBIT = 1
+ LOOK_DIRECTION = 2
+ End Enum
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/CameraPoint.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/CameraPoint.vb
new file mode 100644
index 0000000..5fb91d1
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/CameraPoint.vb
@@ -0,0 +1,10 @@
+Namespace CameraN
+
+ Public Interface ICameraPoint
+
+ Property Position As Numerics.Vector3
+ Property Rotation As Numerics.Vector3
+
+ End Interface
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/LookDirection.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/LookDirection.vb
new file mode 100644
index 0000000..38853ac
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Camera/LookDirection.vb
@@ -0,0 +1,12 @@
+Namespace CameraN
+
+ Public Enum LookDirection
+ Top
+ Bottom
+ Left
+ Right
+ Front
+ Back
+ End Enum
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/ModelPreview.Designer.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/ModelPreview.Designer.vb
new file mode 100644
index 0000000..2e53c09
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/ModelPreview.Designer.vb
@@ -0,0 +1,120 @@
+
+Partial Class ModelPreview
+ Inherits DevComponents.DotNetBar.OfficeForm
+
+ 'Form overrides dispose to clean up the component list.
+
+ Protected Overrides Sub Dispose(ByVal disposing As Boolean)
+ Try
+ If disposing AndAlso components IsNot Nothing Then
+ components.Dispose()
+ End If
+ Finally
+ MyBase.Dispose(disposing)
+ End Try
+ End Sub
+
+ 'Required by the Windows Form Designer
+ Private components As System.ComponentModel.IContainer
+
+ 'NOTE: The following procedure is required by the Windows Form Designer
+ 'It can be modified using the Windows Form Designer.
+ 'Do not modify it using the code editor.
+
+ Private Sub InitializeComponent()
+ Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(ModelPreview))
+ Me.PanelEx1 = New DevComponents.DotNetBar.PanelEx()
+ Me.PanelEx2 = New DevComponents.DotNetBar.PanelEx()
+ Me.DoubleInput1 = New DevComponents.Editors.DoubleInput()
+ Me.LabelX1 = New DevComponents.DotNetBar.LabelX()
+ Me.PanelEx2.SuspendLayout()
+ CType(Me.DoubleInput1, System.ComponentModel.ISupportInitialize).BeginInit()
+ Me.SuspendLayout()
+ '
+ 'PanelEx1
+ '
+ Me.PanelEx1.CanvasColor = System.Drawing.Color.Empty
+ Me.PanelEx1.ColorSchemeStyle = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled
+ Me.PanelEx1.DisabledBackColor = System.Drawing.Color.Empty
+ Me.PanelEx1.Dock = System.Windows.Forms.DockStyle.Fill
+ Me.PanelEx1.Location = New System.Drawing.Point(0, 47)
+ Me.PanelEx1.Name = "PanelEx1"
+ Me.PanelEx1.Size = New System.Drawing.Size(880, 491)
+ Me.PanelEx1.Style.Alignment = System.Drawing.StringAlignment.Center
+ Me.PanelEx1.Style.BorderColor.ColorSchemePart = DevComponents.DotNetBar.eColorSchemePart.PanelBorder
+ Me.PanelEx1.Style.ForeColor.ColorSchemePart = DevComponents.DotNetBar.eColorSchemePart.PanelText
+ Me.PanelEx1.Style.GradientAngle = 90
+ Me.PanelEx1.TabIndex = 0
+ '
+ 'PanelEx2
+ '
+ Me.PanelEx2.CanvasColor = System.Drawing.Color.Empty
+ Me.PanelEx2.ColorSchemeStyle = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled
+ Me.PanelEx2.Controls.Add(Me.DoubleInput1)
+ Me.PanelEx2.Controls.Add(Me.LabelX1)
+ Me.PanelEx2.DisabledBackColor = System.Drawing.Color.Empty
+ Me.PanelEx2.Dock = System.Windows.Forms.DockStyle.Top
+ Me.PanelEx2.Location = New System.Drawing.Point(0, 0)
+ Me.PanelEx2.Name = "PanelEx2"
+ Me.PanelEx2.Size = New System.Drawing.Size(880, 47)
+ Me.PanelEx2.Style.Alignment = System.Drawing.StringAlignment.Center
+ Me.PanelEx2.Style.BorderColor.ColorSchemePart = DevComponents.DotNetBar.eColorSchemePart.PanelBorder
+ Me.PanelEx2.Style.ForeColor.ColorSchemePart = DevComponents.DotNetBar.eColorSchemePart.PanelText
+ Me.PanelEx2.Style.GradientAngle = 90
+ Me.PanelEx2.TabIndex = 7
+ Me.PanelEx2.Visible = False
+ '
+ 'DoubleInput1
+ '
+ '
+ '
+ '
+ Me.DoubleInput1.BackgroundStyle.Class = "DateTimeInputBackground"
+ Me.DoubleInput1.BackgroundStyle.CornerType = DevComponents.DotNetBar.eCornerType.Square
+ Me.DoubleInput1.ButtonFreeText.Shortcut = DevComponents.DotNetBar.eShortcut.F2
+ Me.DoubleInput1.Increment = 1.0R
+ Me.DoubleInput1.Location = New System.Drawing.Point(62, 13)
+ Me.DoubleInput1.Name = "DoubleInput1"
+ Me.DoubleInput1.ShowUpDown = True
+ Me.DoubleInput1.Size = New System.Drawing.Size(80, 20)
+ Me.DoubleInput1.TabIndex = 0
+ '
+ 'LabelX1
+ '
+ '
+ '
+ '
+ Me.LabelX1.BackgroundStyle.CornerType = DevComponents.DotNetBar.eCornerType.Square
+ Me.LabelX1.Location = New System.Drawing.Point(12, 12)
+ Me.LabelX1.Name = "LabelX1"
+ Me.LabelX1.Size = New System.Drawing.Size(44, 23)
+ Me.LabelX1.TabIndex = 1
+ Me.LabelX1.Text = "Scaling:"
+ '
+ 'ModelPreview
+ '
+ Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
+ Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
+ Me.ClientSize = New System.Drawing.Size(880, 538)
+ Me.Controls.Add(Me.PanelEx1)
+ Me.Controls.Add(Me.PanelEx2)
+ Me.DoubleBuffered = True
+ Me.EnableGlass = False
+ Me.Icon = CType(resources.GetObject("$this.Icon"), System.Drawing.Icon)
+ Me.KeyPreview = True
+ Me.Name = "ModelPreview"
+ Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
+ Me.Text = "ModelPreview"
+ Me.TopLeftCornerSize = 0
+ Me.TopRightCornerSize = 0
+ Me.PanelEx2.ResumeLayout(False)
+ CType(Me.DoubleInput1, System.ComponentModel.ISupportInitialize).EndInit()
+ Me.ResumeLayout(False)
+
+ End Sub
+
+ Friend WithEvents PanelEx1 As DevComponents.DotNetBar.PanelEx
+ Friend WithEvents PanelEx2 As DevComponents.DotNetBar.PanelEx
+ Friend WithEvents DoubleInput1 As DevComponents.Editors.DoubleInput
+ Friend WithEvents LabelX1 As DevComponents.DotNetBar.LabelX
+End Class
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Application.Designer.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Application.Designer.vb
new file mode 100644
index 0000000..8ab460b
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Application.Designer.vb
@@ -0,0 +1,13 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Application.myapp b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Application.myapp
new file mode 100644
index 0000000..758895d
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Application.myapp
@@ -0,0 +1,10 @@
+
+
+ false
+ false
+ 0
+ true
+ 0
+ 1
+ true
+
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/AssemblyInfo.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..05b61da
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' Allgemeine Informationen über eine Assembly werden über die folgenden
+' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+' die einer Assembly zugeordnet sind.
+
+' Werte der Assemblyattribute überprüfen
+
+
+
+
+
+
+
+
+
+
+'Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird.
+
+
+' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+'
+' Hauptversion
+' Nebenversion
+' Buildnummer
+' Revision
+'
+' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+' übernehmen, indem Sie "*" eingeben:
+'
+
+
+
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Resources.Designer.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..300e380
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Resources.Designer.vb
@@ -0,0 +1,63 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+Imports System
+
+Namespace My.Resources
+
+ 'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
+ '-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
+ 'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
+ 'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
+ '''
+ ''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Pilz.Drawing.Drawing3D.OpenGLFactory.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
+ ''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Resources.resx b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Settings.Designer.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..7ef730a
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
+
+#Region "Automatische My.Settings-Speicherfunktion"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+ _
+ Friend ReadOnly Property Settings() As Global.Pilz.Drawing.Drawing3D.OpenGLFactory.My.MySettings
+ Get
+ Return Global.Pilz.Drawing.Drawing3D.OpenGLFactory.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Settings.settings b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Settings.settings
new file mode 100644
index 0000000..85b890b
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/My Project/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/OpenTK.dll.config b/Pilz.Drawing.Drawing3D.OpenGLRenderer/OpenTK.dll.config
new file mode 100644
index 0000000..7098d39
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/OpenTK.dll.config
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj
new file mode 100644
index 0000000..1829246
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj
@@ -0,0 +1,142 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}
+ Library
+ Pilz.Drawing.Drawing3D.OpenGLFactory
+ Pilz.Drawing.Drawing3D.OpenGLFactory
+ 512
+ Windows
+ v4.5
+
+
+ true
+ full
+ true
+ true
+ bin\Debug\
+ Pilz.Drawing.Drawing3D.OpenGLFactory.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ pdbonly
+ false
+ true
+ true
+ bin\Release\
+ Pilz.Drawing.Drawing3D.OpenGLFactory.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ On
+
+
+ Binary
+
+
+ Off
+
+
+ On
+
+
+
+ ..\packages\OpenTK.3.0.1\lib\net20\OpenTK.dll
+
+
+ ..\packages\OpenTK.GLControl.3.0.1\lib\net20\OpenTK.GLControl.dll
+
+
+
+
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\portable-net45+win8+wp8+wpa81\System.Numerics.Vectors.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ModelPreview.vb
+
+
+ Form
+
+
+
+
+
+
+ True
+ Application.myapp
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+ Designer
+
+
+ ModelPreview.vb
+
+
+
+
+
+ MyApplicationCodeGenerator
+ Application.Designer.vb
+
+
+ SettingsSingleFileGenerator
+ My
+ Settings.Designer.vb
+
+
+
+
+
+
+ {ac955819-7910-450c-940c-7c1989483d4b}
+ Pilz.Simple3DFileParser
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.Designer.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.Designer.vb
new file mode 100644
index 0000000..0ee6e5e
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.Designer.vb
@@ -0,0 +1,42 @@
+Namespace PreviewN
+
+
+ Partial Class ModelPreview
+ Inherits System.Windows.Forms.Form
+
+ 'Form overrides dispose to clean up the component list.
+
+ Protected Overrides Sub Dispose(ByVal disposing As Boolean)
+ Try
+ If disposing AndAlso components IsNot Nothing Then
+ components.Dispose()
+ End If
+ Finally
+ MyBase.Dispose(disposing)
+ End Try
+ End Sub
+
+ 'Required by the Windows Form Designer
+ Private components As System.ComponentModel.IContainer
+
+ 'NOTE: The following procedure is required by the Windows Form Designer
+ 'It can be modified using the Windows Form Designer.
+ 'Do not modify it using the code editor.
+
+ Private Sub InitializeComponent()
+ Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(ModelPreview))
+ Me.SuspendLayout()
+ '
+ 'ModelPreview
+ '
+ Me.ClientSize = New System.Drawing.Size(880, 538)
+ Me.DoubleBuffered = True
+ Me.Name = "ModelPreview"
+ Me.Text = "ModelPreview"
+ Me.ResumeLayout(False)
+
+ End Sub
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.resx b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.resx
new file mode 100644
index 0000000..42188b9
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.resx
@@ -0,0 +1,1978 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ AAABAAIAgIAAAAEAIAAoCAEAJgAAAAAAAAABACAAz6kAAE4IAQAoAAAAgAAAAAABAAABACAAAAAAAAAA
+ AQATCwAAEwsAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////ALjx/xK59fozuPT6Xrjz+YK39fqYtvT5pbf0+qS28/mlt/P6mLf1
+ +3+28PZXt/L4J6r//wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AuPX1Gbr0+Vm79/yiuvb72bj1
+ +vi7+v//vPz//7v8//+5/P//ufz//7r7//+5+///ufz//7j5//+39vztt/T6v7bz+m289P8X////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8AtvX6Mbz2/ZC69fzgvPr//778//+6+f//tfb8/7P1+/+y9Pr/sfT6/7D0+v+v9Pr/r/T6/6/0
+ +v+w9Pr/sfT7/7T3/f+4+///ufv//7f1/Ny19Phyv+r/DP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8Auu/0ML33/aK79/3yv/7//7r5//+29fv/tPX6/7Hz
+ +v+s8Pn/qO33/6Tp9f+h5/P/nubz/57m8v+d5vL/n+fz/6Ho9P+l7Pb/qvD4/67z+v+x9Pr/tvn//7v7
+ //+49/u/tfT0MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AtufzFbr0
+ +Yi89/3wwP3//7n3/f+29fr/s/T6/63w+P+l6vX/n+Ty/5rh8P+X4O//ld/v/5Tf7/+T3+//k97v/5Pf
+ 7/+T3+//k9/v/5Xf7/+Y4fD/neXy/6bs9v+u8vr/s/X7/7v9//+69/zktPP3Qf///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////ALz4+0i99vvQwP3//7r4/f+39fr/s/T6/6zu9/+i5fP/m+Hw/5jf
+ 7/+V4O//lODv/5Pf7/+R3+//kd7v/5De7/+Q3u7/kN7u/5De7v+Q3u//kd7v/5Lf7/+U3+//luDv/53k
+ 8v+q7vf/svT6/7r7//+7+P3muPH6Nv///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AMz//wW89Pt5vfj+9r/7
+ //+49fr/tvX6/67v+P+i5fL/m+Dw/5jf7/+W4O//leDv/5Pf7/+R3+//j97v/47e7v+N3u7/jd7u/4ze
+ 7v+N3u7/jN7u/43e7v+O3u7/j97u/5Hf7/+T3+//leDv/5rh7/+n6vX/s/P6/779//+69frOw///Ef//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wC27f8OuvX6n7/7//+7+P7/uPb7/7Ly+f+n6PT/nuHw/5rg8P+Y4O//leDv/5Pf
+ 7/+R3+//j9/v/43e7v+M3u7/i97u/4rd7v+K3e7/it3u/4rd7v+K3e7/it3u/4ze7v+M3u7/j97u/5Hf
+ 7/+T3+//l+Dv/5vf7/+n6fX/tfT6/7/9//+89ft9////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AyP//Drv1+7HC////uvb8/7j1
+ +/+v7/f/ouPy/5zg8P+b4PD/mODv/5Tf7/+S3+//kN/v/47e7v+M3u7/it7u/4rd7v+K3e7/id3u/4nd
+ 7v+J3e7/iN3u/4nd7v+K3e7/it3u/4ve7v+N3u7/j97u/5Pf7/+W4O//muDw/5zg8P+q6vX/vPn+/7n0
+ +eO19PQY////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AKrj/wm79fuswf///7r2+/+49vv/rez2/5/h8P+d4PD/muDw/5ff7/+U3+//kd7v/4/d
+ 7/+N3e7/i93u/4rd7v+J3u7/h93u/4jd7v+I3e7/h93u/4jd7v+I3e7/iN3u/4nd7v+K3e7/i93u/43e
+ 7v+P3u7/kt/v/5Xg7/+Z4O//neDw/6Hh8P+y7/j/v/z//7v0+mH///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Auvb6jMH9//+69vz/t/X7/6rq
+ 9f+f4PD/nODw/5ng8P+W3+//k9/v/5De7/+O3e//i93v/4rc7v+J3O7/iN3u/4fd7v+H3e7/h93u/4bd
+ 7v+H3e7/h93u/4fc7v+H3O7/id3u/4rd7v+L3u7/jd/u/4/f7/+S3+//leDv/5jf7/+c3/D/oODw/6jl
+ 8v/A/P//vPb8pAD//wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////ALz0+Vu++f38u/f9/7n1+/+s6/X/n+Dw/5zg8P+Z4PD/lt/v/5Pf7/+Q3u//jd7v/4vd
+ 7/+J3O7/h9zu/4fc7v+H2+7/h9zu/4fd7v+H3e7/htzu/4fd7v+J3+//iuHx/4/l8v+T6PT/len1/5fr
+ 9v+b7Pb/nez2/57s9v+h6/X/ounz/6Hl8v+i4vH/o+Hw/7fz/P+99/vXsf/rDf///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wC59/chvPb84r/7//+69fv/r+z2/6Dg
+ 8P+d4PD/muDw/5bf8P+T3+//kN7v/43e7v+K3e7/idzu/4fc7v+G3O7/htzu/4Tb7v+F2+7/htzu/4je
+ 7/+N4/H/kun1/5bt9/+Y7/j/mvD4/5vw+P+c7/j/nfD4/5/w+P+i8fn/pPH5/6ny+f+t8/r/sPP6/7Lx
+ +f+u6/X/s+75/732++u9+Pgj////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8AgICAArr0+qbC////uvX7/7Lw+f+i4fH/neDw/5rg8P+W4PD/k9/v/5De7v+M3e7/id3t/4jc
+ 7f+G3O3/hdzu/4Xc7v+F3O7/hNvu/4fd7/+P5fP/lOz3/5jv+P+Y7/j/me/4/5rv+P+a7/j/nPD4/53w
+ +P+e8Pj/oPD4/6Px+f+m8fn/qvL5/67z+v+z9Pr/t/X6/7n2+/+89v3/vfb89L71+jP///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wC69fhKvvn8+rz3/P+39Pv/puXy/57g
+ 8P+b4PD/l+Dw/5Pf7/+P3u7/i93t/4nd7f+G3O3/hdzs/4Pc7P+D3Oz/hNzt/4Xd7v+N5PP/lOz3/5fv
+ +P+Y7/j/me/4/5nv+P+a7/j/nO/4/53w+P+e8Pj/n/D4/6Dw+P+j8fn/pfH5/6jy+f+s8/n/sPP6/7P0
+ +v+39fr/uvX7/733/f+89vv5vPb7Of///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8Av///CLz2+8PB/f//ufb7/6zr9v+f4PD/nODw/5jg8P+U3+//kN7u/4ze7f+I3e3/htzt/4Tc
+ 7f+D3Oz/g9zs/4Pb7P+H4e//ker2/5bu+P+W7vj/mO74/5nv+P+b7/j/m/D4/53w+P+e8Pj/nvD4/6Dw
+ +P+i8fn/o/H5/6Xx+f+o8vn/qvL5/67z+v+x9Pr/tfT6/7j1+v+69fv/vff9/7z2+vW+9foz////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wC59Plbvfj8/7v2/P+08fn/o+Lx/53g
+ 8P+a4PD/ld/v/5Hf7v+M3u3/idzt/4bb7f+D2u3/gtrs/4Ha7P+B3Oz/i+Xx/5Lt9v+U7vf/le74/5fu
+ +P+Z7vj/m+/4/5zw+P+d8Pj/nvD4/6Dw+f+i8fn/o/H5/6Xx+f+n8vn/qfL5/6vy+f+u8/n/sPP6/7T0
+ +v+39Pr/ufX7/7v1+/+/+f7/vvb77MH4/yX///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A1f//Brv2+8TA/f//ufX7/6nn9P+e4PD/m+Dw/5bg7v+R3+7/jN7t/4nc7f+F2+3/g9rs/4Ha
+ 7P+A2ez/gtzt/4vm8/+Q7vb/ku72/5Tu9/+X7vj/me74/5rv+P+d7/n/n/D5/6Dx+f+h8fn/pPH5/6Xx
+ +f+n8vn/qPL5/6ry+f+s8vn/rvP6/7Hz+v+z9Pr/tfT6/7j1+v+69fv/vPX7/8D6//++9vzew/D/Ef//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wC8+PtEvPj8/Lv2/P+z7/n/oeHx/53g
+ 8P+Z4O//k9/u/47e7v+J3e3/htvt/4Pa7f+B2uz/f9rs/4Db7f+K6PT/kO32/5Dt9v+S7vb/le73/5ju
+ +P+a7/j/nO/4/57v+f+i8Pn/o/H5/6Xy+f+n8vn/qfL5/6vy+f+s8vn/rvP6/6/z+v+x8/r/s/T6/7b0
+ +v+49fr/ufX7/7v1+/+99vv/w/z//771+7mq//8D////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////Abz2/KfB/v//ufX7/6no9P+e3/D/m+Dw/5Xg7/+Q3+7/jN3t/4fb7f+D2+3/gdrs/3/a
+ 7P9/2+z/iefz/47s9v+P7Pb/ke32/5Pu9/+W7vf/me74/5zv+f+e7/n/ofH5/6Tx+f+m8vn/qPL5/6vy
+ +f+s8/r/rvP6/7Dz+v+y8/r/s/T6/7T0+v+29Pr/uPX6/7r1+/+79fv/vPX7/772+//F////vfT5i///
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wC58vkovPb78rz4/f+z8Pn/oeHx/53g
+ 8P+Y4O//kt/u/43d7f+I3O3/hdvt/4La7P9/2uz/ftrs/4bl8v+N7fb/jez2/4/s9v+R7Pb/le73/5jv
+ 9/+b7/j/nu/5/6Lw+f+k8Pn/p/L5/6jy+f+s8/r/rvP6/7Dz+v+y9Pr/s/T6/7X0+v+29Pr/t/X6/7j1
+ +v+69fv/u/X7/7z1+/+99vv/v/f8/8H5/f+68/lV////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////ALz3+3rB/v//ufX8/6vp9f+d3/D/muDv/5Tg7v+R3u7/i9zt/4bb7f+D2+3/gNrs/33Z
+ 7P+C4fD/jOz2/43s9v+O7Pb/kez2/5Tt9/+X7/f/mu/3/57w+P+h8Pn/pPD5/6fx+f+q8/n/rPP6/6/z
+ +v+y9Pr/s/T6/7X0+v+29Pr/uPX6/7n1+v+59fv/uvX7/7v1+/+89vv/vfb7/772+//A+f7/vvX77MHw
+ 9yH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wC///8Mu/T60776//+28vr/o+Px/53g
+ 7/+Y4O//k9/u/43d7v+I2+3/hNvt/4Hb7f9+2uz/gN7u/4vr9f+N7Pb/jez2/4/s9v+S7Pf/le33/5jv
+ 9/+e8Pf/oPD5/6Tw+f+n8fn/qvL6/67z+v+w9Pr/svT6/7T0+v+29fr/uPX6/7j1+/+69fv/u/X7/7v1
+ +/+89fv/vfb7/772+/+99vv/vvb7/8T9//++9fm3////Af///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////ALr0+Ea89/z9uvb9/67s9/+f4fD/m+Dv/5bg7v+Q3u7/itzt/4bb7f+C2+3/gNrs/37a
+ 7P+I6PP/je32/43s9v+P7Pb/ke33/5Tt9/+Y7vf/m/D3/5/w+P+j8fn/p/H5/6vy+v+u8/r/sPT6/7P0
+ +v+09Pr/t/X6/7j1+/+69fv/u/X7/7v1+/+89vv/vPb7/732+/++9vv/vvb7/772+/+/9vv/xPz//733
+ +mX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Au/P6mcH+//+49Pv/pebz/53g
+ 8P+Z4O//k9/u/47d7v+J3O3/hNvt/4Ha7f9/2ez/hOLx/4zs9v+O7Pb/juz2/5Ds9/+T7ff/l+33/5vv
+ 9/+f8Pf/o/H4/6fx+f+q8vr/rvL6/7Hz+v+z9Pr/tfX6/7f1+/+69fv/uvX7/7v1+/+89fv/vfb7/732
+ +/++9vv/vvb7/772+/+/9vv/v/b7/8L5/v++9fvnv/b/HP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////ALbz8xW79PrhvPn+/7Pw+f+g4fD/nODv/5fg7/+R3u7/i93u/4fc7f+D2+3/gNrt/4Hc
+ 7v+L6vX/jez2/47s9v+P7Pf/k+33/5bt9/+b7vf/nvD4/6Lx+P+m8fn/qvL6/67y+v+w8/r/tPT6/7b1
+ +v+49fv/uvX7/7v1+/+79vv/vfb7/732+/++9vv/vvb7/772+/++9vv/v/b7/7/2+/+/9vv/xv///73z
+ +pf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Au/b5U735/f+59vz/rOv2/53g
+ 7/+a4O//lN/u/4/d7v+J3O3/hdzt/4Lb7f9/2u3/huPy/43t9v+N7Pf/j+33/5Ht9/+V7vf/me73/53v
+ +P+h8Pj/pvH4/6ry+f+t8/r/sPP6/7P0+v+29fr/uPX7/7r1+/+79fv/vPb7/732+/++9vv/vvb7/772
+ +/++9vv/v/b7/7/2+/+/9vv/v/b7/8D4/f/A+Pz2vfb2Nv///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wC69PyjwP7//7bz+/+k5fL/nODv/5jf7/+S3u7/jN3u/4jc7f+E2+3/gdvt/4Hd
+ 7v+M6/b/ju33/47s9/+R7ff/lO33/5fu9/+b7vf/oO/4/6Ty+P+p8vn/rfP6/7Dz+v+z8/r/tvT6/7j1
+ +/+69fv/vPb7/7z2+/+99vv/vvb7/772+/+/9vv/vvb7/7/2+/+/9vv/v/b7/7/2+/+/9vv/xf///772
+ +qn///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AuPX1Gbn0++W7+P7/sO/4/5/h
+ 8P+a4O//ld/v/5De7v+L3e7/htzt/4Pb7f9/2e3/huTz/43s9/+O7ff/j+33/5Lu9/+W7vf/mu73/53v
+ +P+j8Pj/qPL4/6zy+f+v8/r/s/P6/7b0+v+49fv/u/X7/7v1+/+99vv/vfb7/772+/++9vv/v/b7/7/2
+ +/+/9vv/v/b7/7/2+/+/9vv/v/b7/8H4/f/B+Pz2vPL2Of///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wC59vxUvPn9/7j2/P+p6vX/nN/v/5jf7/+T3+//jt7u/4nd7v+E3O3/gdrt/4Hd
+ 7v+M6/b/jez3/4/s9/+R7ff/le33/5jv+P+d7/j/ofD4/6bx+P+r8vn/rvP6/7Lz+v+19Pr/t/T7/7n1
+ +/+79vv/vPb7/732+/++9vv/vvb7/7/2+/+/9vv/v/b7/7/2+/+/9vv/v/b7/7/2+/+/9vv/xv///770
+ +pz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ALn0+qO//v//tPP5/6Lk
+ 8f+b4O//lt/v/5De7v+L3e7/h9zt/4Pb7f9/2e3/h+Tz/47t9/+N7Pf/j+z3/5Lt9/+W7vf/m+/4/5/w
+ +P+l8fj/qfH5/63z+f+x8/r/tPT7/7f0+/+59fv/u/b7/7z2+/+99vv/vvb7/7/2+/+/9vv/v/b7/7/2
+ +/+/9vv/v/b7/7/2+/+/9vv/v/b7/8L6/v+/9/znvfj4I////wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wC49fUZufT75br4/f+u7/f/neDv/5ng7/+T3+//jt7u/4nd7v+F3O3/gNvt/4Hc
+ 7v+L6vb/jez3/47s9/+Q7ff/k+33/5ju+P+d7/j/ovD4/6bx+P+s8vn/r/P5/7P0+v+19Pv/ufT7/7v1
+ +/+89vv/vfb7/772+/++9vv/vvb7/7/2+/+/9vv/v/b7/7/2+/+/9vv/v/b7/7/2+/+/9/z/xPz+/7z0
+ +G////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ALfw9lW7+f3/t/X7/6jp
+ 9P+b3+//luDv/5De7v+M3e7/htzu/4Lb7f9/2u3/hOLy/4zt9/+N7Pf/j+33/5Ht9/+V7ff/mu/4/5/w
+ +P+k8fj/qfL5/67z+f+x8/n/tPT7/7j0+/+69fv/u/b7/7z2+/+99vv/vvb7/772+/++9vv/v/b7/7/2
+ +/+/9vv/v/b7/7/2+/+/9vv/v/b7/8X+//+/9fu6v///CP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wAA//8Bt/T5p739//+y8vn/oOLx/5ng7/+U3+//jt7u/4nc7v+E2+3/gNvt/3/b
+ 7f+J6fX/i+z3/4zs9/+P7ff/ku33/5fu+P+b7/j/ofD4/6fx+f+r8vn/sPP5/7P0+v+29Pv/ufX7/7r1
+ +/+89vv/vfb7/732+/++9vv/v/b7/7/2+/+/9vv/v/b7/7/2+/+/9vv/v/b7/7/2+//C+v7/wPf87Lz0
+ +S7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ALbt9hy49fvoufj9/6zu
+ 9/+c4O//l+Dv/5Hf7/+M3e7/htzu/4Lb7f992uz/geDv/4vs9v+L7Pb/jez3/4/t9/+T7ff/me74/53w
+ +P+k8Pj/qfH5/63y+f+x9Pn/tfT6/7j0+/+69fv/u/b7/7z2+/+99vv/vvb7/772+/++9vv/v/b7/7/2
+ +/+/9vv/v/b7/7/2+/+/9vv/wPf8/8P7/v7A+P1p////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8Auvb8Vbr4/P+19Pv/pef0/5rf7/+U3+//j97u/4nd7v+E3O7/f9rs/33a
+ 6/+F5vP/iez1/4rs9f+N7Pb/kO33/5Tu+P+a7/j/oPD4/6bx+f+q8vn/r/P5/7L0+f+29Pv/uPX7/7r1
+ +/+89vv/vfb7/772+/++9vv/v/b7/7/2+/+/9vv/v/b7/7/2+/+/9vv/v/b7/7/2+//G////v/T6o6qq
+ qgP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wC49fqfvf3//7Hx
+ +f+e4vH/l+Dv/5Pf7/+M3e7/htzu/4Lb7f982ev/ftzt/4fq9f+I6/X/iuv1/43s9v+R7vf/lu74/5vv
+ +P+h8Pn/p/L5/63y+f+w8/n/tPT6/7f0+/+59fv/u/X7/731+/+99vv/vfb7/732+/++9vv/vvb7/7/2
+ +/+/9vv/v/b7/7/2+/+/9vv/xP3//7/2+9C19PQY////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8AuPHxErf2+tu4+P7/rO33/5rg7/+V3+//j97v/4nd7v+E2+3/f9rr/3vY
+ 7P+C4/D/iOv1/4fr9f+K6/b/jez2/5Lu9/+Y7/j/ne/4/6Lw+f+p8vn/rfL5/7Lz+v+19Pr/uPX6/7n1
+ +/+79fv/vfb7/732+/++9vv/vvb7/772+/+/9vv/v/b7/7/2+/+/9vv/v/b7/8L6///A9/zqvvD6M///
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wC48vs9t/b7+7X1
+ /P+l6PT/mN/v/5Pe7/+O3u//h9zt/4La6/992ev/e9vs/4Xo9P+H6/X/h+v1/4nr9v+O7Pb/k+73/5nv
+ +P+e8Pn/pPH5/6ry+f+u8/n/s/T6/7X0+v+59fv/uvX7/7z1+/+99vv/vfb7/772+/++9vv/vvb7/772
+ +/+/9vv/v/b7/7/2+//B+P3/wvr9+L72/Fb///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////ALf3+3m8/f//sPL6/57j8v+X3+//kd7u/4rd7f+F2uz/gNrr/3rY
+ 6/9/3+//hur0/4br9f+H6/X/iuv2/47s9v+U7vf/mu/4/6Dw+f+m8vn/q/L5/7Dz+f+z9Pr/tvX6/7n1
+ +/+79fv/vPX7/732+/+99vv/vvb7/772+/++9vv/v/b7/7/2+/+/9vv/wPf8/8P6/f+99Pt4////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wCA//8CtvT5trn7
+ //+s7/j/m+Dw/5Tf7/+P3u7/iNvs/4LZ6/992ev/edjr/4Lm8v+F6/T/hev1/4fq9f+L6/b/j+z2/5Xt
+ 9v+b7/j/ofD5/6jx+f+s8/n/sfP6/7X0+v+39fv/uvX7/7v1+/+99vv/vfb7/732+/++9vv/vvb7/7/2
+ +/+/9vv/v/b7/8D3/P/E/f//vfb6k////wH///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////ALXq9Bi29Pvjtvj+/6bq9f+X3u//kt7u/4zc7P+F2uv/f9jr/3rX
+ 6v973O3/hOf0/4Po8/+F6vT/h+r1/4vs9v+R7Pb/lu32/53v+P+j8fn/qfL5/67z+f+y8/r/tfT6/7f1
+ +/+69fv/u/X7/732+/++9vv/vvb7/772+/+/9vv/v/b7/7/2+/+/9vv/xv///771+6yz5uYK////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AtfP3PrX1
+ +/uz9fv/n+Ty/5Xe7f+Q3e3/idrr/4PY6v991+n/edXo/3/h7/+D5/P/gufz/4Tp9P+I6vX/jOz2/5Lt
+ 9v+Z7vf/n/D5/6Xx+f+r8/n/r/P5/7T0+v+39fr/ufX7/7v1+/+89fv/vfb7/772+/++9vv/vvb7/7/2
+ +/+/9vv/v/b7/8b///+/9/u+v/LyFP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wC18/puuvz//67x+f+a4fD/k97u/43c7P+H2Ov/gdfp/3rU
+ 5/941uj/gePw/4Ll8f+C5vL/hOj0/4nq9f+N7Pb/k+33/5vv9/+h8Pj/p/H5/6zz+f+x8/r/tPT6/7f1
+ +v+59fv/u/X7/7z2+/+99vv/vfb7/772+/+/9vv/v/b7/7/2+//F/v//wPb7zbb29hz///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ALTy
+ +aO5/P//qu73/5ff7/+R3e3/itnr/4XX6f9+1ef/eNLm/3ra6f+B5PD/gOTw/4Lm8f+E6PT/ier1/4/s
+ 9v+V7ff/nO/3/6Px+f+p8fn/rvP6/7Hz+v+19fr/uPX6/7r1+/+79fv/vPX7/732+/++9vv/vvb7/7/2
+ +/++9vv/xf7//8D4+9a68fgl////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wCq4+MJtPT5zbT4//+l6fX/ld7u/5Dc6/+I2Or/gdbn/3vT
+ 5f930eT/ft3r/3/j7v9/5O//guXx/4bn8/+K6vT/kez2/5ju9/+f8Pf/pfH5/6ry+f+w8/r/s/T6/7b1
+ +v+49fv/uvX7/7v1+/+99vv/vvb7/772+/++9vv/vvb7/8T9//+/9/revvT6L////wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AK/w
+ 8COy8vrusvX8/57l8v+S3Oz/jNrq/4bY6P9/1Ob/eNHj/3fT5P9+4Oz/fuHt/3/j7/+C5PH/h+fy/4zq
+ 9P+T7fb/me73/6Dw+P+n8fn/rPL5/7Dz+v+09Pr/tvX6/7j1+/+69fv/u/X7/732+/+99vv/vvb7/772
+ +//D+///wPj95r/2+jj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8As/T3Q7L1+/yu8vr/muHw/5Hc6/+K2Or/g9Xm/3zS
+ 5f92z+H/edfm/37g6/994Oz/f+Pu/4Pl8f+J6PP/juv1/5Xu9v+c7vf/ovD4/6jx+f+t8vr/sfP6/7T0
+ +v+39fr/ufX7/7r1+/+99fv/vfb7/732+/++9vv/wvv//8D3/e288/dB////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCz8/pot/v//6ru9/+W3u3/j9rr/4jX6f+B0+X/etDj/3XO4P972ub/fd7q/33g7P+A4u7/heXw/4vo
+ 8/+R6/X/l+32/5/v9/+l8fn/q/L5/6/z+v+y8/r/tvT6/7j1+v+69fv/u/X7/732+/+99vv/vfb7/8H6
+ ///B+f3xvvX8S////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////ALHz+JS2/P//pev1/5Td7P+N2er/hdXn/3/S
+ 5P94zuH/ddDh/33c5/993en/ft/r/4Hj7v+G5vH/jejz/5Ps9f+a7vb/oe/4/6fx+f+s8vn/sfP6/7T0
+ +v+29fr/ufX7/7r1+/+79fv/vfb7/732+//A+f7/wfr99MD2/Fn///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCAgP8CsfP4u7P5//+h5/P/kdrr/4rY6f+E1OX/fNHj/3XN3/940+H/fdzn/33d6P9/4Ov/hOPu/4nm
+ 8f+Q6vT/l+31/53u9/+k8Pj/qfL6/67z+v+y9Pr/tPT6/7f1+v+69fv/u/X7/7z1+/+89vv/wPn9/8L7
+ /vq98/pp////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////ALvu/w+w8vnYsPb9/5zj8P+O2Or/iNbo/4DS
+ 5P96zuH/dMze/3rW4/993ef/fd7o/4Hh6/+F5O//jOfy/5Lr9P+Z7vb/n+/3/6bx+P+q8vr/rvP6/7P0
+ +v+19Pr/uPX7/7r1+/+79fv/vPb7/774/P/B+v7+uvT5d////wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8As/H4Ja/y+fKr8vr/l9/t/43Y6f+G1eb/f9Dj/3fM3/90zN7/fNnk/33b5v9/3+n/g+Ls/4jl
+ 8P+O6PP/lez1/5zu9/+j8Pf/qPL5/6zy+v+w8/r/tPT6/7b0+v+49fv/uvX7/7z1+/+99vz/wfz//7z0
+ +Yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wCx8/tBrvL4/Kjv9/+U3Ov/i9fo/4TT
+ 5f99z+H/dsvd/3fP3/9+2+X/ftvm/4Df6f+F4u7/jObx/5Lp8/+Y7PX/n+/3/6Xw+P+p8vr/rvP6/7H0
+ +v+19Pr/t/X6/7n1+/+69fv/vPX7/8P+//+79PqmzP//Bf///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////ALLy+mCy+P7/o+v1/5Da6v+J1uf/gtLj/3vN3/91ytz/etPh/3/b5f9/3Of/g+Dq/4fk
+ 7v+O5/H/lev0/5vu9v+i8Pf/pvH5/6zy+v+v9Pr/s/T6/7X0+v+49fr/ufX7/7v1+//D/f//vvb7yL/y
+ /xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8ArvD3hbL7//+g6PP/jtjo/4jV
+ 5f9/0eL/esze/3XK3P981uP/f9vm/4Hd6P+E4ev/ieTv/5Do8v+Y7PX/ne/3/6Pw9/+o8vn/rfL6/7D0
+ +v+z9Pr/tvT6/7j1+v+69fv/v/n//7z2/Oa++f8r////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wCt8feosPj//5vj8P+M1+f/hdPk/37P4f94yt3/d8zd/3/Z5P9/2+b/gt7p/4bi
+ 7f+M5vD/k+rz/5vt9v+g7/f/pfD4/6ry+v+u8/r/svT6/7T0+v+39fr/ufX6/7z3/P/A+v75u/b5U///
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Amcz/Bazx+MSs9fz/lt/t/4rV
+ 5v+D0uP/fM7f/3bK2/94z97/gNrk/4Db5/+D3+r/ieTu/4/n8f+W6/X/nO72/6Lw9/+n8fn/rPL6/6/z
+ +v+z9Pr/tfT6/7j1+v+69fv/wP3//7r0+In///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wCz8v8Uq/D34Kjx+f+T3Or/iNXl/4HR4v97zd7/dsnb/3rT4P+A2uX/gt3o/4Xg
+ 6v+L5e//keny/5js9f+e7/f/pPD3/6nx+f+t8/r/sfP6/7P0+v+29Pr/uPT6/8D8//+89vvDxP//Df//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AKTn8yqn7fb0o+32/47Z
+ 6P+G0+T/f8/g/3nM3f91ytv/fdbi/4Db5v+C3ej/huLs/43m8P+U6vP/mu32/6Hv9/+l8fj/qvL5/6/z
+ +v+y9Pr/tfT6/7b1+v+7+P3/uvX77rr0+jD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8An9/tSJzk8f2e5/L/jNfo/4TS4/99zt//d8rc/3XL3P9+2OT/gNvm/4Pe
+ 6f+I4+3/j+jx/5br9P+b7fb/ovD3/6bx+P+r8/r/sPP6/7P0+v+19Pr/uPb7/736/f+68/pr////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wCa3OxgmuPz/43X
+ 6P+F0uP/gtHi/3vN3v90ydv/d87d/3/Z5P+A3Of/hOHr/4rl7/+R6fL/l+v1/53u9/+j8Pf/qfH5/6zz
+ +v+w8/r/tPT6/7b0+v++/f//uvX7rcz//wX///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AFRXVDBIS0CsSEtFIFBHVWhQS1WYUEtRwFxLWcBcU
+ 1HEXFdhuFxTZZCMm0mY1PMxqPkfRXkxZ1E1icdM0anvTHXaJ2A3b/9sHzP8zBf//AAL///8A////AP//
+ /wD///8A////AP///wD///8A////AJnd7YCZ5PX/hs/k/3jD2/95yNz/ecrd/3PI2/950d//f9rl/4Hd
+ 5/+G4uz/jObw/5Pq9P+Z7Pb/oO/3/6Xx+P+q8/r/rvP6/7L0+v+z9Pr/uvn+/7n2+uK28Pgj////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AID//wKn1fc9msXyjSUo
+ 16wTD9TaFBPS9BMR0v4UEdX/FRLZ/xQS2/8VE93/FhTe/xcU4P8YFuD/FRXS/xcXzP8YGcz/GBrJ/xsc
+ y/YeIMvtJinN4Cku0MwpLc61LDPOnDU6zog6Q85zR1LSWl5q0Dxre84fgJXVDNX/qgb//wADm+Duppbh
+ 8v+CzOD/dcHZ/2+91v9tvdT/b8PW/3vU4f9/2ub/gt7p/4fj7f+M5/H/lev0/5vu9v+h8Pf/pvH5/6vz
+ +v+v8/r/svT6/7b1+/+6+P38uvb8Vf///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wCezfNCn8n0uZ/M9fik0fz/RFPl/w4L0/8SENH/Eg/Q/xIQzv8REM//EhDP/xMR
+ 0f8TEdP/FBLS/xMSzv8QEMP/EBDE/xERx/8SEsj/EhLK/xISzP8SEc3/ERDP/xAQ0P8QEdD/ERDP/wwN
+ zP8QEsb/EBHC+BMXwO0cH8DdHSG/wyYqwKOHxObhk93s/37I3v9zwNf/bbzU/2i50f9nutL/csrb/3nT
+ 4v+B3un/ieTu/4/p8v+X6/X/ne73/6Pw+P+n8vn/rPP6/7Dz+v+z9Pr/vf3//7bz+pn///8B////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wCWw/ARncv2kp/L9/eiz/v/ncn1/6LP
+ 9P9rhub/DQvK/w4MxP8ODL//DQy8/w0MvP8NDLz/DQ29/w4Nvv8ODb7/DQ29/w4OwP8ODsL/Dw/F/xAP
+ x/8QEMj/EBDI/w0NyP8LC8j/CwvJ/wwNyP8UE8n/QD/T/wYGw/8HB8L/BQW+/wMDvP8CAbz/DhHB/366
+ 5f+O2uj/esXb/3G/1v9su9P/ZrjR/2i70/9wx9r/csrd/3jQ4v+A2en/iuLv/5To8/+d7fb/pPD4/6nx
+ +f+u8/r/sfP6/7f5//+29PrVter0GP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8Aj7TwIpzJ9MGj0Pz/nsr1/53I8/+dyfP/l8Xv/2uQ2/8PEbj/Cgmy/woKsf8LCrL/Cgqz/woK
+ s/8LCrb/DQy6/xMRvv8WFcH/GhrC/yYnxv8nJ8j/KinK/yorzP81NdD/VVXZ/2dn3/9OTtv/KCjS/yop
+ 0P9oZ93/AADB/wcHv/8FBrz/BQW5/wMBt/8YIL7/iMvn/4nV5f91wdn/b7zV/2q60v9lt8//ab7U/3HI
+ 2/9yy9//eNDj/33U5v+D1+r/itvs/5Hf7v+X4vD/neXy/6Lm8/+l6PX/qen1+Krm8Uj///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AIev7yCaxPXRo9D9/53I9P+eyfP/msbx/4Wz
+ 5P9yotr/Y47S/xUatP8IB6//CQmv/wkKsP8JCrD/Cgqz/w0Mtf8UFK7/IiKl/ygpnP8iJZb/HiCQ/x4g
+ jv8fIo7/ICKQ/xwekP8XGY//HB2X/xgZof8uL6//Pj2//1BPz/83OM7/ERHF/woKwP8FBLv/AQC3/yQ0
+ w/+N0+j/htHi/3O/1/9tu9P/Z7jQ/2S2z/9swdX/cMjb/3LL3/950eT/ftXo/4XZ6/+L2+z/kN7t/5Tf
+ 7/+Z3+//nODw/6Tp9f2p5+2C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCHpfARmMPzwqPQ/f+dyPP/ncnz/5TA7f94p9z/bZzW/26d1/9qmNX/Fx60/wYFrf8ICK3/CAmx/wwM
+ uP8QEaX/EBKL/wwPfP8IC3f/BQl1/wQIdf8EB3T/Awd1/wMGc/8CBXL/AgZv/wIFa/8AA2f/AAJk/wAA
+ Yf8AAGH/BARo/xYWev8jI4z/EhOY/wMCo/8AAK//NEvI/5Db6f+Czd//cL3V/2u50f9mts//Y7bP/23D
+ 1v9xyNv/dMzf/3rS5P+A1un/htnr/43d7f+S3u7/lt/v/5rg8P+h5vP/jcDw6Ds/7j0AAL8E////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AJW+85ii0P3/ncn0/57J9P+Rvuz/c6La/22c
+ 1v9tndb/bp7W/2iW1P8WHLH/BgSq/wgItf8ODbj/EROR/w4Ref8MD3b/CQx1/wgLdv8GCXX/BQh0/wQH
+ df8DB3T/AgVy/wIEcP8BA23/AANr/wABZ/8AAGP/AABf/wAAW/8AAFf/AABS/wAAUP8AAFP/AABY/wAA
+ X/9DY6j/kN7r/3zI3P9vu9P/abjQ/2S1zf9kt8//bsXX/3DJ3P91zuD/e9Pl/4LX6v+I2uz/jt3t/5Pf
+ 7/+Y4O//nePw/5bU8f86RO/9IRrt8yMg7sIkIOx5IyPoLAAA/wH///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCPs/Fbnsr5/Z7K9f+eyfT/kr/t/3Ki2v9tnNf/bZ3W/22d1v9vn9b/YYvQ/xEVrf8GBbP/Dw67/xQW
+ i/8PEnX/DRB2/woOdP8IC3P/Bgpy/wUIcf8DBnD/AgVw/wEEcP8AAm//AAJt/wACa/8AAGf/AABk/wAA
+ YP8AAF3/AABZ/wAAV/8AAFT/AABS/wAAUv8AAFP/AABU/1iEr/+O3Or/eMPZ/2260f9nt87/Y7PM/2a6
+ z/9vxdf/ccnc/3fO4f991Ob/hNjq/4ra7P+Q3u3/leDv/5nh8P+f5fD/VXLi/xoW3/8iHun/JCDz/yUh
+ 9P8kH+3zJB7tuCUg72EjI+gW////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AgJvtHJjC9d+hzvr/nsn0/5jE8P92pd3/bZzX/22d
+ 1v9tndb/bZ3V/3Ch1v9Uecn/CQmv/wkHvf8ZGaD/ERN1/w8Rdf8MD3P/Cgxx/wcKb/8FCG//BAdu/wIG
+ bv8BBG3/AANs/wACbP8AAWr/AABn/wAAZP8AAGD/AABd/wAAWf8AAFb/AABU/wAAUv8AAFH/AABR/wAA
+ U/8BAVj/aJ3B/4vY5v91wdf/a7nQ/2a1zf9is8z/aL3R/3DG2P9zy93/eM/i/3/V5/+F2Or/jNzs/5Le
+ 7v+V3+7/nubx/3qr6v8dHdT/GBbT/xoZ1P8cG9r/Hx3h/yMf6v8lIfT/JSDx/yMg7t8iHOyQUWDwRcH/
+ 5R3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCPs/GUotD+/53J9P+dyPP/fq3h/2yc1/9tndf/bZ3W/22d1f9tnNX/caHW/ztUvv8EA7T/DAu8/x0e
+ jP8QEnP/DhBz/wwOcf8JDG//Bwlt/wUIbP8DBmv/AQVr/wADav8AAWn/AABm/wAAZf8AAGP/AABg/wAA
+ XP8AAFr/AABW/wAAU/8AAFH/AABQ/wAAT/8AAFD/AABS/wkNX/93ttD/htPj/3G+1f9quND/ZbXM/2Kz
+ zP9qv9P/cMbY/3TL3f960OP/gdXo/4fZ6/+N3Oz/k97u/5jh8P+W2e3/NULR/xUT0v8aGNf/GhnW/xoZ
+ 1P8ZGNP/GhnV/x0b2/8gHuT/JCDv/yQg9f8sKu76f5333bLl+Yu25/kq////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8Ad5nuLZnC9PKfzPf/nsn0/4266v9undf/bZ3X/22d
+ 1v9tndb/bZzU/26d1f9pltL/GSKu/wQCtP8RELv/FhmD/xAScv8OD3H/Cw1u/wgLa/8HCWv/BQdp/wIF
+ aP8AA2b/AAJm/wABZf8AAGP/AABi/wAAYP8AAF3/AABY/wAAVf8AAFP/AABP/wAATf8AAEz/AABM/wAA
+ Tv8AAE//Ex1o/4LJ3f+Cz+D/b7zT/2i40P9jtMz/Y7XN/23C1f9xx9n/dsze/3zS5P+D1un/idnr/47c
+ 7P+V3u7/nefz/1qCvf8ICYP/Dg+U/xESqf8WFsH/GRjQ/xoZ1v8aGdb/GRjU/xkY1P8bGtj/Hx3h/yEc
+ 6/8xMvP/iKn9/6nY+uup2fibter6MP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCKsPGUo8/9/53I9P+bx/L/d6bd/22c1v9tndb/bZ3W/22d1f9tnNT/caHW/0NfwP8DA6H/BQWw/xAP
+ uv8hIon/DhFw/w0Qb/8LDWz/CApq/wYIaP8FB2j/AgVl/wADZP8AAWP/AABi/wAAX/8AAF7/AABa/wAA
+ WP8AAFX/AABR/wAAT/8AAEv/AABK/wAASf8AAEr/AABM/wAATP8hMXT/h9Di/33L3v9tu9P/aLfP/2Oz
+ zP9luM7/b8XW/3LJ2/94zuD/f9Tm/4XX6f+L2uv/kN3t/5ji8P+JyeP/GiWK/wYHev8HCnr/Bgp6/wcL
+ f/8LDY3/EBGi/xUVvP8ZGND/GhnW/xoZ1v8ZGdT/GhnW/xsZ3v8rK+r/d5L3/6jV//+m1Pruqtj5orLk
+ +jj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AYoDrGpW+8+Shzfj/nsn0/4266v9tndj/bZ3X/22d
+ 1v9tndX/bZzU/3Cg1f9eh83/EBWn/wMCn/8FBaf/Cwm4/y0unf8QEm7/DQ9u/woNa/8ICmj/Bghl/wQG
+ Zf8CBGP/AAJh/wAAX/8AAF7/AABb/wAAWf8AAFj/AABU/wAAUf8AAE7/AABL/wAASf8AAEb/AABH/wAA
+ R/8AAEn/AABH/y9Igv+K2Of/esfb/2u50f9nt8//Y7TM/2i70P9xxtf/dMnb/3rP4f+B1Of/htjq/4zb
+ 7P+S3e7/m+by/01vsf8EBHj/Bwl7/wYIe/8FCHr/Bgl7/wYJef8HCnn/CQt9/wwOi/8REqL/Fhe+/xoY
+ 0f8aGdb/GRnV/xkX1v8fHN3/V2nt/5a9+v+q2P//pdT68qnY+aOz5voy////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wCAoe5cnsn6/57J9P+dyPP/fKvg/2yc1/9tndb/bZ3V/22c1f9vn9X/Z5PR/x8rrv8CAZ//BQWe/wUF
+ n/8EBK3/Kyq2/x0eev8LDWv/Cg1q/wgKaP8GCGX/BAZi/wIEYP8AAl7/AABc/wAAWv8AAFj/AABV/wAA
+ VP8AAFD/AABN/wAASf8AAEf/AABE/wAAQv8AAEP/AABE/wAARf8AAET/QGKT/4vb6f92w9j/a7nR/2a2
+ zv9jtMz/bL/T/3PH2f93y97/fNHj/4PW6P+J2ev/jtzs/5Xh8P+GxeD/Fh6F/wUHeP8FCHn/BAd4/wQH
+ ef8FB3n/BQh6/wYKev8HCnv/CAx6/woNev8MD4D/EBKP/xUWqv8ZGMb/GhnU/xkY1v8XFNX/LjLf/2R7
+ 7v+Tufn/ptT//6nY+u6u4Pibv/r6MP//AAH///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AIes8aij0Pz/nsn0/5XC7/9xoNr/bZ3X/22d
+ 1v9tnNX/b5/V/2mW0f8oN7H/AgCe/wUFnv8FBZ3/BQWc/wMDof8REbX/Ozul/wwOav8JDGn/CApn/wYI
+ Y/8DBWD/AgRe/wACXf8AAFr/AABY/wAAVP8AAFP/AABQ/wAATf8AAEr/AABG/wAAQ/8AAEH/AABA/wAA
+ P/8AAED/AABD/wAARv9Vg6n/iNjn/3PB1v9quND/ZrbN/2W2zv9vw9X/c8jZ/3jN3/9+0uT/hdbo/4va
+ 6/+Q3e3/meXy/05zsf8CA3P/BQh2/wQHdv8EB3X/BAd3/wQHd/8FCHj/Bgl4/wgKef8IC3r/Cw59/wwP
+ ff8OEXz/DxJ9/xIVhP8VF5n/Fxi1/xoZzv8YFtb/FxXX/ygq3v9LVuz/aoH2/4Oi/P+Rtvnul773mpnE
+ 9x7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wBAUN8Qkrry2qHO+v+eyfT/irjo/22c1v9tndb/bZ3W/3Gh1v9kjtD/IzCw/wIBnv8FBZ3/BQSb/wUE
+ m/8EBJr/BASa/wIBpP8pKbz/RUac/wgKZv8GCGX/Bghi/wQGYP8CBF3/AQJb/wAAWf8AAFX/AABT/wAA
+ UP8AAE7/AABL/wAASP8AAET/AABB/wAAPv8AADz/AAA8/wAAPf8AAD//AgNG/2efvP+D0uL/b73T/2i3
+ z/9ktcz/Z7jO/3HF1v90yNr/ec3g/4DS5f+G1+n/jNrr/5Lf7v+N0eb/HCiD/wIEcP8EBnL/AwVx/wMG
+ c/8CBnP/Awd0/wQHdf8GCHX/Bwt3/wkMeP8KDnr/DA97/w4RfP8PE33/ERR+/xIVfv8SFn//FBeM/xYY
+ pP8YGcH/GBfS/xYU2P8bGN7/IyDp/yoo8P8wMfX/KSfuzCQe7VUAAKoD////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AGuG6TmVvvT7n8v1/53J9P9/ruL/bJzW/26f
+ 1v9wodb/VXnJ/xggrP8BAaD/BQWd/wUEnP8FBJr/BQOZ/wUEmv8EBJn/BASb/wIBqv88O8L/UlSe/wsN
+ Zv8DBWD/AwZf/wIEXf8BAlr/AAFY/wAAVf8AAFL/AABP/wAAS/8AAEj/AABF/wAAQf8AAD7/AAA7/wAA
+ Ov8AADr/AAA6/wAAOv8ME0//d7vQ/33L3f9ruND/ZrXN/2Szyv9ous7/csbW/3XI2v97zuD/gdPl/4fW
+ 6P+N2uv/l+Tx/2mbxf8EBmz/BAZt/wIFbf8CBW7/AgVv/wIFb/8DBnD/BAdy/wUJc/8IC3T/CQx2/wsN
+ d/8MD3n/DhF7/w8Te/8QE3z/ERR+/xEVfv8SFX7/EhV8/xIVgf8UFpT/Fxe3/xkY0/8aGdf/HRze/yIe
+ 6v8lIPT/JCDu/yQg7rIlH+wp////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8Ab4jrWp3J+/+eyvT/nMjz/3io3f9wotj/ZZDS/zhPvf8KDKb/AwKg/wUFnv8FBZv/BQSa/wUE
+ mP8FBJj/BQSX/wQDmP8EBJj/BASd/wICrP83N8P/Y2Ss/xgabP8AAVz/AgRd/wEDW/8AAlf/AABV/wAA
+ Uv8AAE7/AABL/wAAR/8AAET/AABA/wAAPv8AADn/AAA4/wAAOP8AADn/AAA2/x8vYv9+yNn/dsPV/2e1
+ y/9kscn/YbDJ/2m7zv9xxNX/dsja/3vO3/+B0uP/iNXn/43a6/+U3u3/OVSX/wAAZP8CBWn/AARo/wED
+ af8BBGr/AQRr/wIFbP8EB27/Bghv/wgKcf8JC3L/Cg10/wwPdv8OEXj/DhF4/xASef8QEnr/EBN7/xEU
+ fP8QE33/ERN8/xATev8QEnz/EhSZ/xkYyv8aGdT/GxrX/yEf5/8kIO//JSH1/yUh8OMkIepV////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wBpg+x5p9b+/6DM9f+Svu7/YIjT/zxV
+ w/8VHLH/AwKm/wUEo/8FBaD/BQWd/wUEmv8FBJf/BASW/wQDlv8EA5b/BAOX/wQDmP8EBJr/BASe/wAA
+ qv8lJMD/Xl+9/zc5g/8GB1z/AAJY/wACWf8AAVT/AABS/wAATv8AAEv/AABH/wAAQ/8AAD//AAA8/wAA
+ Of8AADb/AAA2/wAAN/8AADT/OVmB/4DN2v9tuc3/Y6/H/2Ctxf9frcT/abrM/27A0v90xtf/esvc/4HQ
+ 4f+H1OX/j9vq/4LC2/8QGG7/AABh/wACY/8AAWP/AAFk/wACZf8BA2b/AQRn/wQGaf8FB2z/Bglt/wgK
+ b/8JDHH/Cw5y/wwPdP8NEHT/DhF2/w8ReP8PEXf/DxF4/w4Ref8OEXn/DRB5/w0Qev8OEXf/EhOR/xkZ
+ 0P8aGdT/GxrW/yIf6P8kIO3/JSHy/yQg8fUkHuxd////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////ADtD4phccO7/RlXg/y020v8OEbf/BgSu/wUEqv8GB6b/BQWj/wUFn/8FBJr/BQSY/wQE
+ l/8EA5X/BAOV/wQClP8EA5X/BAOW/wQEmP8EBJr/BQSd/wIBpv8IB7f/NzbD/0JCpf8dHnD/AQNW/wAA
+ Uf8AAFH/AABP/wAASv8AAEf/AABD/wAAP/8AADv/AAA4/wAANv8AADX/AAA2/wECOf9ZjKf/eMPT/2Wv
+ xP9fqsD/XKi//1yrwf9nuMn/a7zO/3LC0/94x9j/f83d/4XR4f+R3ev/X423/wEBW/8AAV3/AABd/wAA
+ Xf8AAF7/AABf/wAAYf8AAmP/AgRl/wMGZ/8FB2j/Bglp/wcKbP8JC27/Cgxu/wsOcP8MDnL/DA5y/wwP
+ dP8MDnX/Cw51/woOdv8LDnb/Cw53/wwPeP8NEHj/FRau/xoZ1v8ZGNP/HRva/yQg7P8kIO3/JSHx/yUg
+ 8PQiH+pK////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AFhPcrxIP3/8PC9P/CwnH/wkJ
+ s/8ICK7/Bweq/wYGpP8FBaL/BQWe/wUEmv8EA5f/BASV/wQDlP8DA5P/AwOT/wMDk/8EA5T/BAOW/wQE
+ mP8EBJn/BQSe/wUEo/8BAK3/Dg2+/ycnwP8pKqL/FhZ4/wkJW/8AAE3/AABG/wAARv8AAEL/AAA//wAA
+ PP8AADn/AAA3/wAANv8AADP/FSBQ/3Gzxf9vuMj/X6a8/1mjuf9Xorj/W6i8/2SzxP9pt8n/br3O/3bE
+ 1P99ydn/g83d/4vT4v8xSoj/AABU/wAAWP8AAFj/AABY/wAAWf8AAFr/AABb/wABXv8AAmD/AQNh/wMF
+ ZP8EBmX/BQdn/wYJaf8ICmv/CAtr/wkMbf8JDG7/CQtu/wgLb/8IC3D/CAty/wgLcv8JC3T/Cg11/woN
+ dP8RE5P/GhnU/xoZ1P8aGdX/IR7o/yQg7v8kIO3/JSHz/yMg7NogIOoY////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wAYFdvBFhTe/xIR0/8PDcf/CQmw/wgIrf8HB6j/Bgak/wUFof8FBJv/BQOY/wQD
+ lv8EA5T/AwOS/wMDkf8DA5H/AwOR/wMDkv8DApT/BAOW/wQDmP8EA5z/BQSe/wUEov8EA6f/AwOx/wsK
+ v/8ZGMX/HRy6/xoanv8QD37/BQVe/wICS/8AAED/AAA5/wAAN/8AADf/AAA3/wAAM/8+YIP/d7/N/2Wt
+ vv9Zobb/Vp+0/1Sds/9aprn/Ya+//2SyxP9rucn/cr7O/3rE1P+Cy9r/ebfN/w0TYv8AAFL/AABU/wAA
+ U/8AAFT/AABV/wAAV/8AAFj/AABZ/wAAW/8AAVz/AAJf/wIEYf8CBWL/AwZk/wQGZf8FB2f/Bgho/wUI
+ av8GCGn/Bghq/wUIbP8FCG3/Bglv/wcKcf8IC3L/Cgxy/w8Rkf8aGdX/GhnU/xoZ1P8hHuX/JCDu/yQg
+ 7f8kIO3/JSH2/yQg7If///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ABgV3MIWE93/EhDS/w8O
+ x/8JCbH/CAes/wYHqP8GBqP/BQWf/wUEmv8EA5f/BAOU/wMDk/8DA5D/AwOQ/wMDkP8DA5D/AwOS/wMD
+ kv8EA5T/BAOW/wQDmv8FBJ3/BQSf/wUEof8FBaT/BQWo/wUFr/8FBbf/CwvC/xAOxf8TEsD/DQ2p/wgI
+ kf8ICHr/BgZj/wMDTf8AAD7/Ex1P/3Gwvv91vcj/Yai5/1igtP9VnLH/Upuw/1mlt/9frLv/Y7DA/2m1
+ xf9vusr/dsDQ/4PM2f9biq7/AQFR/wAAUf8AAFH/AABR/wAAUv8AAFL/AABT/wAAVP8AAFX/AABX/wAA
+ WP8AAFr/AAFc/wACXv8BA1//AgRh/wIFYv8CBWP/AwVl/wIFZf8CBGb/AgVo/wMGa/8EBmz/BQht/wcJ
+ bv8JDHL/FRWy/xoZ1v8aGdP/GxnV/yIf6f8kIO3/JCDt/yQg7f8kIPH/JCDt5Ccn6xr///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8AGBXawhYT3f8SENL/Dg3G/wkJsP8IB6z/Bgen/wUFo/8FBZ7/BQSa/wQD
+ l/8DA5T/AwOR/wMDkP8DA4//AwOP/wMDjv8DA4//AwOQ/wMCkv8DA5T/BAOX/wQDmv8FBJz/BQSf/wUE
+ of8FBKX/BQWm/wYGqf8GBqz/Bwav/wcHsf8ICbX/Cgu5/wsLu/8MDLn/DAuy/wgHoP8ZIaD/QmO1/017
+ r/9TjbD/Vpqu/1aerv9XorL/Xau4/2Ctu/9jr77/aLPD/2+5yP92vs7/gMjV/zhUif8AAEv/AABQ/wAA
+ T/8AAE//AABP/wAAUP8AAFH/AABR/wAAUv8AAFT/AABW/wAAV/8AAFn/AABa/wABW/8AAV3/AAFe/wAB
+ X/8AAWH/AAJi/wACYv8AAmT/AQNn/wMFaf8DBmn/Bglt/xASoP8aGdX/GhnU/xoZ0/8eHN7/JCDu/yQg
+ 7f8kIO3/JCDt/yQg7f8lIfP/JiDsX////wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAYFdrCFRPc/xIQ
+ 0v8ODMX/CQmv/wgHqv8GB6f/BQWh/wUFnf8FBJn/BASV/wMDk/8DA5H/AwOP/wMDjv8DA47/AwON/wMC
+ jv8CAo//AgKQ/wMDkv8DApX/AwOW/wQDmf8EA5z/BQSf/wUEof8FBaT/BQWm/wYGqP8GB6v/Bwes/wgI
+ r/8ICLD/CAmy/woKtP8LC7b/DAu6/wsJuv8JB7f/DAq5/xIVtf8eLa//K0et/zxoqf9QjrL/XaW3/2ay
+ vP9uu8X/c73J/3nBz/96vc3/HChr/wAATf8AAE//AABO/wAATv8AAE//AABO/wAAT/8AAE//AABP/wAA
+ Uv8AAFP/AABV/wAAVf8AAFf/AABY/wAAWv8AAFz/AABd/wAAXv8AAF7/AABd/wAAYf8AAGL/AQNi/wUH
+ c/8SE63/GhnV/xoZ1f8ZGdP/HRvc/yMg7P8kIO3/JCDt/yQg7f8kIO3/JCDt/yUh9f8jIO2o////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////ABgV2sEWE93/EhDR/w4MxP8JCK//CAeq/wYHpv8FBaH/BQWd/wUE
+ mf8EBJT/AwOR/wMDkf8DA4//AwOO/wMCjf8DAo3/AwKO/wIDjv8DAo//AwKR/wMCkv8DApX/BAOY/wQD
+ mf8EA5z/BASe/wUEof8FBaP/BQWl/wYGp/8GB6n/Bger/wcHrP8ICK7/CAmw/woKtv8MC73/DQu//w0N
+ v/8NDLz/DQy8/wsJvP8MCb3/Dgy//xETvP8eK7b/Lke1/0Nstv9bkr7/dLfM/3Oxwv8KEFj/AABK/wAA
+ TP8AAE3/AABN/wAATf8AAE3/AABN/wsLV/8UFF//AABP/wAAUf8AAFL/AABT/wAAU/8AAFX/AABW/wAA
+ V/8AAFf/AABX/wQEXf9GRoj/CQlr/xUWfP8OD5z/FxfG/xsZ1/8aGdP/GhnV/x8d4P8kIO3/JCDt/yQg
+ 7f8kIO3/JCDt/yQg7f8kIO3/JSDx/yMg7d8cHPES////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AFxTbsBYT
+ 3f8SD9H/Dg3F/wkIr/8HB6v/Bgem/wUFov8FBJz/BASY/wQDlf8DA5H/AwOQ/wMDj/8DAo3/AwKL/wMD
+ jP8DAoz/AgKM/wMCjv8CApD/AwKQ/wMCkv8DApT/AwKW/wQDmf8EA5z/BQSc/wUEoP8FBKL/BQWk/wYG
+ pf8GB6f/Bgeo/wcHqv8KCLf/DAvC/w0LxP8ODMb/Dw3G/xAOyP8QDsf/Dw3C/w4Ovv8ODrz/Dg7A/w4N
+ xP8ODMT/Dw7E/xUYxf8lMML/MELD/w4Qmv8JCYX/BQVw/wUFYP8IB1n/CQlW/wsLVP8PD1b/Ojp2/yAg
+ Zv8AAE3/BwdW/wkJWf8WFmL/Hh5o/yYmbf8hIW//GRlx/ygohv9CQp//RUSu/0dGxf9OTsv/OjrY/xsa
+ 1v8aGdX/GxrW/x4c3v8iH+n/JCDu/yQg7f8kIO3/Ix/t/yMf7f8kIO3/JCDt/yQg7f8kIO7/JCDt+iEd
+ 7j3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wAXFNubFhTd/xIR0f8ODcb/CQmw/wgHq/8GBqX/BgWh/wUF
+ nP8FBJj/BAOU/wMDkf8DA4//AwON/wMCjf8DAov/AwKL/wICi/8DAov/AgKL/wICjf8DAo//AwKR/wMC
+ k/8DApX/AwOW/wMDmf8EA5r/BASb/wUEnf8FBKD/BQWh/wUGpP8GBqT/Bwes/woIvP8LCbz/DAq//wwL
+ wf8NDMP/DgzF/xANyP8RD8z/EQ/M/w8Qxv8OD8D/Dw/A/xAQwv8QEMX/ERHH/xAPyv8QDsz/FBPQ/xUV
+ 0P8UFMz/FxfF/x8ewP8jIrr/JiW3/yYmt/8cHbH/Oju2/0JCtP8/QLv/QkLB/0lJzP9NTdT/XV3b/1RU
+ 2f9FRdf/NzbX/yEg1/8dHNf/FxbU/x4e1/8WFtX/HBrb/yAd4/8jIOv/JSDt/yQg7v8kIO3/JCDt/yUh
+ 7f8uKu7/NjLu/zMw7/8iHe3/Ih3t/yId7f8kH/T/IR3sa////wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ABgU
+ 234XFOD/EhDS/w8NyP8JCrH/Bwer/wYHpv8FBaH/BQSd/wUDmP8EBJX/AwOR/wMDj/8DAo3/AwKM/wMC
+ i/8DAov/AwKK/wMCi/8CAoz/AgKN/wMCjf8CAo//AwKR/wMCk/8DApT/AwKW/wQDmP8EA5j/BAOa/wUD
+ nv8FBJ//BQWf/wUFoP8IB67/CQe2/wkIuf8KCbr/Cwq7/wwLwP8NC8H/DgzE/w8NyP8QDsv/EhDP/xIR
+ 0f8REcv/ERDG/xARxP8REcX/EhLH/xMTyf8TE8v/FBTO/xUVz/8VFdH/FBTS/xQU0/8UFNT/FBTV/xUW
+ 1v8ZGdb/Hh7Y/xkZ1/8ZGdb/FRXU/xIS0/8QENL/EhHS/xQT0v8VFdL/GRjU/xoZ1/8dG93/IB3l/yIf
+ 6v8kIO3/JSHu/yYi7v8lIe7/JSHt/yQg7f8mIu3/My/v/zk17/89OO//RUPv/zY47/80Nu//NDbv/y4u
+ 9v8mJO6V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AGBXaYRYU3f8TENH/Dw3K/woKtP8ICKv/Bwam/wYG
+ ov8FBZz/BAOY/wQDlf8DA5H/AwOO/wMCjf8DAoz/AwKL/wMCi/8DAon/AwKJ/wICiv8CAoz/AgKN/wIC
+ jv8CAo//AgKR/wMCk/8DApT/AwOV/wMDl/8EA5j/BAOY/wQDmv8FBJz/BQWc/wcGq/8IB7L/CAe0/wkI
+ t/8KCLn/Cwm6/wwLvv8NC8D/DgzE/w8NyP8RD8z/EhDR/xMR1P8UEtb/FRPV/xQS0v8TEs3/ExPM/xQT
+ y/8UE8z/FRTO/xUVz/8VFc//FhXQ/xYV0P8WFtH/FhbR/xYW0f8WF9H/FxfR/xcX0v8YGNL/GBjT/xkY
+ 1P8aGdf/HBrc/x4c4f8hHef/Ix/r/yQg7f8kIO7/JCDt/yQg7f8nIu//JyPu/yYi7v8lIe7/KCTu/zIt
+ 7v82Me//TE3w/3iK9P+Ztff/msD3/5fA9/+Xv/f/kbX8/4ms9suOxv8J////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wAaFtw6FhPX+hMR1P8QDs7/Cwq3/wgIq/8HB6j/Bgaj/wUFnf8FBJn/BAOV/wMDkv8DAo//AwON/wMC
+ jP8DAov/AgKJ/wICiv8DAYr/AgKK/wICiv8CAoz/AgKM/wMCjv8CAo//AgKQ/wMCk/8DApX/AwKV/wMD
+ lf8EA5b/BAOX/wUEmP8FBJn/BgWm/wcGr/8IBrD/CAey/wkItf8KCLf/Cwq6/wsKvv8NC8L/DgzF/xAO
+ yf8RD87/ExHS/xQS1v8WE9r/FxTe/xgV3/8YFt7/GRbe/xgX3P8YFtn/GBfY/xgX1/8YFtb/GBfW/xgX
+ 1v8YGNf/GBjY/xoZ2f8bGtz/HRrf/x4c4v8gHOX/IB3o/yMf6/8jH+3/Ix/t/yMf7f8jH+3/Ix/s/yMg
+ 7f8jIO3/JSHu/ykk7/8oI+//JiLv/ykk7v8wK+7/QD7w/3WG9P+jxfj/stj5/7LX+f+kz/j/ocz4/6HN
+ +P+l0fz/o8/45pXB9h3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////ABIS2xwWFNnlFBLX/xEPzv8NDL3/CAis/wcH
+ qP8GBqP/BQWf/wUEmf8EBJb/BAOS/wMDj/8DAo7/AwKL/wMCi/8DAon/AwKJ/wICif8CAon/AgKJ/wIC
+ i/8CAYz/AwKN/wICjv8DApD/AwOQ/wMCkv8DApL/AwKU/wMDlP8DA5T/BAOV/wUElv8FBJ3/BgWr/wcF
+ rP8HBq//CAex/wkItP8KCLf/Cwm6/wwKvv8NDMT/Dw3I/xAOzP8SEND/FBHV/xUS1/8VEtv/FRLe/xcT
+ 4f8ZFOT/Ghbm/xsY5/8dGun/Hhrp/x4b6f8fG+r/Hxzq/x8c6v8gHev/IR3r/yEd7P8iHu3/Ih7t/yIe
+ 7f8iHu3/Ix/s/yMf7P8jH+z/Ix/t/yMg7P8jH+3/Ix/t/yMg7f8oI+//KSXw/ygk7/8oJO//MCrv/1Vb
+ 8v+XtPf/stf5/6/V+f+w1Pn/sNT5/6PN+P+gy/j/oMv4/6LN+/+fyvjvm8H5Kf///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8AAAD/AhcU2L8WEtr/EhDQ/w4Nwv8JCa7/CAep/wYHpf8FBqH/BQSa/wMClf8DApL/AgKQ/wMC
+ jv8DAoz/AwKL/wMCif8DAon/AgKJ/wMCiv8CAor/AgKL/wIBi/8CAYz/AgKM/wICjv8CAo//AwKP/wMC
+ kP8DApH/AwKR/wMDkf8DA5P/BAOU/wQDlf8FBaT/BgWq/wYGrP8HBq7/CAey/wkItf8KCbn/Cwq8/w0L
+ wf8ODMb/Dw3L/xANz/8OC9L/EA3W/xoZ3P8iI+D/Ky7k/y0x5v8nKOf/IR/n/xkV6P8aFen/HRrq/x8b
+ 6v8fHOr/IBzr/yAd6/8gHev/IR3r/yEd6/8hHuv/Ih7s/yIe7P8jH+z/Ix/s/yMf7f8jH+3/Ix/t/yMf
+ 7f8kIO3/JyPv/ywn8f8qJvD/KiTw/zEs8P9pc/T/q875/7PY+f+w1Pn/sdT5/7HV+f+y1fn/o834/6DL
+ +P+gy/j/os36/5/J+PKYw/ov////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AFxPYhBYT3v8TENH/EA3J/woJ
+ sv8HBqn/BAOk/wEAn/8DApv/BgWY/wUFlf8EBJH/AACN/wAAi/8AAIr/AgCJ/wICiv8CAor/AwKK/wIC
+ if8CAor/AgKL/wICi/8CAYv/AgKM/wIBjv8CAY7/AwKO/wMCj/8DA5D/AwKR/wMCkf8DA5H/BAOS/wQD
+ mv8GBaj/BgWp/wcGrP8HBq//CAez/wkIuP8LCbz/DArB/wwKxP8KB8j/GBnQ/z9L3v9lfuj/f6Hv/4yy
+ 8v+VvfX/lr/1/4619f+DpvT/aoLx/0NN7f8hH+r/Gxfq/x8c6/8gHOv/IBzr/yAd6/8hHev/IR3r/yEe
+ 6/8iHuz/Ih/s/yIf7P8iH+z/Ix/t/yMf7P8jH+z/Ix/s/yUh7f8sJ/H/LSjy/ysn8f8wLPH/d4X1/7XW
+ +v+12Pr/s9X6/7PW+f+z1vn/s9b5/7PV+f+jzfj/oMv4/6DL+P+izfv/oMr58Za89C7///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wAXE9lDFhPY+xMR0/8PDcz/BwW4/w0Prf8hLbL/OE+6/0dlv/9RdMP/UnbD/09x
+ v/9DYLb/M0mr/xsmm/8JCo7/AACI/wEAiP8DAor/AgGK/wIBiv8CAov/AgKL/wIBi/8CAoz/AgKN/wIC
+ jf8CAo7/AgKN/wMCj/8DAo//AwOQ/wMDkP8DA5H/AwOU/wQEov8GBan/BgWr/wcGsP8HB7P/CQi2/woJ
+ vP8IBr//EBDG/0lZ2f+Fqez/nsvz/6HO9f+gzfX/n8v1/5/L9v+fyvb/oMz3/6HO9/+j0Pf/n8v4/4Cg
+ 9P8/R+7/HBjr/x8c6/8gHOv/IR3r/yEd6/8hHuz/IR7s/yIe7P8iHuz/Ih/s/yIf7P8jH+3/Ix/s/yMf
+ 7f8jH+3/KSXw/y8q8/8tKPL/MCry/3F89f+72/r/udn6/7bY+v+21/r/tdf6/7XX+f+21/n/stX5/6HL
+ +P+gy/j/oMv4/6LO+/+eyffrirbwI////wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AB4P4REWFNfZEQ3X/xcX
+ 0P9CVdH/XILP/22c1f9woNX/cKHW/3Cg1f9woNT/cKHT/3Ch0/9woNL/bJvP/1qBw/84T63/DxWS/wAA
+ h/8CAIr/AgKL/wIBi/8CAov/AgKM/wICi/8CAo3/AgGM/wICjv8DAo3/AwKM/wMCjf8DAo//AwOP/wMD
+ kP8EA5L/BAOY/wUFp/8GBqv/Bwav/wgHsv8IB7b/BgO5/yAlx/91lOT/n8zy/5/M8/+cyPP/nMj0/53I
+ 9P+dyfX/ncn1/57J9v+eyvb/nsr3/5/K9/+fyvf/o8/4/5vF9/9WZvD/Hhnq/yAc6/8hHev/IR3r/yIe
+ 7P8iHuz/Ih7s/yIf7P8jH+z/Ix/s/yMf7f8jH+z/Ix/s/yYi7/8wKvP/MCvz/zAq8/9aXvX/utb6/77d
+ +v+72vr/udn6/7nZ+v+42fr/uNj5/7nZ+f+y1fn/ocz4/6DL+P+gy/j/o8/8/5/J99+Apv8U////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////ABQQ2YwtM+L/fJzr/5rH8P91pdr/bZzV/22c1P9tnNT/bZzT/22c
+ 0v9tnNL/bZzR/22c0P9tnND/b5/R/3Gg0f9ijMj/Mkep/wUGjP8BAIr/AgKL/wICiv8CAYv/AgGL/wIC
+ i/8CAoz/AwGN/wMCjf8DAo3/AgKN/wMCj/8DApD/AwOP/wMDkf8DA5P/BASg/wYGrP8GBq7/CAay/wQC
+ tv8jK8T/iK7p/6DO8f+bx/H/nMfy/5zI8/+cyPT/ncj0/53J9f+dyfb/nsn2/57J9/+eyvf/n8r3/5/K
+ 9/+fyvj/oMz4/5/L+P9PXvD/HRjr/yAd6/8hHev/IR7r/yIe7P8iHuz/Ix/s/yMf7P8jH+z/Ix/t/yMf
+ 7P8kIO3/MCrz/zIs9f80L/T/Pzz0/6W6+P/F4vv/wNz7/77c+v+82/r/vNr6/7va+v+72vr/vNr6/6/T
+ +f+izPj/oMv4/6DL+P+k0P7/mcL3yGaZzAX///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AISbZPYGk
+ 8Pmj0fb/ncnz/4Ct4f9snNT/bZ3V/22c1P9tnNT/bZzT/22c0v9tnNH/bZzR/22c0P9tm9D/bZzP/2+e
+ 0P9woNH/TW67/wwRkP8AAIn/AgKL/wICi/8CAor/AgKM/wICjf8CAYz/AgKN/wICjf8CAo3/AwKO/wMC
+ j/8DApD/AwOR/wMDlP8EBJj/BQWn/wYFsP8FBLL/FBe9/4Gl5f+gzfH/m8fw/5vH8f+cx/L/nMjz/5zI
+ 9P+dyPT/ncn1/53J9v+eyfb/nsn3/57K9/+fyvf/n8r3/5/K+P+fyvj/oc34/5W99/80N+3/Hhrr/yEd
+ 6/8hHuv/Ih7s/yMe7P8jHuz/Ih/s/yMf7P8jH+3/Ix/s/ywn8f81L/b/NzH2/zky9f9veff/yeT7/8Xf
+ +//D3vv/wd37/8Dc+v+/3Pr/vtv6/73b+/++2/r/rdL5/6LM+P+hzPj/oMv4/6bS//+Tufeh////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wAAAP8FeJbtw6LQ+/+eyfP/kLzq/26e1/9tndX/bZ3V/22c
+ 1P9tnNP/bZzT/22c0v9tnNH/bZzR/22c0P9tnND/bZvP/22cz/9xodL/VXrA/wwSkv8AAIv/AgKM/wIB
+ jP8CAoz/AgKM/wIBjf8CAo3/AgKN/wICjv8DAo//AwKQ/wMDkf8DApL/AwOU/wQElv8FBJ3/BgWu/wQD
+ tP9actb/oc7w/5vH8P+bx/H/m8fy/5zH8v+cyPP/nMj0/53I9f+dyPX/nsn2/57J9v+eyvf/nsr3/5/K
+ 9/+fyvf/n8r4/5/K+P+fy/j/o9H4/2qB8v8eGuv/IR7s/yEe7P8iHuz/Ih/s/yMf7P8iH+z/Ix/t/yMf
+ 7P8pJO//NjD2/zgx9/8+OPf/RD/2/6q8+v/O5/v/yOH7/8bg+//E3/v/w976/8Hd+v/A3fr/wNz7/7/b
+ +/+r0fn/pM34/6LM+P+hzPj/pND//5W792X///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wBYZ+VjmMH4/5/K9P+bx/H/eafd/2yc1f9tndX/bZzU/22c1P9tnNP/bZzT/22c0v9tnNH/bZzR/22c
+ 0P9tm9D/bZvQ/2yb0P9xodL/T3C8/wYIj/8CAYz/AwKN/wICjP8CAoz/AgKN/wMCjv8CAo3/AwKO/wMC
+ j/8DApD/AwOS/wQDlP8DA5b/BAOY/wUEm/8DAqP/GyG8/5C56v+dyO//m8bw/5vH8f+bx/L/nMfz/5zI
+ 8/+cyPT/ncj1/53J9f+eyfb/nsn2/57K9/+eyvf/n8r3/5/K9/+fyvj/n8r4/5/K+P+gzfj/k7r3/y8w
+ 7f8gG+v/Ih7s/yIf7P8iH+z/Ih/s/yMf7P8jH+z/JiLu/zYw9v85M/j/PTf3/0E79/9eX/f/zOD7/8/l
+ /P/L4/v/yeL7/8fg+//F4Pv/xN/6/8Pe+//C3vv/v9v7/6rQ+f+mzvj/o834/6PP+/+cxfnveZnyKP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////ABsb1xN9nu3aos/5/57K8/+KuOf/bZzW/22d
+ 1f9tndX/bZzU/22c1P9tnNT/bZzS/22c0v9tnNH/bZzR/22c0P9tnND/bZvQ/22b0P9woNH/M0is/wAA
+ i/8CAo3/AwKN/wICjf8CAo7/AgKO/wICj/8DAo//AwKQ/wMDkv8EA5P/AwOW/wQDmP8FBJr/BQSd/wAA
+ nv8wP7v/msfv/5zH8P+bx/D/m8fx/5vH8v+cx/P/nMj0/5zI9P+dyPX/ncn2/57J9v+eyff/nsr3/57K
+ 9/+fyvf/n8r3/5/K+P+fyvj/n8v4/5/M+P+hzfj/SVTv/x0Y6/8iHuz/Ih7s/yIf7P8jH+z/Ih7s/yQg
+ 7f80L/b/OzX5/z03+P9DPfj/Qjv4/4aQ+f/W7Pz/0eb8/87k+//M4/v/yuL7/8jh+//G4Pv/xd/7/8Xf
+ +/+92/r/qtD5/6fP+P+kzfj/p9L//5S697j///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AF5z6Hicx/v/nsr0/5rF8P91pNv/bZzV/22d1v9tndT/bZzU/22c1P9tnNP/bZzS/22c
+ 0v9tnNH/bZzR/22c0f9tnNH/bZzQ/2+e0f9gisn/DRGV/wEAjv8CAo//AgKO/wICjv8CApD/AwKQ/wMC
+ kP8DA5H/BAOT/wQDlf8EA5b/AwOZ/wUDnf8FBKD/AQCh/zJHuf+AsOD/msXw/5vH8f+bx/H/m8fy/5zH
+ 8/+cyPT/nMj0/53I9f+dyfb/nsn2/57J9v+eyvf/nsr3/5/K9/+fyvj/n8r4/5/K+P+fy/j/n8v4/6TS
+ +P9kefL/Hxns/yIe7P8iHuz/Ih7s/yIe7P8jIO3/NC71/z02+v8+N/r/Qzz5/0hB+f9HQPj/oqr6/9zv
+ /P/T5/z/0eb8/87l+//M4/v/yuL7/8nh+//H4fv/x+H7/7nZ+v+q0fn/qM/5/6bO+P+mz///kLH1Zf//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AICDfGH+h7uGiz/j/nsnz/4i2
+ 5v9tnNb/bp3W/22d1f9tndT/bZzU/22c1P9tnNP/bZzT/22c0v9tnNH/bZzR/22c0f9tnNH/bZzQ/2+f
+ 0f8sPqj/AACN/wMCkP8CApD/AgGQ/wMCkf8DApL/AwKS/wQCk/8DA5b/BAOX/wQDmP8EA5z/BAOf/wQE
+ ov8CAKT/Nky9/2+g1v9/reD/m8bx/5vH8v+bx/P/nMfz/5zI9P+cyPX/ncj1/53J9v+eyfb/nsr3/57K
+ 9/+fyvf/n8r3/5/K+P+fyvj/n8v4/5/L+P+fy/j/o9D4/3mV9P8iHuz/Ih7s/yMf7P8jH+z/Ix/t/zMt
+ 9f8/OPv/Pzj7/0M9+v9IQfr/S0T6/01H+f+uuPv/3/D8/9bp/P/T5/z/0eX8/8/l+//M5Pv/y+L7/8nh
+ +//J4fv/ttf6/6vR+f+p0Pn/qdL8/5/G+Ol3kfce////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8AX3LoeZzH/P+ey/T/msbx/3em3f9tndb/bZ3W/22d1f9tndX/bZzU/22c
+ 1P9tnNP/bZzS/22c0v9tnNL/bZzS/22c0f9tnNH/caHT/0dluv8BAJD/AwOR/wMCkv8DApH/AwKS/wMC
+ kv8DApX/AwOW/wMDl/8EBJr/BASb/wQDnv8FA6L/BQSk/wEApv8zSL7/caHY/2yb1v+AruL/m8fy/5zH
+ 8/+cyPP/nMj0/53I9f+dyfb/nsn2/57J9v+eyvf/nsr3/5/K9/+fyvj/n8r4/5/K+P+fy/j/n8v4/6DL
+ +P+iz/j/g6P1/yUh7P8iHuz/Ix/s/yIf7P80LvX/QTr8/0E5/P9DPPz/SEL7/0xG+/9QSfr/U075/7G7
+ +//h8f3/2er8/9bo/P/T5/z/0eX7/87k/P/M5Pv/zOP7/8nh+/+01vn/rdL5/6rQ+f+s1v//lLj2ov//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAjI9wWfJzv3KPQ
+ +v+eyvT/jrrq/26e2P9tndf/bZ3W/22d1f9tnNT/bZzU/22c1P9tnNT/bZzT/22c0/9tnNL/bZzS/22c
+ 0v9voNP/VnrE/wYGlf8CAZT/AwOU/wMClP8DA5X/AwOV/wMDlv8EApf/BAOZ/wQDnP8EA57/BQOh/wUE
+ pP8FBKf/AQCo/ys7u/9woNf/bZ3X/2yc1/+DseX/ncj0/5zI9P+cyPT/ncj1/53J9v+eyfb/nsn3/57K
+ 9/+eyvf/n8r3/5/K+P+fyvj/n8r4/5/L+P+fy/j/oMv4/6PP+P+Hqfb/JiTs/yIe7P8jH+z/NC/2/0M7
+ /f9DO/3/RD39/0hA/P9NRvz/UUr7/1ZP+v9XUPr/r7b7/+Py/f/b6/z/2Or8/9Xo/P/S5/z/0OX8/8/k
+ /P/O5Pv/xuD7/7LU+f+u0vn/rNL7/6TL+/mCnvM/////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wBQX+Vjlbz3/6DM9f+dyPP/gK7i/2yc1v9undf/bp3W/22d
+ 1v9tnNX/bZzU/22c1P9tnNT/bZzT/22c0/9tnNL/bZzS/2+f0/9ZgMf/CQqZ/wIBlf8DApX/AwKW/wQD
+ l/8EA5j/BAOZ/wQDmv8EA57/BASf/wUEov8FBKT/BQSm/wUFqf8DAar/ICu5/2ua1v9undj/bZ3Y/22d
+ 2f+Iten/ncn1/53I9f+dyfX/ncn2/57J9/+eyff/nsr3/5/K9/+fyvj/n8r4/5/K+P+fyvj/oMv4/6DL
+ +P+gy/j/o8/4/4Sl9f8kIez/Ix/s/zYx9/9EPf7/RDz+/0M8/f9IQf3/TET8/1FL/P9VTvv/WVP7/1lS
+ +v+iqfv/4/P9/9zs/P/Z6vz/1uj8/9To/P/R5vz/0OX8/8/l+/+/3Pr/stX5/67T+f+w2v//lrf2sQAA
+ /wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAA
+ tgduh+23o8/9/57K9P+ZxfH/d6Xd/22d1/9undf/bZ3W/22d1f9tnNT/bZzU/22c1P9tnNT/bZzT/22c
+ 0/9tnNP/b5/U/1l/x/8JC5z/AwKY/wQDmf8EBJn/BAOZ/wQDmv8EBJz/BASd/wUEoP8FBKL/BQWk/wUF
+ pv8FBan/BQWr/wUErv8RFrb/ZI/U/26f2f9tndn/bZzZ/2+f2/+PvO3/nsr2/53J9v+dyfb/nsn2/57K
+ 9/+eyvf/n8r3/5/K9/+fyvj/n8v4/5/L+P+gy/j/oMv4/6DL+P+k0Pj/eZb0/yYi7v85M/n/RT7+/0U9
+ /v9FPf7/R0D+/0pE/f9QSf3/VE78/1pT/P9eWPv/YFn6/4SH+v/f7v3/3u38/9vr/P/Y6fz/1ej8/9Pn
+ /P/S5vz/zeT7/7jY+v+y1fn/stf8/6TJ+/F6lPUy////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AC4u4iyCo/Too8/5/57K9P+TwO7/cqHa/22d
+ 1/9undf/bZ3W/22d1v9tndX/bZzU/22c1P9tnNT/bZzU/22c1P9wodX/UnbF/wYGnf8EA5z/BQSd/wUE
+ nP8EBJ3/BASd/wUEnv8FBKD/BQSj/wUEpP8FBKb/BQWp/wYFrP8GBq7/Bgax/wYGtP9Mbc3/cKLa/22d
+ 2f9undr/bZ3Z/3al3v+ZxPP/nsr2/57J9v+eyvf/nsr3/5/K9/+fyvf/n8r4/5/L+P+fy/j/oMv4/6DL
+ +P+gy/j/oMv4/6PQ+P9sf/X/ODH6/0U9/v9FPf//Rj7//0Y///9KQ/7/Tkf+/1RN/f9ZUfz/Xlj8/2Nc
+ +/9mYfr/b2v6/8vX/P/h8Pz/2+v8/9jq/P/W6fz/1Of8/9Pn/P/G4Pv/ttf6/7TX+v+v0///jKb0c///
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AEpa52CQt/b+oc73/5/K9P+PvOv/cKDa/22d1/9untf/bp3W/22d1v9tndX/bZzV/22c
+ 1P9tnNT/bZzU/3Ch1v9GZMD/AgGe/wUFn/8FBZ//BQWg/wUEoP8FBKH/BQWi/wUFpP8FBaf/BgWn/wYF
+ qf8GBaz/Bgat/wYGsP8HB7P/BQO2/yUzwv9untn/bp7a/26d2v9untr/bZzZ/4Kw5v+fyvf/nsn3/57K
+ 9/+eyvf/n8r4/5/K+P+fyvj/n8v4/5/L+P+gy/j/oMv4/5/K+P+hy/j/vt76/2xx/P8/Nv7/RT3+/0U9
+ //9GPv//SkL//01G/v9RSv7/WFD9/11W/P9hWvz/ZmD7/2xl+v9sZvr/pKr7/+Lx/P/c7Pz/2er8/9fp
+ /P/W6Pz/zuT7/7za+v+32Pr/uNv//5Kt9qIAAP8E////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAVps6YuYwfv/oM32/57K
+ 9P+Nuur/caDa/22d1/9undf/bp3W/22d1v9tndX/bZzV/22c1P9tnNT/b5/V/zFEt/8CAKH/BQWj/wUF
+ o/8FBaL/BQWj/wUFpP8GBqX/BQWm/wUFqP8GBqr/Bgas/wYHr/8GB7H/CAe0/wgIt/8ICLr/Cgq9/01s
+ 0f9xo9v/bp7a/2+e2v9vntv/caDc/5TB8f+fy/f/n8r3/5/K9/+fyvj/n8r4/5/L+P+fy/j/n8v4/6DL
+ +P+eyvj/ps74/9Lo/P/H1f3/SEP9/0I6/f9EPP7/RT7+/0c//v9MRP7/UEn+/1RN/f9cVP3/YFr8/2Ve
+ /P9rZPv/cGr6/3Ru+v+Affn/0Nz8/9/u/f/a6vz/2Or8/9Lm/P/B3fr/u9v6/7zd//+Ys/e1W23tDv//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8AAADbB2B07KKbxfz/ocz2/5/K9P+Rvez/c6Lb/2yd1/9untj/bp3X/26d
+ 1v9tndb/bZ3V/26d1f9qmNP/GiSw/wQEpv8GB6f/Bgam/wYGpv8GBqf/BQWo/wYGqf8GBqr/Bger/wYH
+ rv8GB6//CAex/wgHtP8ICLf/CAi5/wkJvP8IB77/GB3D/2GL1/9yotr/b57a/2+e2/9unNr/gK/l/5/L
+ 9/+fyvf/n8r3/5/K+P+fyvj/n8v4/6DL+P+fy/j/nsr4/7LV+f/c7fz/5O/9/2dn/P89NPz/Qzv9/0M8
+ /f9FPf7/SUH+/01F/v9TTP7/WFH9/19Y/f9iXPz/aGP8/25o+/9zbfv/eXP6/3p0+f+hpPr/3u39/9vr
+ /P/V6Pz/xd/7/8De+/+/3v//mrP3tVBg7xD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAADRC2B3
+ 66Waw/3/oc32/5/K9f+Vwu//eqjg/22d2P9tntf/bp3X/26d1/9tndb/cKHX/1Z7zP8JC6z/Bgaq/wcH
+ qf8HB6r/Bgeq/wcHqf8GB6v/Bges/wcHrf8HB6//Bwew/wcIsv8ICLT/CAi3/wkJuv8KCrv/Cwq+/wwL
+ wf8KB8L/JS/K/2aR2f9zo9z/cJ7b/3Ce2/90ot7/mcXz/6DL9/+fyvf/n8r4/5/L+P+fy/j/nsr4/6bO
+ +P/C3vv/5PP9/93q/f91e/v/OjP7/0E5/P9CO/3/Qjv9/0U9/f9KQ/3/T0j9/1VP/f9bVP3/YFr8/2Zf
+ /P9tZvv/cmz7/3Zw+v97dvr/gHr5/4R/+f/Ayfv/3O78/8nh+//G4v3/vdr//5aq96JOTusN////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AAADmCltv6ZeSufj/o9D5/5/K9f+bx/L/hrPm/3Kh
+ 2/9tnNf/bp3X/26d1/9xodj/MkbA/wYErv8JCa//CAiu/wgIrf8IB63/CAiu/wgIr/8ICK//CAmx/wgI
+ sv8JCLT/CQm1/woKt/8LCrr/Cwq8/wwLvv8MDMH/DQzC/w4NxP8MCsb/IivL/1l91/9yotz/c6Pc/3Gg
+ 3P+Ou+3/oc34/5/L+P+gy/j/n8z4/6PO+P+22vr/1Or8/9zu/P+0xPv/XmD6/zgx+v8+N/v/QDn8/0A5
+ /P9COvz/RT79/0tE/f9RSv3/V1D8/11X/P9jXPz/aWP7/29p+/90bvv/eXP6/396+v+Ef/n/ioT5/3x8
+ +P+xx/r/z+r//7XP/faRpvZ2AADMBf///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8AAAD/Ak5e6XKCo/Lyo9D9/6DM9f+eyvT/lcHv/4Cu4/9woNr/b6DY/16G0v8RFLf/Cgiz/woK
+ s/8KCrP/Cgmx/wkKsf8JCrL/CQqz/wkKs/8JCrT/Cgm2/woKt/8LCrn/DAq7/wwLvf8MC77/DQzA/w0M
+ wv8ODcT/Dg7G/xAQyP8PDsj/FhjL/zVH0/9Wd9j/ZY7a/36p5v+fy/n/n8v4/53I+P+lzfj/stD5/7HB
+ +v+Uofn/YWf5/zw3+P83L/n/PDb6/z02+v8/OPv/Pzj7/0E6+/9HQPz/TEX8/1NM/P9ZUvz/X1j8/2Zf
+ +/9rZPv/cWv7/3dx+v99d/r/hH/5/4R/+f9oY/f/Ni/4/1VX//+kuvnQfoz0Rf///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ADA05TtshfDBk7v5/6PQ
+ +/+hzfX/nsr0/5XC7/+FsuX/MUDJ/wkHuP8MDLf/DAy3/wwLtv8MC7b/Cwu2/wsLtf8LC7f/Cwu3/wsL
+ uP8MC7n/DAu6/wwMvP8NDL3/DQy//w0Mwf8ODcP/Dw7E/w8Pxv8PEMj/ERHJ/xISyv8TEsz/EhDN/xUU
+ zv8eI9D/LDTa/0JL7v9IUvD/SE/z/01R9P9GSfX/NjL2/zAp9v8yK/f/ODH4/zo0+P87NPn/PTb6/z44
+ +v8+N/v/Qzz7/0hC+/9PSPv/VE37/1tV+/9hWvv/Z2H7/2xm+v9zbvr/e3X5/314+f9qZfj/SEL5/zYw
+ //84MvfxOzP0hhsN5BP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AAAA0QtJVeRpdI/u1pK4+P+j0Pz/pNH4/2N66P8UEdT/EhDO/xEQ
+ yP8PDsL/Dg6//w4NvP8NDLr/DAy5/wwMuv8MDLr/DQy7/wwMu/8NDb3/Dg2//w4Nwf8ODcH/Dw/D/w8P
+ xf8PEMf/ERHI/xISyf8TE8v/FBTM/xUUzf8VFc7/FRXP/xUU0P8YFtn/Ih3u/ych8P8pJPL/KyXz/y8o
+ 9P8zLfX/NS72/zYw9/84Mff/OjT4/zs0+P87NPn/PDb5/z84+v9EPfr/SkP6/09J+/9WUPv/XFX6/2Nc
+ +v9pZPr/cWv6/3Rv+v9nYfn/SUP4/zgx/v83Mvj8QDv2rk5F8DT///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wAAAMkTSFPkX3GL7rlmfe3sHRzj/xcV4f8YFd7/FxTc/xYT2f8UE9T/FBLR/xQRz/8TEM3/EhDM/xER
+ yf8REMj/EBDG/xEPxv8QEMX/EBDF/xAQxf8QEMX/ERHG/xESx/8TE8n/ExPK/xQUzP8VFc7/FRXP/xYV
+ 0P8XF9L/GBnW/yAe4v8pJPD/KyXx/y0n8v8uKfP/MSz0/zIt9f80LvX/NS/1/zYw9/83Mff/OTP4/zs0
+ +P87Nfn/QDn5/0Q++f9KRPn/UUv6/1dS+v9eWPr/ZV/6/2Zg+v9gWfn/SkT5/zkz//85M/j+QDv4u0xF
+ 9Ur///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAA2CcYEt1hGhfcmxgW
+ 3McZFtzkGBXa9xkW4P8YFuD/GBXg/xgV4f8YFeD/GBXf/xkV3v8XFd3/GBXd/xcV2/8YFdv/FxXa/xcV
+ 2P8XFdb/FhXS/xUV0f8VFc//FRXO/xUVzv8WFtD/FxfT/xgZ1f8aG9n/JCHq/ykk8P8rJvH/LCfy/y4p
+ 8v8vKvP/Miv0/zMt9f80LvX/NjD2/zYw9v83Mff/OTP4/zw1+P9AOvj/RkD5/01G+f9TTPn/VE75/1FK
+ +f9IQvj/Pzn6/zkz//86M/n+Qj34vE5I8k6ZmcwF////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AJCTbBxoa3R4YGNk2GRbaUxkX3W8aFt6LGRbbpBkW
+ 27gZFdvMGhbd3BkW3egaF9/0Gxfi/xwY6f8cGer/HBnq/x0Z6f8dGuj/HRrm/x4b5P8dG+L/HBre/xsa
+ 3P8cG9v/HRze/yMg6P8nI+//KSTv/yom8f8tKPH/Liny/y8q8/8xK/P/MSz0/zMt9f8zLvX/NS/2/zcw
+ 9v84Mvf/PTb3/0E79/9GP/j/RkD4/0I7+P87Nfj/ODL6/zkz//87Nfj7Qz34t05L8k6ZzMwF////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////ABoa5goYGNsVFxfgIRoV4DEcFeBKHBfjZRwY
+ 44kcGeOsHBrkzx4b5uYfG+f9IR3x/yIe8f8iHvD/Ix/v/yMf7v8lIe3/JiLu/ycj7v8oJO//KiXw/ywn
+ 8f8tKPH/Liny/y8q8/8wK/T/Miz0/zMu9f80LvX/NS/2/zcx9v85M/b/OTP2/zkz9/84Mfj/ODL8/zoz
+ //89N/jyRD/3qU1J80L//6oD////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wAVFeoMIRnmHyAY5z8gHetoIh3rlyIe
+ 674iHurfIx/r9iUh8/8mIvb/KCP2/ykk9f8qJfT/Kybz/ywn8/8tKPL/Liny/y8q8/8wKvP/Miz0/zMt
+ 9P8zLvb/NC74/zUv+f82MP3/NzH+/zkz9v0+OfXTR0H1hVFR9C///wAB////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8AAACqAyAg6hgjHuszJSLrWSYj7IUnI+6oKCTuxykm
+ 794sJ/DsLSjx+C0o8/8uKfr/MCr6/zEr+/8xLPv/My36/zQu9P43MvTyODL14Ds19LtCPvWESUXzP3dm
+ 7g////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wBJSf8HNzfpFzcw8SUzLvAyMCvyOysn8EIuK/BCLivwQi4r
+ 80I0LPNAOzfxOEtG8yxcXPUZ//8AAf///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
+ /wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////////////
+ 4AD//////////////////wAAP/////////////////wAAA/////////////////wAAAH////////////
+ ////wAAAA////////////////4AAAAH///////////////4AAAAA///////////////8AAAAAP//////
+ ////////+AAAAAB///////////////AAAAAAf//////////////wAAAAAD//////////////4AAAAAA/
+ /////////////8AAAAAAP/////////////+AAAAAAD//////////////gAAAAAA//////////////wAA
+ AAAAP/////////////8AAAAAAD/////////////+AAAAAAA//////////////gAAAAAAP///////////
+ //wAAAAAAH/////////////8AAAAAAB//////////////AAAAAAAf/////////////gAAAAAAH//////
+ ///////4AAAAAAD/////////////+AAAAAAA//////////////AAAAAAAf/////////////wAAAAAAH/
+ ////////////8AAAAAAB/////////////+AAAAAAA//////////////gAAAAAAf/////////////4AAA
+ AAAH/////////////8AAAAAAD//////////////AAAAAAA//////////////gAAAAAAf////////////
+ /4AAAAAAP/////////////+AAAAAAD//////////////gAAAAAB//////////////wAAAAAA////////
+ //////8AAAAAAf//////////////AAAAAAP//////////////gAAAAAD//////////////4AAAAAB///
+ ///////////+AAAAAA///////////////gAAAAAf//////////////4AAAAAP//////////////8AAAA
+ AH///////////////AAAAAD///////////////wAAAAB///////////////8AAAAA///////////////
+ /AAAAAf///////////////gAAAAP///////////////4AAAAH///////////////+AAAAD//////////
+ //////gAAAA////////////////4AAAAf///////////////+AAAAP////////////////gAAAH/////
+ ///////////wAAAD////////////////8AAAA/////////////////AAAAf////////////////wAAAP
+ ////////////////8AAAD////////////wAAD/AAAB////////////AAAAAAAAA////////////gAAAA
+ AAAAP///////////gAAAAAAAAH///////////wAAAAAAAAD///////////4AAAAAAAAB///////////8
+ AAAAAAAAAP///////////AAAAAAAAAAf//////////gAAAAAAAAAB//////////wAAAAAAAAAAD/////
+ ////8AAAAAAAAAAAP////////+AAAAAAAAAAAA/////////gAAAAAAAAAAAD////////wAAAAAAAAAAA
+ AP///////8AAAAAAAAAAAAAf///////AAAAAAAAAAAAAD///////gAAAAAAAAAAAAAP//////4AAAAAA
+ AAAAAAAB//////+AAAAAAAAAAAAAAP//////gAAAAAAAAAAAAAB//////4AAAAAAAAAAAAAAP/////+A
+ AAAAAAAAAAAAAB//////gAAAAAAAAAAAAAAf/////4AAAAAAAAAAAAAAD/////+AAAAAAAAAAAAAAA//
+ ////gAAAAAAAAAAAAAAP/////4AAAAAAAAAAAAAAB/////+AAAAAAAAAAAAAAAf/////gAAAAAAAAAAA
+ AAAH/////4AAAAAAAAAAAAAAB/////+AAAAAAAAAAAAAAAP/////gAAAAAAAAAAAAAAD/////4AAAAAA
+ AAAAAAAAA/////+AAAAAAAAAAAAAAAP/////wAAAAAAAAAAAAAAD/////8AAAAAAAAAAAAAAA//////A
+ AAAAAAAAAAAAAAP/////4AAAAAAAAAAAAAAD/////+AAAAAAAAAAAAAAB//////gAAAAAAAAAAAAAAf/
+ ////8AAAAAAAAAAAAAAH//////AAAAAAAAAAAAAAD//////4AAAAAAAAAAAAAA//////+AAAAAAAAAAA
+ AAAP//////wAAAAAAAAAAAAAH//////8AAAAAAAAAAAAAB///////gAAAAAAAAAAAAAf//////4AAAAA
+ AAAAAAAAP///////AAAAAAAAAAAAAH///////4AAAAAAAAAAAAB///////+AAAAAAAAAAAAA////////
+ wAAAAAAAAAAAAf///////+AAAAAAAAAAAAP////////wAAAAAAAAAAAH////////+AAAAAAAAAAAH///
+ //////4AAAAAAAAAAD//////////AAAAAAAAAAD//////////8AAAAAAAAAB///////////4AAAAAAAA
+ B////////////wAAAAAAAB//////////////AAAAAAB///////////////8AAAAB////////////////
+ +AAAD//////////////////gAH//////////////////////////////iVBORw0KGgoAAAANSUhEUgAA
+ AQAAAAEACAYAAABccqhmAAAKPWlDQ1BpY2MAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4BUaaIS
+ kgChhBgSQOyIqMCIoiKCFRkUccDREZCxIoqFQbH3AXkIKOPgKDZU3g/eGn2z5r03b/avvfY5Z53vnH0+
+ AEZgsESahaoBZEoV8ogAHzw2Lh4ndwMKVCCBA4BAmC0LifSPAgDg+/Hw7IgAH/gCBODNbUAAAG7YBIbh
+ OPx/UBfK5AoAJAwApovE2UIApBAAMnIVMgUAMgoA7KR0mQIAJQAAWx4bFw+AagEAO2WSTwMAdtIk9wIA
+ tihTKgJAowBAJsoUiQDQDgBYl6MUiwCwYAAoypGIcwGwmwBgkqHMlABg7wCAnSkWZAMQGABgohALUwEI
+ 9gDAkEdF8AAIMwEojJSveNJXXCHOUwAA8LJki+WSlFQFbiG0xB1cXbl4oDg3Q6xQ2IQJhOkCuQjnZWXK
+ BNLFAJMzAwCARnZEgA/O9+M5O7g6O9s42jp8taj/GvyLiI2L/5c/r8IBAQCE0/VF+7O8rBoA7hgAtvGL
+ lrQdoGUNgNb9L5rJHgDVQoDmq1/Nw+H78fBUhULmZmeXm5trKxELbYWpX/X5nwl/AV/1s+X78fDf14P7
+ ipMFygwFHhHggwuzMrKUcjxbJhCKcZs/HvHfLvzzd0yLECeL5WKpUIxHS8S5EmkKzsuSiiQKSZYUl0j/
+ k4l/s+wPmLxrAGDVfgb2QltQu8oG7JcuILDogCXsAgDkd9+CqdEQBgAxBoOTdw8AMPmb/x1oGQCg2ZIU
+ HACAFxGFC5XynMkYAQCACDRQBTZogz4YgwXYgCO4gDt4gR/MhlCIgjhYAEJIhUyQQy4shVVQBCWwEbZC
+ FeyGWqiHRjgCLXACzsIFuALX4BY8gF4YgOcwCm9gHEEQMsJEWIg2YoCYItaII8JFZiF+SDASgcQhiUgK
+ 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
+ +QAAAABJRU5ErkJggg==
+
+
+
\ No newline at end of file
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.vb
new file mode 100644
index 0000000..85b4b8b
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Preview/ModelPreview.vb
@@ -0,0 +1,341 @@
+Imports System.Drawing
+Imports System.Windows.Forms
+Imports Pilz.Drawing.Drawing3D.OpenGLFactory.CameraN
+Imports Pilz.Drawing.Drawing3D.OpenGLFactory.RenderingN
+Imports OpenTK
+Imports OpenTK.Graphics.OpenGL
+Imports Pilz.S3DFileParser
+Imports Point = System.Drawing.Point
+
+Namespace PreviewN
+
+ Public Class ModelPreview
+
+ Public Event WandUpdateView()
+
+ Private WithEvents glControl1 As GLControl
+ Private WithEvents MyCamera As New Camera
+ Private ProjMatrix As Matrix4 = Nothing
+ Private FOV As Single = 1.048F
+ Private camMtx As Matrix4 = Matrix4.Identity
+ Private savedCamPos As New Vector3
+ Private _isMouseDown As Boolean = False
+ Private myPressedKeys As New List(Of Keys)
+ Private isDeactivated As Boolean = False
+ Private ReadOnly myModels As New Dictionary(Of Object3D, Renderer)
+
+ Public Property RenderWhenWindowsIsInactive As Boolean = False
+ Public Property EnableCameraControlling As Boolean = True
+ Public Property Scaling As Single = 500.0F
+ Public Property ClearColor As Color = Color.CornflowerBlue
+
+ Public ReadOnly Property PressedKeys As IReadOnlyList(Of Keys)
+ Get
+ Return myPressedKeys
+ End Get
+ End Property
+
+ Public ReadOnly Property Camera As Camera
+ Get
+ Return MyCamera
+ End Get
+ End Property
+
+ Public ReadOnly Property CameraMatrix As Matrix4
+ Get
+ Return camMtx
+ End Get
+ End Property
+
+ Public ReadOnly Property Models As IReadOnlyDictionary(Of Object3D, Renderer)
+ Get
+ Return myModels
+ End Get
+ End Property
+
+ Private ReadOnly Property IsStrgPressed As Boolean
+ Get
+ Return myPressedKeys.Contains(Keys.ControlKey)
+ End Get
+ End Property
+
+ Private ReadOnly Property IsShiftPressed As Boolean
+ Get
+ Return myPressedKeys.Contains(Keys.ShiftKey)
+ End Get
+ End Property
+
+ Public Property IsMouseDown As Boolean
+ Get
+ Return _isMouseDown
+ End Get
+ Set(value As Boolean)
+ _isMouseDown = value
+ glControl1.Refresh()
+ End Set
+ End Property
+
+ Public Sub New()
+ Me.New({}, 1.0F)
+ End Sub
+
+ Public Sub New(obj As Object3D)
+ Me.New(obj, 1.0F)
+ End Sub
+
+ Public Sub New(obj As Object3D, scale As Single)
+ Me.New({obj}, scale)
+ End Sub
+
+ Public Sub New(objs As Object3D(), scale As Single)
+ Me.SuspendLayout()
+
+ InitializeComponent()
+ DoubleBuffered = True
+
+ 'glControl1
+ Me.glControl1 = New GLControl
+ Me.glControl1.BackColor = Color.Black
+ Me.glControl1.Location = New Point(0, 0)
+ Me.glControl1.MinimumSize = New Size(600, 120)
+ Me.glControl1.Name = "glControl1"
+ Me.glControl1.Anchor = AnchorStyles.Left Or AnchorStyles.Top Or AnchorStyles.Right Or AnchorStyles.Bottom
+ Me.glControl1.Location = New Point(0, 0)
+ Me.glControl1.Size = Me.ClientSize
+ Me.glControl1.TabIndex = 0
+ Me.glControl1.TabStop = False
+ Me.glControl1.VSync = False
+ Me.Controls.Add(Me.glControl1)
+ Me.ResumeLayout(False)
+ AddHandler Windows.Media.CompositionTarget.Rendering, AddressOf CompositionTarget_Rendering
+
+ Scaling = scale
+
+ 'Toolkit.Init()
+
+ glControl1.CreateControl()
+ AddHandler glControl1.MouseWheel, AddressOf glControl1_Wheel
+ ProjMatrix = Matrix4.CreatePerspectiveFieldOfView(FOV, glControl1.Width / glControl1.Height, 100.0F, 100000.0F)
+ glControl1.Enabled = False
+ MyCamera.SetCameraMode(CameraMode.FLY, camMtx)
+ MyCamera.UpdateMatrix(camMtx)
+
+ Me.ResumeLayout()
+
+ For Each obj As Object3D In objs
+ AddModel(obj)
+ Next
+ End Sub
+
+ Public Sub UpdateOrbitCamera()
+ If Camera.IsOrbitCamera Then
+ Camera.UpdateOrbitCamera(camMtx)
+ End If
+ End Sub
+
+ Public Sub UpdateView()
+ glControl1.Invalidate()
+ 'glControl1.Update()
+ End Sub
+
+ Public Function AddModel(obj As Object3D) As Renderer
+ Dim rndr As New Renderer(obj)
+ AddModel(rndr)
+ Return rndr
+ End Function
+
+ Public Sub AddModel(rndr As Renderer)
+ myModels.Add(rndr.Model, rndr)
+ End Sub
+
+ Public Sub HandlesOnShown(sender As Object, e As EventArgs) Handles MyBase.Shown
+ glControl1.Enabled = True
+ RenderModels()
+ glControl1.Invalidate()
+ End Sub
+
+ Public Sub RenderModels()
+ For Each rndr As Renderer In myModels.Values
+ RenderModel(rndr)
+ Next
+ End Sub
+
+ Public Sub RenderModel(rndr As Renderer)
+ If myModels.Values.Contains(rndr) Then
+ rndr.ModelScaling = Scaling
+ rndr.RenderModel()
+ End If
+ End Sub
+
+ Private Sub glControl1_Load(sender As Object, e As EventArgs) Handles glControl1.Load
+ GL.Enable(EnableCap.Blend)
+ GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha)
+
+ GL.Enable(EnableCap.DepthTest)
+ GL.DepthFunc(DepthFunction.Lequal)
+
+ GL.Enable(EnableCap.Texture2D)
+ GL.Enable(EnableCap.AlphaTest)
+ GL.AlphaFunc(AlphaFunction.Gequal, 0.5F)
+
+ GL.Enable(EnableCap.CullFace)
+ End Sub
+
+ Public Sub HandlesOnActivated(sender As Object, e As EventArgs) Handles Me.Activated
+ If isDeactivated Then
+ isDeactivated = False
+ End If
+ End Sub
+
+ Public Sub HandlesOnDeactivate(sender As Object, e As EventArgs) Handles Me.Deactivate
+ isDeactivated = True
+ End Sub
+
+ Private Sub CompositionTarget_Rendering(sender As Object, e As EventArgs)
+ If Not isDeactivated OrElse RenderWhenWindowsIsInactive Then
+ RaiseEvent WandUpdateView()
+ glControl1.Invalidate()
+ End If
+ End Sub
+
+ Public Sub HandlesOnPaint(sender As Object, e As PaintEventArgs) Handles glControl1.Paint
+ If EnableCameraControlling Then
+ MoveCameraViaWASDQE()
+ End If
+
+ GL.ClearColor(ClearColor)
+
+ GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)
+
+ GL.MatrixMode(MatrixMode.Projection)
+ GL.LoadMatrix(ProjMatrix)
+ GL.MatrixMode(MatrixMode.Modelview)
+ GL.LoadMatrix(camMtx)
+
+ For Each rndr As Renderer In myModels.Values
+ If rndr.HasRendered Then
+ rndr.DrawModel(RenderMode.FillOutline)
+ End If
+ Next
+
+ glControl1.SwapBuffers()
+
+ 'If Not IsMouseDown AndAlso obj3d IsNot Nothing Then
+ ' e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
+ ' e.Graphics.DrawString(GetModelInfoAsString, New Font(FontFamily.GenericSerif, 10), New SolidBrush(Panel1.ForeColor), New Drawing.Point(10, 10))
+ 'End If
+ End Sub
+
+ Private Function GetModelInfoAsString() As String
+ Dim matsCount As Long = 0
+ Dim facesCount As Long = 0
+ Dim vertsCount As Long = 0
+ Dim vcCount As Long = 0
+ Dim uvCount As Long = 0
+
+ For Each obj3d As Object3D In myModels.Keys
+ matsCount += obj3d.Materials.Count
+ For Each m As Mesh In obj3d.Meshes
+ vertsCount += m.Vertices.Count
+ facesCount += m.Faces.Count
+ vcCount += m.VertexColors.Count
+ uvCount += m.UVs.Count
+ Next
+ Next
+
+ Return String.Format("Materials:{0}{1}
+Faces:{0}{0}{2}
+Vertices:{0}{3}
+Vertex Colors{0}{4}
+UVs:{0}{0}{5}",
+ vbTab, matsCount, facesCount, vertsCount, vcCount, uvCount)
+ End Function
+
+ Private Sub glControl1_Resize(sender As Object, e As EventArgs) Handles glControl1.Resize
+ glControl1.Context.Update(glControl1.WindowInfo)
+ GL.Viewport(0, 0, glControl1.Width, glControl1.Height)
+ ProjMatrix = Matrix4.CreatePerspectiveFieldOfView(FOV, glControl1.Width / glControl1.Height, 100.0F, 100000.0F)
+ glControl1.Invalidate()
+ End Sub
+
+ Private Sub glControl1_Wheel(sender As Object, e As MouseEventArgs)
+ MyCamera.ResetMouseStuff()
+ MyCamera.UpdateCameraMatrixWithScrollWheel(CInt(Math.Truncate(e.Delta * (If(IsShiftPressed, 3.5F, 1.5F)))), camMtx)
+ savedCamPos = MyCamera.Position
+ glControl1.Invalidate()
+ End Sub
+
+ Private Sub glControl1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles glControl1.MouseDown
+ IsMouseDown = True
+ savedCamPos = MyCamera.Position
+ End Sub
+
+ Private Sub glControl1_MouseLeave(ByVal sender As Object, ByVal e As EventArgs) Handles glControl1.MouseLeave, glControl1.MouseUp
+ MyCamera.ResetMouseStuff()
+ IsMouseDown = False
+ End Sub
+
+ Private Sub glControl1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles glControl1.MouseMove
+ If IsMouseDown AndAlso e.Button = MouseButtons.Left Then
+ If IsShiftPressed Then
+ MyCamera.UpdateCameraOffsetWithMouse(savedCamPos, e.X, e.Y, glControl1.Width, glControl1.Height, camMtx)
+ Else
+ MyCamera.UpdateCameraMatrixWithMouse(e.X, e.Y, camMtx)
+ End If
+ glControl1.Invalidate()
+ End If
+ End Sub
+
+ Public Sub HandlesOnKeyDown(sender As Object, e As KeyEventArgs) Handles glControl1.KeyDown
+ If Not myPressedKeys.Contains(e.KeyCode) Then myPressedKeys.Add(e.KeyCode)
+ End Sub
+
+ Public Sub HandlesOnKeyUp(sender As Object, e As KeyEventArgs) Handles MyBase.KeyUp
+ If myPressedKeys.Contains(e.KeyCode) Then myPressedKeys.Remove(e.KeyCode)
+ End Sub
+
+ Public Sub MoveCameraViaWASDQE()
+ Dim moveSpeed As Integer = Convert.ToInt32(Math.Round((If(IsShiftPressed, 60, 30)) * (MyCamera.CamSpeedMultiplier), 0))
+ Dim allowCamMove As Boolean = Not (IsMouseDown AndAlso IsShiftPressed)
+
+ For Each k As Keys In myPressedKeys
+ If allowCamMove Then
+ Select Case k
+ Case Keys.W
+ 'camera.Move(moveSpeed, moveSpeed, camMtx)
+ MyCamera.UpdateCameraMatrixWithScrollWheel(moveSpeed, camMtx)
+ savedCamPos = MyCamera.Position
+ Case Keys.S
+ 'camera.Move(-moveSpeed, -moveSpeed, camMtx)
+ MyCamera.UpdateCameraMatrixWithScrollWheel(-moveSpeed, camMtx)
+ savedCamPos = MyCamera.Position
+ Case Keys.A
+ 'camera.Move(-moveSpeed, 0, camMtx)
+ MyCamera.UpdateCameraOffsetDirectly(-moveSpeed, 0, camMtx)
+ Case Keys.D
+ 'camera.Move(moveSpeed, 0, camMtx)
+ MyCamera.UpdateCameraOffsetDirectly(moveSpeed, 0, camMtx)
+ Case Keys.E
+ 'camera.Move(0, -moveSpeed, camMtx)
+ MyCamera.UpdateCameraOffsetDirectly(0, -moveSpeed, camMtx)
+ Case Keys.Q
+ 'camera.Move(0, moveSpeed, camMtx)
+ MyCamera.UpdateCameraOffsetDirectly(0, moveSpeed, camMtx)
+ End Select
+ End If
+ Next
+ End Sub
+
+ Private Sub Camera_NeedSelectedObject(e As Camera.NeedSelectedObjectEventArgs) Handles MyCamera.NeedSelectedObject
+ e.Points = Nothing
+ End Sub
+
+ Private Sub ModelPreview_FormDisposed(sender As Object, e As EventArgs) Handles Me.Disposed
+ For Each rndr As Renderer In myModels.Values
+ rndr.ReleaseBuffers()
+ Next
+ End Sub
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/BoundingBox.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/BoundingBox.vb
new file mode 100644
index 0000000..edbd8d4
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/BoundingBox.vb
@@ -0,0 +1,105 @@
+Imports System.Drawing
+Imports OpenTK
+Imports OpenTK.Graphics.OpenGL
+
+Namespace RenderingN
+
+ Public Class BoundingBox
+
+ Public Shared Sub DrawSolid(scale As System.Numerics.Vector3, rot As System.Numerics.Quaternion, pos As System.Numerics.Vector3, color As Color, upper As System.Numerics.Vector3, lower As System.Numerics.Vector3)
+ GL.Disable(EnableCap.Blend)
+ GL.Disable(EnableCap.Texture2D)
+ GL.Disable(EnableCap.AlphaTest)
+ 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.X, scale.Y, scale.Z)
+
+ GL.Begin(PrimitiveType.Quads)
+ GL.Color4(color)
+
+ GL.Vertex3(upper.X, upper.Y, lower.Z) ' Top-right of top face
+ GL.Vertex3(lower.X, upper.Y, lower.Z) ' Top-left of top face
+ GL.Vertex3(lower.X, upper.Y, upper.Z) ' Bottom-left of top face
+ GL.Vertex3(upper.X, upper.Y, upper.Z) ' Bottom-right of top face
+
+ GL.Vertex3(upper.X, lower.Y, lower.Z) ' Top-right of bottom face
+ GL.Vertex3(lower.X, lower.Y, lower.Z) ' Top-left of bottom face
+ GL.Vertex3(lower.X, lower.Y, upper.Z) ' Bottom-left of bottom face
+ GL.Vertex3(upper.X, lower.Y, upper.Z) ' Bottom-right of bottom face
+
+ GL.Vertex3(upper.X, upper.Y, upper.Z) ' Top-Right of front face
+ GL.Vertex3(lower.X, upper.Y, upper.Z) ' Top-left of front face
+ GL.Vertex3(lower.X, lower.Y, upper.Z) ' Bottom-left of front face
+ GL.Vertex3(upper.X, lower.Y, upper.Z) ' Bottom-right of front face
+
+ GL.Vertex3(upper.X, lower.Y, lower.Z) ' Bottom-Left of back face
+ GL.Vertex3(lower.X, lower.Y, lower.Z) ' Bottom-Right of back face
+ GL.Vertex3(lower.X, upper.Y, lower.Z) ' Top-Right of back face
+ GL.Vertex3(upper.X, upper.Y, lower.Z) ' Top-Left of back face
+
+ GL.Vertex3(lower.X, upper.Y, upper.Z) ' Top-Right of left face
+ GL.Vertex3(lower.X, upper.Y, lower.Z) ' Top-Left of left face
+ GL.Vertex3(lower.X, lower.Y, lower.Z) ' Bottom-Left of left face
+ GL.Vertex3(lower.X, lower.Y, upper.Z) ' Bottom-Right of left face
+
+ GL.Vertex3(upper.X, upper.Y, upper.Z) ' Top-Right of left face
+ GL.Vertex3(upper.X, upper.Y, lower.Z) ' Top-Left of left face
+ GL.Vertex3(upper.X, lower.Y, lower.Z) ' Bottom-Left of left face
+ GL.Vertex3(upper.X, lower.Y, upper.Z) ' Bottom-Right of left face
+
+ GL.Color4(Color.White)
+ GL.End()
+ GL.PopMatrix()
+ GL.Enable(EnableCap.Blend)
+ GL.Enable(EnableCap.Texture2D)
+ GL.Enable(EnableCap.AlphaTest)
+ End Sub
+
+ Public Shared Sub Draw(scale As Numerics.Vector3, rot As Numerics.Quaternion, pos As Numerics.Vector3, color As Color, upper As Numerics.Vector3, lower As Numerics.Vector3)
+ GL.Disable(EnableCap.Blend)
+ GL.Disable(EnableCap.Texture2D)
+ GL.Disable(EnableCap.AlphaTest)
+ 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.X, scale.Y, scale.Z)
+
+ GL.Begin(PrimitiveType.LineLoop)
+ GL.Color4(color)
+
+ GL.Vertex3(upper.X, upper.Y, lower.Z) ' 1
+ GL.Vertex3(lower.X, upper.Y, lower.Z) ' 2
+ GL.Vertex3(lower.X, upper.Y, upper.Z) ' 3
+ GL.Vertex3(upper.X, upper.Y, lower.Z) ' 1
+ GL.Vertex3(upper.X, upper.Y, upper.Z) ' 4
+ GL.Vertex3(lower.X, upper.Y, upper.Z) ' 3
+
+ GL.Vertex3(lower.X, lower.Y, upper.Z) ' 7
+ GL.Vertex3(lower.X, lower.Y, lower.Z) ' 6
+ GL.Vertex3(upper.X, lower.Y, lower.Z) ' 5
+ GL.Vertex3(lower.X, lower.Y, upper.Z) ' 7
+ GL.Vertex3(upper.X, lower.Y, upper.Z) ' 8
+ GL.Vertex3(upper.X, lower.Y, lower.Z) ' 5
+
+ GL.Vertex3(lower.X, upper.Y, lower.Z) ' 2
+ GL.Vertex3(lower.X, lower.Y, lower.Z) ' 6
+ GL.Vertex3(lower.X, upper.Y, upper.Z) ' 3
+ GL.Vertex3(upper.X, lower.Y, upper.Z) ' 8
+ GL.Vertex3(upper.X, upper.Y, upper.Z) ' 4
+ GL.Vertex3(upper.X, lower.Y, lower.Z) ' 5
+
+ GL.Color4(Color.White)
+ GL.End()
+ GL.PopMatrix()
+ GL.Enable(EnableCap.Blend)
+ GL.Enable(EnableCap.Texture2D)
+ GL.Enable(EnableCap.AlphaTest)
+ End Sub
+ End Class
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/ContentPipe.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/ContentPipe.vb
new file mode 100644
index 0000000..8e0d289
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/ContentPipe.vb
@@ -0,0 +1,33 @@
+Imports System
+Imports OpenTK
+Imports OpenTK.Graphics.OpenGL
+Imports System.Drawing
+Imports System.Drawing.Imaging
+
+Namespace RenderingN
+
+ Public Class ContentPipe
+
+ Public Shared Function LoadTexture(filepath As String) As Integer
+ Dim bitmap As New Bitmap(filepath)
+ Return LoadTexture(bitmap)
+ End Function
+
+ Public Shared Function LoadTexture(bitmap As Bitmap) As Integer
+ Dim id As Integer = GL.GenTexture()
+ LoadTexture(bitmap, id)
+ Return id
+ End Function
+
+ Public Shared Sub LoadTexture(bitmap As Bitmap, id As Integer)
+ Dim bmpData As BitmapData = bitmap.LockBits(New Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, Imaging.PixelFormat.Format32bppArgb)
+ GL.BindTexture(TextureTarget.Texture2D, id)
+ GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bitmap.Width, bitmap.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmpData.Scan0)
+ bitmap.UnlockBits(bmpData)
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, CInt(Math.Truncate(TextureMinFilter.Linear)))
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, CInt(Math.Truncate(TextureMagFilter.Linear)))
+ End Sub
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/RenderMode.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/RenderMode.vb
new file mode 100644
index 0000000..0205862
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/RenderMode.vb
@@ -0,0 +1,10 @@
+Namespace RenderingN
+
+ Public Enum RenderMode As Byte
+ None = &H0
+ Fill = &H1
+ Outline = &H2
+ FillOutline = Fill Or Outline
+ End Enum
+
+End Namespace
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/Renderer.vb b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/Renderer.vb
new file mode 100644
index 0000000..86eb404
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/Rendering/Renderer.vb
@@ -0,0 +1,456 @@
+Imports System.Drawing
+Imports System.Threading
+Imports System.Windows.Forms
+Imports OpenTK
+Imports OpenTK.Graphics.OpenGL
+Imports Pilz.S3DFileParser
+
+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 verts 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 texID As Integer
+ Dim isEmptyTexture As Boolean = l.Material?.Image Is Nothing
+ Dim isEmptyColor As Boolean = l.Material?.Color Is Nothing
+
+ If (mode And RenderMode.Fill) = RenderMode.Fill Then
+ texID = If(isEmptyTexture, If(isEmptyColor, dicTextureIDs(emptyTexture), dicColorIDs(l.Material.Color)), dicTextureIDs(l.Material.Image))
+
+ GL.BindTexture(TextureTarget.Texture2D, texID)
+
+ 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
+ texID = dicTextureIDs(lineTexture)
+ GL.BindTexture(TextureTarget.Texture2D, texID)
+ Else
+ texID = If(isEmptyTexture, If(isEmptyColor, dicTextureIDs(emptyTexture), dicColorIDs(l.Material.Color)), dicTextureIDs(l.Material.Image))
+ GL.BindTexture(TextureTarget.Texture2D, texID)
+
+ 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))
+
+ GL.Color4(Color.FromArgb(&H20000000 + (iMesh << 16) + iFace)) '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
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/app.config b/Pilz.Drawing.Drawing3D.OpenGLRenderer/app.config
new file mode 100644
index 0000000..d4f722e
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/app.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Drawing.Drawing3D.OpenGLRenderer/packages.config b/Pilz.Drawing.Drawing3D.OpenGLRenderer/packages.config
new file mode 100644
index 0000000..d8280d7
--- /dev/null
+++ b/Pilz.Drawing.Drawing3D.OpenGLRenderer/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.IO/ManagedPipes/ManagedPipeServer.vb b/Pilz.IO/ManagedPipes/ManagedPipeServer.vb
index 9d50580..54222fe 100644
--- a/Pilz.IO/ManagedPipes/ManagedPipeServer.vb
+++ b/Pilz.IO/ManagedPipes/ManagedPipeServer.vb
@@ -4,8 +4,8 @@ Imports Pilz.Threading
Public Class ManagedPipeServer : Inherits ManagedPipe
- 'Pro Verbindung(sanfrage) wird ein Client-Objekt generiert, das den Datenaustausch dieser Verbindung abwickelt
- Private _Clients As New List(Of ManagedPipeClient)
+ 'Pro Verbindung (Anfrage) wird ein Client-Objekt generiert, das den Datenaustausch dieser Verbindung abwickelt
+ Public ReadOnly Property Clients As New List(Of ManagedPipeClient)
Private ReadOnly pipeName As String = ""
Private ReadOnly maxNumbersOfServerInstances As Integer
Private numberOfStartedServerInstances As Integer = 0
@@ -70,22 +70,16 @@ Public Class ManagedPipeServer : Inherits ManagedPipe
OnStatusMessage(e)
End Sub
-#End Region '_Clients-Ereignisverarbeitung
+#End Region
Public Overrides Function SendAsnyc(bytes() As Byte) As Task
Return Task.Run(Sub() Send(bytes))
End Function
Public Overrides Sub Send(data As Byte())
- Console.WriteLine("Sending Data ...")
-
- 'OnRetriveData(New DataEventargs(data)) ' anzeigen
-
- For Each client As ManagedPipeClient In _Clients ' an alle versenden
+ For Each client As ManagedPipeClient In _Clients 'an alle versenden
client.Send(data)
Next
-
- Console.WriteLine("Data send!")
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
diff --git a/Pilz.IO/Pilz.IO.vbproj b/Pilz.IO/Pilz.IO.vbproj
index d70fe2d..bdc16cc 100644
--- a/Pilz.IO/Pilz.IO.vbproj
+++ b/Pilz.IO/Pilz.IO.vbproj
@@ -128,7 +128,7 @@
{d9c8655e-4f1c-4348-a51c-ab00fd9a14bb}
- CrossThreads
+ Pilz.Threading
diff --git a/Pilz.LicenseHelper/AsposeModifyInMemory.cs b/Pilz.LicenseHelper/AsposeModifyInMemory.cs
new file mode 100644
index 0000000..ce93850
--- /dev/null
+++ b/Pilz.LicenseHelper/AsposeModifyInMemory.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Xml;
+
+namespace Pilz.LicenseHelper
+{
+ public static class AsposeModifyInMemory
+ {
+ private static string AsposeList = "Aspose.3D.dll, Aspose.BarCode.dll, Aspose.BarCode.Compact.dll, Aspose.BarCode.WPF.dll, Aspose.Cells.GridDesktop.dll, Aspose.Cells.GridWeb.dll, Aspose.CAD.dll, Aspose.Cells.dll, Aspose.Diagram.dll, Aspose.Email.dll, Aspose.Imaging.dll, Aspose.Note.dll, Aspose.OCR.dll, Aspose.Pdf.dll, Aspose.Slides.dll, Aspose.Tasks.dll, Aspose.Words.dll";
+
+ public static void ActivateMemoryPatching()
+ {
+ Assembly[] arr = AppDomain.CurrentDomain.GetAssemblies();
+ foreach (Assembly assembly in arr)
+ {
+ if (AsposeList.IndexOf(assembly.FullName.Split(',')[0] + ".dll") != -1)
+ ActivateForAssembly(assembly);
+ }
+ AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(ActivateOnLoad);
+ }
+
+ private static void ActivateOnLoad(object sender, AssemblyLoadEventArgs e)
+ {
+ if (AsposeList.IndexOf(e.LoadedAssembly.FullName.Split(',')[0] + ".dll") != -1)
+ ActivateForAssembly(e.LoadedAssembly);
+ }
+
+ private static void ActivateForAssembly(Assembly assembly)
+ {
+ MethodInfo miLicensed1 = typeof(AsposeModifyInMemory).GetMethod("InvokeMe1", BindingFlags.NonPublic | BindingFlags.Static);
+ MethodInfo miLicensed2 = typeof(AsposeModifyInMemory).GetMethod("InvokeMe2", BindingFlags.NonPublic | BindingFlags.Static);
+ MethodInfo miEvaluation = null;
+
+ Dictionary miDict = new Dictionary()
+ {
+ {"System.DateTime" , miLicensed1},
+ {"System.Xml.XmlElement", miLicensed2}
+ };
+
+ Type[] arrType = null;
+ bool isFound = false;
+ int nCount = 0;
+
+ try
+ {
+ arrType = assembly.GetTypes();
+ }
+ catch (ReflectionTypeLoadException err)
+ {
+ arrType = err.Types;
+ }
+
+
+ foreach (Type type in arrType)
+ {
+ if (isFound) break;
+
+ if (type == null) continue;
+
+ MethodInfo[] arrMInfo = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static);
+
+ foreach (MethodInfo info in arrMInfo)
+ {
+ if (isFound) break;
+
+ try
+ {
+ string strMethod = info.ToString();
+ if ((strMethod.IndexOf("(System.Xml.XmlElement, System.String)") > 0) && (miDict.ContainsKey(info.ReturnType.ToString())))
+ {
+ miEvaluation = info;
+ MemoryPatching(miEvaluation, miDict[miEvaluation.ReturnType.ToString()]);
+ nCount++;
+
+ if ((assembly.FullName.IndexOf("Aspose.3D") != -1) && (nCount == 2))
+ {
+ isFound = true;
+ break;
+ }
+ }
+ }
+ catch
+ {
+ throw new InvalidOperationException("MemoryPatching for \"" + assembly.FullName + "\" failed !");
+ }
+ }
+ }
+
+ String[] aParts = assembly.FullName.Split(',');
+ string fName = aParts[0];
+ if (fName.IndexOf("Aspose.BarCode.") != -1)
+ fName = "Aspose.BarCode";
+ else if (fName.IndexOf("Aspose.3D") != -1)
+ fName = "Aspose.ThreeD";
+
+ try
+ {
+ Type type2 = assembly.GetType(fName + ".License");
+ MethodInfo mi = type2.GetMethod("SetLicense", new Type[] { typeof(Stream) });
+ string LData = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPExpY2Vuc2U+CiAgPERhdGE+CiAgICA8TGljZW5zZWRUbz5MaWNlbnNlZTwvTGljZW5zZWRUbz4KICAgIDxFbWFpbFRvPmxpY2Vuc2VlQGVtYWlsLmNvbTwvRW1haWxUbz4KICAgIDxMaWNlbnNlVHlwZT5EZXZlbG9wZXIgT0VNPC9MaWNlbnNlVHlwZT4KICAgIDxMaWNlbnNlTm90ZT5MaW1pdGVkIHRvIDEwMDAgZGV2ZWxvcGVyLCB1bmxpbWl0ZWQgcGh5c2ljYWwgbG9jYXRpb25zPC9MaWNlbnNlTm90ZT4KICAgIDxPcmRlcklEPjc4NDM3ODU3Nzg1PC9PcmRlcklEPgogICAgPFVzZXJJRD4xMTk3ODkyNDM3OTwvVXNlcklEPgogICAgPE9FTT5UaGlzIGlzIGEgcmVkaXN0cmlidXRhYmxlIGxpY2Vuc2U8L09FTT4KICAgIDxQcm9kdWN0cz4KICAgICAgPFByb2R1Y3Q+QXNwb3NlLlRvdGFsIFByb2R1Y3QgRmFtaWx5PC9Qcm9kdWN0PgogICAgPC9Qcm9kdWN0cz4KICAgIDxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT4KICAgIDxTZXJpYWxOdW1iZXI+e0YyQjk3MDQ1LTFCMjktNEIzRi1CRDUzLTYwMUVGRkExNUFBOX08L1NlcmlhbE51bWJlcj4KICAgIDxTdWJzY3JpcHRpb25FeHBpcnk+MjA5OTEyMzE8L1N1YnNjcmlwdGlvbkV4cGlyeT4KICAgIDxMaWNlbnNlVmVyc2lvbj4zLjA8L0xpY2Vuc2VWZXJzaW9uPgogIDwvRGF0YT4KICA8U2lnbmF0dXJlPlFYTndiM05sTGxSdmRHRnNJRkJ5YjJSMVkzUWdSbUZ0YVd4NTwvU2lnbmF0dXJlPgo8L0xpY2Vuc2U+";
+ Stream stream = new MemoryStream(Convert.FromBase64String(LData));
+ stream.Seek(0, SeekOrigin.Begin);
+ mi.Invoke(Activator.CreateInstance(type2, null), new Stream[] { stream });
+ }
+ catch
+ {
+ throw new InvalidOperationException("SetLicense for \"" + assembly.FullName + "\" failed !");
+ }
+
+ }
+
+
+ private static DateTime InvokeMe1(XmlElement element, string name)
+ {
+ return DateTime.MaxValue;
+ }
+
+
+ private static XmlElement InvokeMe2(XmlElement element, string name)
+ {
+ if (element.LocalName == "License")
+ {
+ string License64 = "PERhdGE+PExpY2Vuc2VkVG8+R3JvdXBEb2NzPC9MaWNlbnNlZFRvPjxMaWNlbnNlVHlwZT5TaXRlIE9FTTwvTGljZW5zZVR5cGU+PExpY2Vuc2VOb3RlPkxpbWl0ZWQgdG8gMTAgZGV2ZWxvcGVyczwvTGljZW5zZU5vdGU+PE9yZGVySUQ+MTMwNzI0MDQwODQ5PC9PcmRlcklEPjxPRU0+VGhpcyBpcyBhIHJlZGlzdHJpYnV0YWJsZSBsaWNlbnNlPC9PRU0+PFByb2R1Y3RzPjxQcm9kdWN0PkFzcG9zZS5Ub3RhbDwvUHJvZHVjdD48L1Byb2R1Y3RzPjxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT48U2VyaWFsTnVtYmVyPjliNTc5NTAxLTUyNjEtNDIyMC04NjcwLWZjMmQ4Y2NkZDkwYzwvU2VyaWFsTnVtYmVyPjxTdWJzY3JpcHRpb25FeHBpcnk+MjAxNDA3MjQ8L1N1YnNjcmlwdGlvbkV4cGlyeT48TGljZW5zZVZlcnNpb24+Mi4yPC9MaWNlbnNlVmVyc2lvbj48L0RhdGE+PFNpZ25hdHVyZT5udFpocmRoL3I0QS81ZFpsU2dWYnhac0hYSFBxSjZ5UVVYa0RvaW4vS2lVZWhUUWZET0lQdHdzUlR2NmRTUVplOVdXekNnV3RGdkdROWpmR2QySmF4YUQvbkx1ZEk2R0VVajhqeVhUMG4vbWRrMEF1WVZNYlBXRjJYd3dSTnFlTmRrblYyQjhrZVFwbDJ2RzZVbnhxS2J6VVFxS2Rhc1pzZ2w1Q0xqSFVEWms9PC9TaWduYXR1cmU+";
+ element.InnerXml = new UTF8Encoding().GetString(Convert.FromBase64String(License64));
+ }
+
+ if (element.LocalName == "BlackList")
+ {
+ string BlackList64 = "PERhdGE+PC9EYXRhPjxTaWduYXR1cmU+cUJwMEx1cEVoM1ZnOWJjeS8vbUVXUk9KRWZmczRlY25iTHQxYlNhanU2NjY5RHlad09FakJ1eEdBdVBxS1hyd0x5bmZ5VWplYUNGQ0QxSkh2RVUxVUl5eXJOTnBSMXc2NXJIOUFyUCtFbE1lVCtIQkZ4NFMzckFVMnd6dkxPZnhGeU9DQ0dGQ2UraTdiSHlGQk44WHp6R1UwdGRPMGR1RTFoRTQ5M1RNY3pRPTwvU2lnbmF0dXJlPg==";
+ element.InnerXml = new UTF8Encoding().GetString(Convert.FromBase64String(BlackList64));
+ }
+
+ XmlNodeList elementsByTagName = element.GetElementsByTagName(name);
+ if (elementsByTagName.Count <= 0)
+ {
+ return null;
+ }
+
+ return (XmlElement)elementsByTagName[0];
+ }
+
+
+ private static unsafe void MemoryPatching(MethodBase miEvaluation, MethodBase miLicensed)
+ {
+ IntPtr IntPtrEval = GetMemoryAddress(miEvaluation);
+ IntPtr IntPtrLicensed = GetMemoryAddress(miLicensed);
+
+ if (IntPtr.Size == 8)
+ *((long*)IntPtrEval.ToPointer()) = *((long*)IntPtrLicensed.ToPointer());
+ else
+ *((int*)IntPtrEval.ToPointer()) = *((int*)IntPtrLicensed.ToPointer());
+
+ }
+
+
+ private static unsafe IntPtr GetMemoryAddress(MethodBase mb)
+ {
+ RuntimeHelpers.PrepareMethod(mb.MethodHandle);
+
+ if ((Environment.Version.Major >= 4) || ((Environment.Version.Major == 2) && (Environment.Version.MinorRevision >= 3053)))
+ {
+ return new IntPtr(((int*)mb.MethodHandle.Value.ToPointer() + 2));
+ }
+
+ UInt64* location = (UInt64*)(mb.MethodHandle.Value.ToPointer());
+ int index = (int)(((*location) >> 32) & 0xFF);
+ if (IntPtr.Size == 8)
+ {
+ ulong* classStart = (ulong*)mb.DeclaringType.TypeHandle.Value.ToPointer();
+ ulong* address = classStart + index + 10;
+ return new IntPtr(address);
+ }
+ else
+ {
+ uint* classStart = (uint*)mb.DeclaringType.TypeHandle.Value.ToPointer();
+ uint* address = classStart + index + 10;
+ return new IntPtr(address);
+ }
+ }
+ }
+}
diff --git a/Pilz.LicenseHelper/Pilz.LicenseHelper.csproj b/Pilz.LicenseHelper/Pilz.LicenseHelper.csproj
new file mode 100644
index 0000000..bd103e8
--- /dev/null
+++ b/Pilz.LicenseHelper/Pilz.LicenseHelper.csproj
@@ -0,0 +1,49 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}
+ Library
+ Properties
+ Pilz.LicenseHelper
+ Pilz.LicenseHelper
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.LicenseHelper/Properties/AssemblyInfo.cs b/Pilz.LicenseHelper/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0d2d071
--- /dev/null
+++ b/Pilz.LicenseHelper/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Allgemeine Informationen über eine Assembly werden über die folgenden
+// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+// die einer Assembly zugeordnet sind.
+[assembly: AssemblyTitle("LicenseHelper")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("DRSN")]
+[assembly: AssemblyProduct("LicenseHelper")]
+[assembly: AssemblyCopyright("Copyright © DRSN 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
+// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
+// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
+[assembly: ComVisible(false)]
+
+// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
+[assembly: Guid("67593ff7-c1d1-4529-98c4-61cbd0615f08")]
+
+// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+//
+// Hauptversion
+// Nebenversion
+// Buildnummer
+// Revision
+//
+// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+// indem Sie "*" wie unten gezeigt eingeben:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Pilz.Simple3DFileParser/App.config b/Pilz.Simple3DFileParser/App.config
new file mode 100644
index 0000000..bc3672d
--- /dev/null
+++ b/Pilz.Simple3DFileParser/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Simple3DFileParser/FileParser/Aspose3DLoader.vb b/Pilz.Simple3DFileParser/FileParser/Aspose3DLoader.vb
new file mode 100644
index 0000000..67806f0
--- /dev/null
+++ b/Pilz.Simple3DFileParser/FileParser/Aspose3DLoader.vb
@@ -0,0 +1,250 @@
+Imports System.Globalization
+Imports System.IO
+Imports System.Threading
+Imports Aspose.ThreeD
+Imports Aspose.ThreeD.Entities
+Imports Aspose.ThreeD.Formats
+Imports Aspose.ThreeD.Shading
+Imports Aspose.ThreeD.Utilities
+
+Namespace Aspose3DModule
+
+ Public Class Aspose3DLoader
+
+ Private Shared hasActivatedMemoryPatching As Boolean = False
+
+ Private Shared Sub ActivateMemoryPatching()
+ If Not hasActivatedMemoryPatching Then
+ LicenseHelper.AsposeModifyInMemory.ActivateMemoryPatching()
+ hasActivatedMemoryPatching = True
+ End If
+ End Sub
+
+ Public Shared Function FromFile(fileName As String, LoadMaterials As Boolean, UpAxis As UpAxis) As Object3D
+ ActivateMemoryPatching()
+
+ 'Create new Model
+ Dim obj3d As New Object3D
+
+ 'Create new temporary CultureInfo
+ Dim curThread As Thread = Thread.CurrentThread
+ Dim curCultInfo As CultureInfo = curThread.CurrentCulture
+ Dim newCultInfo As New CultureInfo(curCultInfo.Name)
+ newCultInfo.NumberFormat.NumberDecimalSeparator = "."
+ newCultInfo.NumberFormat.PercentDecimalSeparator = "."
+ newCultInfo.NumberFormat.CurrencyDecimalSeparator = "."
+ newCultInfo.NumberFormat.NumberGroupSeparator = ","
+ newCultInfo.NumberFormat.PercentGroupSeparator = ","
+ newCultInfo.NumberFormat.CurrencyGroupSeparator = ","
+ curThread.CurrentCulture = newCultInfo
+
+ 'Load Model from file
+ Dim scene As New Scene(fileName)
+
+ 'Reset Cultur-Info
+ curThread.CurrentCulture = curCultInfo
+
+ 'Triangulate the Model
+ PolygonModifier.Triangulate(scene)
+
+ 'Create Dictionary for Materials
+ Dim dicMaterials As New Dictionary(Of Aspose.ThreeD.Shading.Material, Material)
+
+ 'Create List of all avaiable Map-States
+ Dim MapNames As String() = {Aspose.ThreeD.Shading.Material.MapDiffuse, Aspose.ThreeD.Shading.Material.MapAmbient, Aspose.ThreeD.Shading.Material.MapSpecular, Aspose.ThreeD.Shading.Material.MapEmissive, Aspose.ThreeD.Shading.Material.MapNormal}
+ Dim ColorNames As String() = {"DiffuseColor", "AmbientColor", "SpecularColor", "EmissiveColor"}
+
+ For Each node As Node In scene.RootNode.ChildNodes
+
+ 'Add new Materials, if not added
+ For Each mat As Aspose.ThreeD.Shading.Material In node.Materials
+ If Not dicMaterials.ContainsKey(mat) Then
+
+ 'Create new Material
+ Dim newMat As New Material
+
+ 'Get TextureBase
+ Dim texBase As TextureBase = Nothing
+ Dim curmnindex As Byte = 0
+ Do While texBase Is Nothing AndAlso curmnindex < MapNames.Length
+ texBase = mat.GetTexture(MapNames(curmnindex))
+ curmnindex += 1
+ Loop
+
+ If texBase IsNot Nothing Then
+ If LoadMaterials Then
+ 'Get Texture Image
+ Dim imgFile As String = texBase.GetPropertyValue("FileName")
+ imgFile = imgFile.Replace("/", "\")
+
+ 'Load and set Image
+ If imgFile <> "" Then
+ Dim fs As New FileStream(imgFile, FileMode.Open, FileAccess.Read)
+ newMat.Image = Image.FromStream(fs)
+ fs.Close()
+ End If
+ End If
+ End If
+
+ 'Get Texture Color
+ Dim texcol As Vector3? = Nothing
+ Dim curcnindex As Byte = 0
+ Do While texcol Is Nothing AndAlso curcnindex < ColorNames.Length
+ texcol = mat.GetPropertyValue(ColorNames(curcnindex))
+ curcnindex += 1
+ Loop
+
+ If texcol IsNot Nothing Then
+ newMat.Color = Color.FromArgb(texcol?.x, texcol?.y, texcol?.z)
+ End If
+
+ 'Add Material to Object3D
+ obj3d.Materials.Add(mat.Name, newMat)
+
+ 'Add Dictionary-Entry
+ dicMaterials.Add(mat, newMat)
+
+ End If
+ Next
+
+ 'Get Aspose-Mesh
+ Dim curMesh As Entities.Mesh = node.GetEntity(Of Entities.Mesh)
+
+ If curMesh IsNot Nothing Then
+
+ 'Create new Mesh
+ Dim newMesh As New Mesh
+
+ 'Create Vertices
+ For Each vert As Vector4 In curMesh.ControlPoints
+ 'Create new Vertex
+ Dim newVert As New Vertex
+
+ 'Set Vertex Data
+ newVert.X = vert.x
+ newVert.Y = vert.y
+ newVert.Z = vert.z
+
+ 'Add new Vertex
+ newMesh.Vertices.Add(newVert)
+ Next
+
+ 'Create Normals
+ Dim veNormals As VertexElementNormal = curMesh.GetElement(VertexElementType.Normal)
+ If veNormals IsNot Nothing Then
+ For Each n As Vector4 In veNormals.Data
+ 'Create new Normal
+ Dim newNormal As New Normal
+
+ 'Set Normal Data
+ newNormal.X = n.x
+ newNormal.Y = n.y
+ newNormal.Z = n.z
+
+ 'Add new Normal
+ newMesh.Normals.Add(newNormal)
+ Next
+ End If
+
+ 'Create Normals
+ Dim veUVs As VertexElementUV = curMesh.GetElement(VertexElementType.UV)
+ If veUVs IsNot Nothing Then
+ For Each uv As Vector4 In veUVs.Data
+ 'Create new UV
+ Dim newUV As New UV
+
+ 'Set UV Data
+ newUV.U = uv.x
+ newUV.V = uv.y
+
+ 'Add new UV
+ newMesh.UVs.Add(newUV)
+ Next
+ End If
+
+ 'Create Normals
+ Dim veVertexColor As VertexElementVertexColor = curMesh.GetElement(VertexElementType.VertexColor)
+ If veVertexColor IsNot Nothing Then
+ For Each n As Vector4 In veVertexColor.Data
+ 'Create new Normal
+ Dim newVC As New VertexColor
+
+ 'Set Normal Data
+ newVC.R = n.x
+ newVC.G = n.y
+ newVC.B = n.z
+ newVC.A = n.w
+
+ 'Add new Normal
+ newMesh.VertexColors.Add(newVC)
+ Next
+ End If
+
+ 'Get Material-Indicies
+ Dim veMaterials As VertexElementMaterial = curMesh.GetElement(VertexElementType.Material)
+
+ 'Definde Index for VertexElement.Indicies
+ Dim veIndex As Integer = 0
+
+ 'Build Polygones
+ For iPoly = 0 To curMesh.Polygons.Count - 1
+ 'Get current Polygon
+ Dim poly As Integer() = curMesh.Polygons(iPoly)
+
+ 'Create new Face
+ Dim f As New Face
+
+ 'Set Texture, if avaiable
+ If veMaterials IsNot Nothing Then
+ f.Material = dicMaterials(node.Materials(veMaterials.Indices(iPoly)))
+ ElseIf node.Material IsNot Nothing Then
+ f.Material = dicMaterials(node.Material)
+ End If
+
+ For Each index As Integer In poly
+ 'Create new Point
+ Dim p As New Point
+
+ 'Set Vertex
+ p.Vertex = newMesh.Vertices(index)
+
+ 'Set Normal
+ If veNormals IsNot Nothing Then
+ p.Normal = newMesh.Normals(veNormals.Indices(veIndex))
+ End If
+
+ 'Set UV
+ If veUVs IsNot Nothing Then
+ p.UV = newMesh.UVs(veUVs.Indices(veIndex))
+ End If
+
+ 'Set Vertex Color
+ If veVertexColor IsNot Nothing Then
+ p.VertexColor = newMesh.VertexColors(veVertexColor.Indices(veIndex))
+ End If
+
+ 'Add new Point
+ f.Points.Add(p)
+
+ 'Increment VertexElementIndicies-Index
+ veIndex += 1
+ Next
+
+ 'Add new Face
+ newMesh.Faces.Add(f)
+ Next
+
+ 'Add new Mesh
+ obj3d.Meshes.Add(newMesh)
+
+ End If
+
+ Next
+
+ 'Return the new Object3D
+ Return obj3d
+ End Function
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Simple3DFileParser/FileParser/AssimpLoader.vb b/Pilz.Simple3DFileParser/FileParser/AssimpLoader.vb
new file mode 100644
index 0000000..f5df5f5
--- /dev/null
+++ b/Pilz.Simple3DFileParser/FileParser/AssimpLoader.vb
@@ -0,0 +1,391 @@
+Imports System.IO
+Imports Assimp
+Imports Assimp.Unmanaged
+
+Namespace AssimpModule
+
+ Public Class AssimpLoader
+
+ Public Shared PathToAssimpLib32 As String = "Assimp32.dll"
+ Public Shared PathToAssimpLib64 As String = "Assimp64.dll"
+
+ Friend Shared Sub LoadAssimpLibs()
+ If Not AssimpLibrary.Instance.IsLibraryLoaded Then
+ AssimpLibrary.Instance.LoadLibrary(PathToAssimpLib32, PathToAssimpLib64)
+ End If
+ End Sub
+
+ Public Shared Function FromFile(fileName As String, LoadMaterials As Boolean, UpAxis As UpAxis) As Object3D
+ Dim LoadedImages As New Dictionary(Of String, Image)
+ Dim newObj As New Object3D
+ Dim daeMdl As Scene = Nothing
+ Dim ac As New AssimpContext
+ Dim channelIndicies As New Dictionary(Of Material, Integer)
+
+ daeMdl = ac.ImportFile(fileName, PostProcessPreset.TargetRealTimeMaximumQuality Or PostProcessSteps.Triangulate)
+
+ For Each et As EmbeddedTexture In daeMdl.Textures
+ If et.HasCompressedData Then
+ Dim newMat As New Material
+
+ Dim ms As New MemoryStream(et.CompressedData)
+ newMat.Image = Image.FromStream(ms)
+ ms.Close()
+
+ newObj.Materials.Add("tex_" & daeMdl.Textures.IndexOf(et), newMat)
+ End If
+ Next
+
+ For Each mat As Assimp.Material In daeMdl.Materials
+ Dim newMat As New Material
+ Dim texSlot As TextureSlot? = Nothing
+ Dim col4d As Color4D? = Nothing
+
+ newMat.Opacity = mat.Opacity
+
+ Select Case True
+ Case mat.HasTextureNormal
+ texSlot = mat.TextureNormal
+ Case mat.HasTextureDiffuse
+ texSlot = mat.TextureDiffuse
+ Case mat.HasTextureAmbient
+ texSlot = mat.TextureAmbient
+ Case mat.HasTextureSpecular
+ texSlot = mat.TextureSpecular
+ End Select
+
+ Select Case True
+ Case mat.HasColorDiffuse
+ col4d = mat.ColorDiffuse
+ Case mat.HasColorAmbient
+ col4d = mat.ColorAmbient
+ Case mat.HasColorSpecular
+ col4d = mat.ColorSpecular
+ End Select
+
+ If texSlot IsNot Nothing Then
+ Dim filePath As String = texSlot.Value.FilePath
+
+ If LoadMaterials Then
+ If filePath <> "" Then
+ Dim combiPath As String = Path.Combine(Path.GetDirectoryName(fileName), filePath)
+ If File.Exists(combiPath) Then
+ newMat.Image = LoadImage(combiPath, LoadedImages)
+ ElseIf File.Exists(filePath) Then
+ newMat.Image = LoadImage(filePath, LoadedImages)
+ End If
+ ElseIf texSlot.Value.TextureIndex > -1 AndAlso daeMdl.Textures.Count > texSlot.Value.TextureIndex Then
+ Dim et As EmbeddedTexture = daeMdl.Textures(texSlot.Value.TextureIndex)
+ If et.HasCompressedData Then
+ Dim ms As New MemoryStream(et.CompressedData)
+ newMat.Image = Image.FromStream(ms)
+ ms.Close()
+ End If
+ End If
+ End If
+
+ channelIndicies.Add(newMat, texSlot.Value.UVIndex)
+ End If
+
+ If col4d IsNot Nothing Then
+ newMat.Color = Color.FromArgb(col4d.Value.R * 255, col4d.Value.G * 255, col4d.Value.B * 255)
+ End If
+
+ newObj.Materials.Add(mat.Name, newMat)
+ Next
+
+ Dim newMesh As New Mesh
+ newObj.Meshes.Add(newMesh)
+
+ Dim dicVertices As New Dictionary(Of Vector3D, Vertex)
+ Dim dicNormals As New Dictionary(Of Vector3D, Normal)
+ Dim dicUVs As New Dictionary(Of Vector3D, UV)
+ Dim dicVertexColors As New Dictionary(Of Color4D, VertexColor)
+
+ For Each m As Assimp.Mesh In daeMdl.Meshes
+ Dim curMat As Material
+ If m.MaterialIndex > -1 AndAlso newObj.Materials.Count > m.MaterialIndex Then
+ curMat = newObj.Materials.ElementAt(m.MaterialIndex).Value
+ Else
+ curMat = Nothing
+ End If
+
+ For Each n As Vector3D In m.Normals
+ If Not dicNormals.ContainsKey(n) Then
+ Dim newNormal As New Normal
+
+ Select Case UpAxis
+ Case UpAxis.Y
+ newNormal.X = n.X
+ newNormal.Y = n.Y
+ newNormal.Z = n.Z
+ Case UpAxis.Z
+ newNormal.X = n.Y
+ newNormal.Y = n.Z
+ newNormal.Z = n.X
+ End Select
+
+ newMesh.Normals.Add(newNormal)
+ dicNormals.Add(n, newNormal)
+ End If
+ Next
+
+ For Each v As Vector3D In m.Vertices
+ If Not dicVertices.ContainsKey(v) Then
+ Dim newVert As New Vertex
+
+ Select Case UpAxis
+ Case UpAxis.Y
+ newVert.X = v.X
+ newVert.Y = v.Y
+ newVert.Z = v.Z
+ Case UpAxis.Z
+ newVert.X = v.Y
+ newVert.Y = v.Z
+ newVert.Z = v.X
+ End Select
+
+ newMesh.Vertices.Add(newVert)
+ dicVertices.Add(v, newVert)
+ End If
+ Next
+
+ For Each uvList As List(Of Vector3D) In m.TextureCoordinateChannels
+ For Each uv As Vector3D In uvList
+ If Not dicUVs.ContainsKey(uv) Then
+ Dim newUV As New UV
+
+ newUV.U = uv.X
+ newUV.V = uv.Y
+
+ newMesh.UVs.Add(newUV)
+ dicUVs.Add(uv, newUV)
+ End If
+ Next
+ Next
+
+ For Each vcList As List(Of Color4D) In m.VertexColorChannels
+ For Each vc As Color4D In vcList
+ If Not dicVertexColors.ContainsKey(vc) Then
+ Dim newVC As New VertexColor
+
+ newVC.R = vc.R
+ newVC.G = vc.G
+ newVC.B = vc.B
+ newVC.A = vc.A
+
+ newMesh.VertexColors.Add(newVC)
+ dicVertexColors.Add(vc, newVC)
+ End If
+ Next
+ Next
+
+ For Each f As Assimp.Face In m.Faces
+ If f.HasIndices Then
+ Dim newFace As New Face With {.Material = curMat}
+
+ For Each index As Integer In f.Indices
+ If index > -1 Then
+ Dim newPoint As New Point
+
+ If m.HasVertices Then
+ newPoint.Vertex = dicVertices(m.Vertices(index))
+ End If
+
+ If m.HasNormals Then
+ newPoint.Normal = dicNormals(m.Normals(index))
+ End If
+
+ If curMat IsNot Nothing AndAlso channelIndicies.ContainsKey(curMat) Then
+ Dim tkey As Integer = channelIndicies(curMat)
+
+ If m.HasTextureCoords(tkey) Then
+ newPoint.UV = dicUVs(m.TextureCoordinateChannels(tkey)(index))
+ End If
+
+ If m.HasVertexColors(tkey) Then
+ newPoint.VertexColor = dicVertexColors(m.VertexColorChannels(tkey)(index))
+ End If
+ End If
+
+ newFace.Points.Add(newPoint)
+ End If
+ Next
+
+ If newFace.Points.Count = 3 Then
+ newMesh.Faces.Add(newFace)
+ End If
+ End If
+ Next
+ Next
+
+ Return newObj
+ End Function
+
+ Public Shared Sub ToFile(fileName As String, obj As Object3D)
+ Dim mdl As New Scene
+ Dim dicMatIndex As New Dictionary(Of Material, Integer)
+
+ Dim texDir As String = ""
+ If obj.Materials.Count > 0 Then
+ texDir = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName))
+ If Not Directory.Exists(texDir) Then
+ Directory.CreateDirectory(texDir)
+ End If
+ End If
+
+ For Each kvp As KeyValuePair(Of String, Material) In obj.Materials
+ Dim mat As New Assimp.Material
+
+ mat.Name = If(kvp.Key <> "", kvp.Key, "_" & mdl.Materials.Count)
+ mat.Opacity = mat.Opacity
+
+ Dim texslot As New TextureSlot
+ texslot.TextureIndex = mdl.Textures.Count
+ texslot.TextureType = TextureType.Diffuse
+ texslot.UVIndex = 0
+
+ Dim ms As New MemoryStream
+ kvp.Value.Image.Save(ms, Imaging.ImageFormat.Png)
+ 'Dim tex As New EmbeddedTexture("png", ms.GetBuffer)
+ ms.Close()
+
+ If kvp.Value.Image IsNot Nothing Then
+ texslot.FilePath = Path.Combine(texDir, mat.Name & ".png")
+ File.WriteAllBytes(texslot.FilePath, ms.GetBuffer)
+ End If
+
+ 'mdl.Textures.Add(tex)
+ mat.AddMaterialTexture(texslot)
+ mdl.Materials.Add(mat)
+
+ If kvp.Value.Color IsNot Nothing Then
+ With kvp.Value.Color.Value
+ mat.ColorDiffuse = New Color4D(.R / 255, .G / 255, .B / 255, 1)
+ End With
+ End If
+
+ dicMatIndex.Add(kvp.Value, mdl.Materials.Count - 1)
+ Next
+
+ Dim dicTexMesh As New Dictionary(Of Material, Assimp.Mesh)
+ Dim dicMeshDicVertIndex As New Dictionary(Of Assimp.Mesh, Dictionary(Of Vertex, Integer))
+ Dim dicCounter As New Dictionary(Of Assimp.Mesh, Integer)
+
+ For Each mesh As Mesh In obj.Meshes
+ For Each f As Face In mesh.Faces
+ Dim m As Assimp.Mesh
+
+ If dicTexMesh.ContainsKey(f.Material) Then
+ m = dicTexMesh(f.Material)
+ Else
+ m = New Assimp.Mesh("Mesh_" & mdl.MeshCount + 1)
+ m.PrimitiveType = PrimitiveType.Triangle
+ If dicMatIndex.ContainsKey(f.Material) Then
+ m.MaterialIndex = dicMatIndex(f.Material)
+ End If
+ mdl.Meshes.Add(m)
+ dicTexMesh.Add(f.Material, m)
+ dicMeshDicVertIndex.Add(m, New Dictionary(Of Vertex, Integer))
+ dicCounter.Add(m, 0)
+ End If
+
+ Dim newFace As New Assimp.Face
+
+ For Each p As Point In f.Points
+ newFace.Indices.Add(dicCounter(m))
+
+ If p.Vertex IsNot Nothing Then
+ Dim vert As New Vector3D
+ vert.X = p.Vertex.X
+ vert.Y = p.Vertex.Y
+ vert.Z = p.Vertex.Z
+ m.Vertices.Add(vert)
+ Else
+ m.Vertices.Add(New Vector3D(0, 0, 0))
+ End If
+
+ If p.Normal IsNot Nothing Then
+ Dim norm As New Vector3D
+ norm.X = p.Normal.X
+ norm.Y = p.Normal.Y
+ norm.Z = p.Normal.Z
+ m.Normals.Add(norm)
+ Else
+ m.Normals.Add(New Vector3D(0, 0, 0))
+ End If
+
+ 'If p.UV IsNot Nothing Then
+ ' Dim uv As New Vector3D
+ ' uv.X = p.UV.U
+ ' uv.Y = p.UV.V
+ ' m.TextureCoordinateChannels(0).Add(uv)
+ 'Else
+ ' m.TextureCoordinateChannels(0).Add(New Vector3D(0, 0, 0))
+ 'End If
+
+ 'If p.VertexColor IsNot Nothing Then
+ ' Dim vc As New Color4D
+ ' vc.R = p.VertexColor.R
+ ' vc.G = p.VertexColor.G
+ ' vc.B = p.VertexColor.B
+ ' vc.A = p.VertexColor.A
+ ' m.VertexColorChannels(0).Add(vc)
+ 'Else
+ ' m.VertexColorChannels(0).Add(New Color4D(0, 0, 0, 0))
+ 'End If
+
+ dicCounter(m) += 1
+ Next
+
+ m.Faces.Add(newFace)
+ Next
+ Next
+
+ 'Add Root Node
+ mdl.RootNode = New Node(Path.GetFileName(fileName))
+
+ 'Add Mesh Indicies
+ For i As Integer = 0 To mdl.MeshCount - 1
+ mdl.RootNode.MeshIndices.Add(i)
+ Next
+
+ Dim ac As New AssimpContext
+
+ Dim formatID As String = ""
+ Dim myExt As String = Path.GetExtension(fileName).ToLower.Substring(1)
+ For Each efd As ExportFormatDescription In ac.GetSupportedExportFormats
+ If myExt = efd.FileExtension Then
+ formatID = efd.FormatId
+ Exit For
+ End If
+ Next
+
+ ac.ExportFile(mdl, fileName, formatID)
+ End Sub
+
+ Private Shared Function LoadImage(fileName As String, loadedImages As Dictionary(Of String, Image)) As Image
+ If File.Exists(fileName) Then
+ If loadedImages.ContainsKey(fileName) Then
+ Return loadedImages(fileName)
+ Else
+ Dim fs As New FileStream(fileName, FileMode.Open, FileAccess.Read)
+ Dim img As Image = Image.FromStream(fs)
+ fs.Close()
+
+ For Each kvp In loadedImages
+ If IsTheSameAs(img, kvp.Value) Then
+ Return kvp.Value
+ End If
+ Next
+
+ loadedImages.Add(fileName, img)
+ Return img
+ End If
+ End If
+ Return Nothing
+ End Function
+
+ End Class
+
+End Namespace
diff --git a/Pilz.Simple3DFileParser/FileParser/Obj.vb b/Pilz.Simple3DFileParser/FileParser/Obj.vb
new file mode 100644
index 0000000..bb28d11
--- /dev/null
+++ b/Pilz.Simple3DFileParser/FileParser/Obj.vb
@@ -0,0 +1,391 @@
+Imports System.Globalization
+Imports System.IO
+Imports System.Threading
+Imports Pilz.S3DFileParser.Exceptions
+
+Namespace ObjModule
+
+ Public Class ObjFile
+
+ Public Shared Function FromFile(FileName As String, LoadMaterials As Boolean, UpAxis As UpAxis) As Object3D
+ Dim curThread As Thread = Thread.CurrentThread
+ Dim curCultInfo As CultureInfo = curThread.CurrentCulture
+ Dim newCultInfo As New CultureInfo(curCultInfo.Name)
+ newCultInfo.NumberFormat.NumberDecimalSeparator = "."
+ newCultInfo.NumberFormat.PercentDecimalSeparator = "."
+ newCultInfo.NumberFormat.CurrencyDecimalSeparator = "."
+ newCultInfo.NumberFormat.NumberGroupSeparator = ","
+ newCultInfo.NumberFormat.PercentGroupSeparator = ","
+ newCultInfo.NumberFormat.CurrencyGroupSeparator = ","
+ curThread.CurrentCulture = newCultInfo
+
+ Dim newObj As New Object3D
+ Dim newMesh As New Mesh
+ Dim curObjPath As String = Path.GetDirectoryName(FileName)
+
+ Dim mtllibs As New Dictionary(Of String, MaterialLib)
+
+ Dim curMaterialLib As MaterialLib = Nothing
+ Dim curMaterial As Material = Nothing
+
+ Dim srObj As New StreamReader(FileName, Text.Encoding.ASCII)
+ Dim line As String = ""
+
+ Do Until srObj.EndOfStream
+ line = srObj.ReadLine.Trim
+
+ If line <> "" Then
+
+ Select Case True
+ Case line.StartsWith("mtllib ")
+ Dim name As String = line.Substring(7)
+
+ If Not mtllibs.ContainsKey(name) Then
+ Dim mtlfile As String = Path.Combine(curObjPath, name)
+ If Not File.Exists(mtlfile) Then Throw New MaterialException("Material Library not found!")
+
+ Dim newmtl As New MaterialLib
+ newmtl.FromFile(mtlfile, LoadMaterials)
+ mtllibs.Add(name, newmtl)
+ curMaterialLib = newmtl
+
+ For Each kvp As KeyValuePair(Of String, Material) In curMaterialLib.Materials
+ If Not newObj.Materials.ContainsKey(kvp.Key) Then newObj.Materials.Add(kvp.Key, kvp.Value)
+ Next
+ Else
+ curMaterialLib = mtllibs(name)
+ End If
+
+ Case line.StartsWith("usemtl ")
+ curMaterial = curMaterialLib.Materials(line.Substring(7))
+
+ Case line.StartsWith("v ")
+ If line.Contains("nan") Then line = line.Replace("nan", "0")
+ Dim splitXYZ() As String = line.Substring(2).Split(" "c)
+
+ Dim tX As Double = Convert.ToDouble(splitXYZ(0))
+ Dim tY As Double = Convert.ToDouble(splitXYZ(1))
+ Dim tZ As Double = Convert.ToDouble(splitXYZ(2))
+
+ Dim v As New Vertex
+ Select Case UpAxis
+ Case UpAxis.Y
+ v.X = tX
+ v.Y = tY
+ v.Z = tZ
+ Case UpAxis.Z
+ v.X = tY
+ v.Y = tZ
+ v.Z = tX
+ End Select
+ newMesh.Vertices.Add(v)
+
+ Case line.StartsWith("vt ")
+ Dim uvstr() As String = line.Substring(3).Split(" "c)
+ Dim uv As New UV With {
+ .U = Convert.ToSingle(uvstr(0)),
+ .V = Convert.ToSingle(uvstr(1))}
+ newMesh.UVs.Add(uv)
+
+ Case line.StartsWith("vn ")
+ Dim splitXYZ() As String = line.Substring(3).Split(" "c)
+
+ Dim tX As Single = Convert.ToSingle(splitXYZ(0))
+ Dim tY As Single = Convert.ToSingle(splitXYZ(1))
+ Dim tZ As Single = Convert.ToSingle(splitXYZ(2))
+
+ Dim n As New Normal
+ Select Case UpAxis
+ Case UpAxis.Y
+ n.X = tX
+ n.Y = tY
+ n.Z = tZ
+ Case UpAxis.Z
+ n.X = tZ
+ n.Y = tY
+ n.Z = tX
+ End Select
+ newMesh.Normals.Add(n)
+
+ Case line.StartsWith("vc ")
+ Dim splitRGB() As String = line.Substring(3).Split(" "c)
+
+ Dim tX As Single = Convert.ToSingle(splitRGB(0))
+ Dim tY As Single = Convert.ToSingle(splitRGB(1))
+ Dim tZ As Single = Convert.ToSingle(splitRGB(2))
+
+ Dim vc As New VertexColor
+ Select Case UpAxis
+ Case UpAxis.Y
+ vc.R = tX
+ vc.G = tY
+ vc.B = tZ
+ Case UpAxis.Z
+ vc.R = tY
+ vc.G = tZ
+ vc.B = tX
+ End Select
+ newMesh.VertexColors.Add(vc)
+
+ Case line.StartsWith("f ")
+ Dim tri As New Face With {.Material = curMaterial}
+
+ For Each xyz As String In line.Substring(2).Split(" "c)
+ xyz = xyz.Trim
+ If xyz = "" Then Continue For
+
+ Dim splitsub() As String = Nothing
+ Dim p As New Point
+
+ Select Case True
+ Case xyz.Contains("/")
+ splitsub = xyz.Split("/"c)
+ Case xyz.Contains("\")
+ splitsub = xyz.Split("\"c)
+ Case Else
+ splitsub = {0, 0, 0}
+ End Select
+
+ Dim v1 As String = splitsub(0)
+ Dim v2 As String = splitsub(1)
+ Dim v3 As String = splitsub(2)
+
+ If v1 <> "" Then
+ p.Vertex = newMesh.Vertices(Convert.ToInt32(v1) - 1)
+ End If
+
+ If v2 <> "" Then
+ p.UV = newMesh.UVs(Convert.ToInt32(v2) - 1)
+ Else
+ Dim newUV As New UV With {.U = 0, .V = 0}
+ p.UV = newUV
+ newMesh.UVs.Add(newUV)
+ End If
+
+ If v3 <> "" Then
+ p.Normal = newMesh.Normals(Convert.ToInt32(v3) - 1)
+ End If
+
+ If splitsub.Count > 3 Then
+ Dim v4 As String = splitsub(3)
+ If v4 <> "" Then p.VertexColor = newMesh.VertexColors(Convert.ToInt32(v4) - 1)
+ End If
+
+ tri.Points.Add(p)
+ Next
+
+ newMesh.Faces.Add(tri)
+
+ End Select
+
+ End If
+
+ Loop
+ newObj.Meshes.Add(newMesh)
+
+ curThread.CurrentCulture = curCultInfo
+
+ srObj.Close()
+ Return newObj
+ End Function
+
+ Public Shared Sub ToFile(FileName As String, obj As Object3D)
+ Dim fs As New FileStream(FileName, FileMode.Create, FileAccess.ReadWrite)
+ Dim sw As New StreamWriter(fs, Text.Encoding.ASCII)
+
+ If obj.Materials.Count > 0 Then
+ Dim mtlName As String = Path.GetFileNameWithoutExtension(FileName) & ".mtl"
+ Dim mtlFile As String = Path.Combine(Path.GetDirectoryName(FileName), mtlName)
+ sw.WriteLine($"mtllib {mtlName}")
+ MaterialLib.ToFile(mtlFile, obj)
+ End If
+
+ Dim curVertCount As Integer = 1
+ Dim curUVCount As Integer = 1
+ Dim curNormCount As Integer = 1
+ Dim curVertColCount As Integer = 1
+
+ For Each m As Mesh In obj.Meshes
+
+ For Each vert As Vertex In m.Vertices
+ sw.WriteLine($"v {vert.X.ToString.Replace(",", ".")} {vert.Y.ToString.Replace(",", ".")} {vert.Z.ToString.Replace(",", ".")}")
+ Next
+
+ For Each uv As UV In m.UVs
+ sw.WriteLine($"vt {uv.U.ToString.Replace(",", ".")} {uv.V.ToString.Replace(",", ".")}")
+ Next
+
+ For Each norm As Normal In m.Normals
+ sw.WriteLine($"vn {norm.X.ToString.Replace(",", ".")} {norm.Y.ToString.Replace(",", ".")} {norm.Z.ToString.Replace(",", ".")}")
+ Next
+
+ For Each vertcol As VertexColor In m.VertexColors
+ sw.WriteLine($"vc {vertcol.R.ToString.Replace(",", ".")} {vertcol.G.ToString.Replace(",", ".")} {vertcol.B.ToString.Replace(",", ".")}")
+ Next
+
+ Dim curMtl As Material = Nothing
+
+ For Each f As Face In m.Faces
+ If curMtl IsNot f.Material Then
+ curMtl = f.Material
+ sw.WriteLine($"usemtl _{GetIndexOfMaterialInList(obj, curMtl)}")
+ End If
+
+ sw.Write("f")
+
+ For Each p As Point In f.Points
+ sw.Write(" ")
+ sw.Write(curVertCount + m.Vertices.IndexOf(p.Vertex))
+
+ sw.Write("/")
+ If p.UV IsNot Nothing Then sw.Write(curUVCount + m.UVs.IndexOf(p.UV))
+
+ sw.Write("/")
+ If p.Normal IsNot Nothing Then sw.Write(curNormCount + m.Normals.IndexOf(p.Normal))
+
+ If m.VertexColors.Count > 0 Then
+ sw.Write("/")
+ If p.VertexColor IsNot Nothing Then sw.Write(curVertColCount + m.VertexColors.IndexOf(p.VertexColor))
+ End If
+ Next
+
+ sw.WriteLine()
+ Next
+
+ curVertCount += m.Vertices.Count
+ curUVCount += m.UVs.Count
+ curNormCount += m.Normals.Count
+ curVertColCount += m.VertexColors.Count
+ Next
+
+ sw.Flush()
+ fs.Close()
+ End Sub
+
+ Public Shared Function GetIndexOfMaterialInList(obj As Object3D, matToFind As Material) As Integer
+ For Index As Integer = 0 To obj.Materials.Count - 1
+ If obj.Materials.ElementAt(Index).Value.Equals(matToFind) Then
+ Return Index
+ End If
+ Next
+ Return -1
+ End Function
+
+ End Class
+
+ Public Class MaterialLib
+
+ Public ReadOnly Property Materials As New Dictionary(Of String, Material)
+ Private ReadOnly LoadedImages As New Dictionary(Of String, Image)
+
+ Public Sub FromFile(fileName As String, LoadMaterials As Boolean)
+ LoadedImages.Clear()
+
+ Dim curMatLibPath As String = Path.GetDirectoryName(fileName)
+
+ Dim curMat As Material = Nothing
+ Dim curName As String = ""
+
+ Dim srMtl As New StreamReader(fileName, Text.Encoding.ASCII)
+ Dim line As String = ""
+
+ Do Until srMtl.EndOfStream
+ line = srMtl.ReadLine
+
+ Select Case True
+ Case line.StartsWith("newmtl ")
+ curMat = New Material
+ curName = line.Substring(7)
+ Materials.Add(curName, curMat)
+
+ Case line.ToLower.StartsWith("kd ")
+ Dim splitColor() As String = line.Substring(3).Split(" "c)
+ Dim col As Color = Color.FromArgb(
+ Convert.ToSingle(Math.Round(255 * splitColor(0))),
+ Convert.ToSingle(Math.Round(255 * splitColor(1))),
+ Convert.ToSingle(Math.Round(255 * splitColor(2))))
+ curMat.Color = col
+
+ Case line.ToLower.StartsWith("d ")
+ curMat.Opacity = Convert.ToSingle(line.Substring(2))
+
+ Case line.ToLower.StartsWith("tr ")
+ curMat.Opacity = 1 - Convert.ToSingle(line.Substring(2))
+
+ Case line.ToLower.StartsWith("map_kd ")
+ If LoadMaterials Then
+ Dim mtlpath As String = line.Substring(7)
+ Dim combipath As String = Path.Combine(curMatLibPath, line.Substring(7))
+ Dim imgfile As String
+
+ If File.Exists(combipath) Then
+ imgfile = combipath
+ ElseIf File.Exists(line.Substring(7)) Then
+ imgfile = mtlpath
+ Else
+ imgfile = ""
+ End If
+
+ If imgfile <> "" Then
+ If LoadedImages.ContainsKey(imgfile) Then
+ curMat.Image = LoadedImages(imgfile)
+ Else
+ Dim fs As New FileStream(imgfile, FileMode.Open, FileAccess.Read)
+ curMat.Image = Image.FromStream(fs)
+ fs.Close()
+ Dim imgExists As Boolean = False
+ For Each kvp In LoadedImages
+ If Not imgExists AndAlso IsTheSameAs(kvp.Value, curMat.Image) Then
+ curMat.Image = kvp.Value
+ imgExists = True
+ End If
+ Next
+ If Not imgExists Then
+ LoadedImages.Add(imgfile, curMat.Image)
+ End If
+ End If
+ End If
+ End If
+
+ End Select
+ Loop
+
+ srMtl.Close()
+ End Sub
+
+ Public Shared Sub ToFile(fileName As String, obj As Object3D)
+ Dim fs As New FileStream(fileName, FileMode.Create, FileAccess.ReadWrite)
+ Dim sw As New StreamWriter(fs, Text.Encoding.ASCII)
+ Dim imgDirName As String = Path.GetFileNameWithoutExtension(fileName)
+ Dim imgDirFull As String = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName))
+
+ For Each kvp As KeyValuePair(Of String, Material) In obj.Materials
+ Dim mat As Material = kvp.Value
+ Dim name As String = "_" & ObjFile.GetIndexOfMaterialInList(obj, mat)
+ sw.WriteLine($"newmtl {name}")
+
+ If mat.Color IsNot Nothing Then
+ sw.WriteLine($"kd {mat.Color.Value.R.ToString.Replace(",", ".")} {mat.Color.Value.G.ToString.Replace(",", ".")} {mat.Color.Value.B.ToString.Replace(",", ".")}")
+ End If
+
+ If mat.Opacity IsNot Nothing Then
+ sw.WriteLine($"d {mat.Opacity.Value.ToString.Replace(",", ".")}")
+ End If
+
+ If mat.Image IsNot Nothing Then
+ Dim imgFile As String = name & ".png"
+
+ If Not Directory.Exists(imgDirFull) Then Directory.CreateDirectory(imgDirFull)
+ mat.Image.Save(Path.Combine(imgDirFull, imgFile), Imaging.ImageFormat.Png)
+
+ sw.WriteLine($"map_kd {Path.Combine(imgDirName, imgFile)}")
+ End If
+ Next
+
+ sw.Flush()
+ fs.Close()
+ End Sub
+
+ End Class
+
+End Namespace
\ No newline at end of file
diff --git a/Pilz.Simple3DFileParser/Model/Face.vb b/Pilz.Simple3DFileParser/Model/Face.vb
new file mode 100644
index 0000000..09497ce
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Face.vb
@@ -0,0 +1,5 @@
+Public Class Face
+ Public ReadOnly Property Points As New List(Of Point)
+ Public Property Material As Material = Nothing
+ Public Property Tag As Object = Nothing
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/Interfaces.vb b/Pilz.Simple3DFileParser/Model/Interfaces.vb
new file mode 100644
index 0000000..05bac76
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Interfaces.vb
@@ -0,0 +1,6 @@
+Public Interface IToObject3D
+
+ Function ToObject3D() As Object3D
+ Function ToObject3DAsync() As Task(Of Object3D)
+
+End Interface
diff --git a/Pilz.Simple3DFileParser/Model/Material.vb b/Pilz.Simple3DFileParser/Model/Material.vb
new file mode 100644
index 0000000..1b755b6
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Material.vb
@@ -0,0 +1,25 @@
+Imports System.Numerics
+
+Public Class Material
+ Implements IComparable
+
+ Public Property Image As Image = Nothing
+ Public Property Color As Color? = Nothing
+ Public Property Opacity As Single? = Nothing
+ Public Property Wrap As New Vector2(10497, 10497)
+ Public Property Scale As New Vector2(1.0F, 1.0F)
+ Public Property Tag As Object = Nothing
+
+ Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
+ If obj IsNot Nothing Then
+ If obj Is Me Then
+ Return 0
+ Else
+ Return -1
+ End If
+ Else
+ Return 1
+ End If
+ End Function
+
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/Mesh.vb b/Pilz.Simple3DFileParser/Model/Mesh.vb
new file mode 100644
index 0000000..53dfa0b
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Mesh.vb
@@ -0,0 +1,41 @@
+Imports System.Numerics
+
+Public Class Mesh
+
+ Public ReadOnly Property Vertices As New List(Of Vertex)
+ Public ReadOnly Property Normals As New List(Of Normal)
+ Public ReadOnly Property UVs As New List(Of UV)
+ Public ReadOnly Property VertexColors As New List(Of VertexColor)
+ Public ReadOnly Property Faces As New List(Of Face)
+
+ Friend Function GetCenterModelAvg() As Vector3
+ Dim avgX As Integer = 0
+ Dim avgY As Integer = 0
+ Dim avgZ As Integer = 0
+
+ For Each v As Vertex In Vertices
+ avgX += v.X
+ avgY += v.Y
+ avgZ += v.Z
+ Next
+
+ Return New Vector3(avgX, avgY, avgZ)
+ End Function
+
+ Public Sub CenterModel()
+ Dim avg As Vector3 = GetCenterModelAvg()
+
+ avg /= New Vector3(Vertices.Count)
+
+ CenterModel(avg)
+ End Sub
+
+ Public Sub CenterModel(avg As Vector3)
+ For Each v As Vertex In Vertices
+ v.X -= avg.X
+ v.Y -= avg.Y
+ v.Z -= avg.Z
+ Next
+ End Sub
+
+End Class
\ No newline at end of file
diff --git a/Pilz.Simple3DFileParser/Model/ModelBoundaries.vb b/Pilz.Simple3DFileParser/Model/ModelBoundaries.vb
new file mode 100644
index 0000000..ea4495d
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/ModelBoundaries.vb
@@ -0,0 +1,11 @@
+Imports System.Numerics
+
+Public Class ModelBoundaries
+ Public ReadOnly Upper As Vector3
+ Public ReadOnly Lower As Vector3
+
+ Public Sub New(upper As Vector3, lower As Vector3)
+ Me.Upper = upper
+ Me.Lower = lower
+ End Sub
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/Normal.vb b/Pilz.Simple3DFileParser/Model/Normal.vb
new file mode 100644
index 0000000..e855cb2
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Normal.vb
@@ -0,0 +1,5 @@
+Public Class Normal
+ Public Property X As Single = 0
+ Public Property Y As Single = 0
+ Public Property Z As Single = 0
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/Object3D.vb b/Pilz.Simple3DFileParser/Model/Object3D.vb
new file mode 100644
index 0000000..52e5aa8
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Object3D.vb
@@ -0,0 +1,200 @@
+Imports System.IO
+Imports System.Numerics
+
+Public Class Object3D
+
+ Public ReadOnly Property Meshes As New List(Of Mesh)
+ Public ReadOnly Property Materials As New Dictionary(Of String, Material)
+ Public Property Shading As New Shading
+
+ Public Sub ScaleModel(factor As Single)
+ For Each m As Mesh In Meshes
+ For Each v As Vertex In m.Vertices
+ v.X *= factor
+ v.Y *= factor
+ v.Z *= factor
+ Next
+ Next
+ End Sub
+
+ Public Sub OffsetModel(off As Vector3)
+ For Each m As Mesh In Meshes
+ For Each v As Vertex In m.Vertices
+ v.X += off.X
+ v.Y += off.Y
+ v.Z += off.Z
+ Next
+ Next
+ End Sub
+
+ Public Function GetBoundaries() As ModelBoundaries
+ Dim maxX As Single? = Nothing
+ Dim maxY As Single? = Nothing
+ Dim maxZ As Single? = Nothing
+ Dim minX As Single? = Nothing
+ Dim minY As Single? = Nothing
+ Dim minZ As Single? = Nothing
+
+ For Each m As Mesh In Meshes
+ For Each vert As Vertex In m.Vertices
+ If maxX Is Nothing OrElse vert.X > maxX Then maxX = vert.X
+ If maxY Is Nothing OrElse vert.Y > maxY Then maxY = vert.Y
+ If maxZ Is Nothing OrElse vert.Z > maxZ Then maxZ = vert.Z
+ If minX Is Nothing OrElse vert.X < minX Then minX = vert.X
+ If minY Is Nothing OrElse vert.Y < minY Then minY = vert.Y
+ If minZ Is Nothing OrElse vert.Z < minZ Then minZ = vert.Z
+ Next
+ Next
+
+ If maxX Is Nothing Then maxX = 0
+ If maxY Is Nothing Then maxY = 0
+ If maxZ Is Nothing Then maxZ = 0
+ If minX Is Nothing Then minX = 0
+ If minY Is Nothing Then minY = 0
+ If minZ Is Nothing Then minZ = 0
+
+ Return New ModelBoundaries(New Vector3(maxX, maxY, maxZ),
+ New Vector3(minX, minY, minZ))
+ End Function
+
+ Public Sub SetNullVertices()
+ Dim newVert As New Vertex With {.X = 0, .Y = 0, .Z = 0}
+ Dim nullCounter As Integer
+
+ For Each m As Mesh In Meshes
+ nullCounter = 0
+
+ For Each f As Face In m.Faces
+ For Each p As Point In f.Points
+ If p.Vertex Is Nothing Then
+ p.Vertex = newVert
+ nullCounter += 1
+ End If
+ Next
+ Next
+
+ If nullCounter > 0 Then
+ m.Vertices.Add(newVert)
+ End If
+ Next
+ End Sub
+
+ Public Sub SetNullUVs()
+ Dim newUV As New UV With {.U = 0, .V = 0}
+ Dim nullCounter As Integer
+
+ For Each m As Mesh In Meshes
+ nullCounter = 0
+
+ For Each f As Face In m.Faces
+ For Each p As Point In f.Points
+ If p.UV Is Nothing Then
+ p.UV = newUV
+ nullCounter += 1
+ End If
+ Next
+ Next
+
+ If nullCounter > 0 Then
+ m.UVs.Add(newUV)
+ End If
+ Next
+ End Sub
+
+ Public Sub SetNullNormals()
+ Dim newNormal As New Normal With {.X = 0, .Y = 0, .Z = 1}
+ Dim nullCounter As Integer
+
+ For Each m As Mesh In Meshes
+ nullCounter = 0
+
+ For Each f As Face In m.Faces
+ For Each p As Point In f.Points
+ If p.Normal Is Nothing Then
+ p.Normal = newNormal
+ nullCounter += 1
+ End If
+ Next
+ Next
+
+ If nullCounter > 0 Then
+ m.Normals.Add(newNormal)
+ End If
+ Next
+ End Sub
+
+ Public Sub RemoveUnusedMaterials()
+ 'Dim usedMats As New List(Of Material)
+ 'Dim unusedMats As New List(Of String)
+
+ 'For Each f As Face In Faces
+ ' If Not usedMats.Contains(f.Material) Then
+ ' usedMats.Add(f.Material)
+ ' End If
+ 'Next
+
+ 'For Each kvp As KeyValuePair(Of String, Material) In Materials
+ ' If Not usedMats.Contains(kvp.Value) Then
+ ' unusedMats.Add(kvp.Key)
+ ' End If
+ 'Next
+
+ 'For Each k As String In unusedMats
+ ' Materials.Remove(k)
+ 'Next
+ End Sub
+
+ Public Function ToOneMesh() As Object3D
+ Dim newObject3D As New Object3D
+ Dim newMesh As New Mesh
+
+ For Each mat As KeyValuePair(Of String, Material) In Materials
+ newObject3D.Materials.Add(mat.Key, mat.Value)
+ Next
+
+ For Each m As Mesh In Meshes
+ For Each v As Vertex In m.Vertices
+ newMesh.Vertices.Add(v)
+ Next
+
+ For Each vc As VertexColor In m.VertexColors
+ newMesh.VertexColors.Add(vc)
+ Next
+
+ For Each n As Normal In m.Normals
+ newMesh.Normals.Add(n)
+ Next
+
+ For Each uv As UV In m.UVs
+ newMesh.UVs.Add(uv)
+ Next
+
+ For Each f As Face In m.Faces
+ newMesh.Faces.Add(f)
+ Next
+ Next
+
+ newObject3D.Meshes.Add(newMesh)
+ Return newObject3D
+ End Function
+
+ Public Sub CenterModel()
+ Dim avg As Vector3 = Vector3.Zero
+ Dim vertsCount As ULong = 0
+
+ For Each m As Mesh In Meshes
+ avg += m.GetCenterModelAvg
+ vertsCount += m.Vertices.Count
+ Next
+
+ avg /= vertsCount
+
+ CenterModel(avg)
+ End Sub
+ Public Sub CenterModel(avg As Vector3)
+ For Each m As Mesh In Meshes
+ m.CenterModel(avg)
+ Next
+ End Sub
+
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/Point.vb b/Pilz.Simple3DFileParser/Model/Point.vb
new file mode 100644
index 0000000..2760f7f
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Point.vb
@@ -0,0 +1,6 @@
+Public Class Point
+ Public Property Vertex As Vertex = Nothing
+ Public Property UV As UV = Nothing
+ Public Property VertexColor As VertexColor = Nothing
+ Public Property Normal As Normal = Nothing
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/Shading.vb b/Pilz.Simple3DFileParser/Model/Shading.vb
new file mode 100644
index 0000000..b69447b
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Shading.vb
@@ -0,0 +1,5 @@
+Public Class Shading
+ Public Property AmbientColor As Color = Color.FromArgb(&HFFFFFFFF)
+ Public Property DiffuseColor As Color = Color.FromArgb(&HFF7F7F7F)
+ Public Property DiffusePosition As Vertex = Nothing
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/UV.vb b/Pilz.Simple3DFileParser/Model/UV.vb
new file mode 100644
index 0000000..74de128
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/UV.vb
@@ -0,0 +1,4 @@
+Public Class UV
+ Public Property U As Single = 0
+ Public Property V As Single = 0
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/UpAxis.vb b/Pilz.Simple3DFileParser/Model/UpAxis.vb
new file mode 100644
index 0000000..1e309de
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/UpAxis.vb
@@ -0,0 +1,4 @@
+Public Enum UpAxis
+ Y
+ Z
+End Enum
diff --git a/Pilz.Simple3DFileParser/Model/Vertex.vb b/Pilz.Simple3DFileParser/Model/Vertex.vb
new file mode 100644
index 0000000..d1b4d1e
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/Vertex.vb
@@ -0,0 +1,5 @@
+Public Class Vertex
+ Public Property X As Double = 0
+ Public Property Y As Double = 0
+ Public Property Z As Double = 0
+End Class
diff --git a/Pilz.Simple3DFileParser/Model/VertexColor.vb b/Pilz.Simple3DFileParser/Model/VertexColor.vb
new file mode 100644
index 0000000..0d41404
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Model/VertexColor.vb
@@ -0,0 +1,6 @@
+Public Class VertexColor
+ Public Property R As Single = 1
+ Public Property G As Single = 1
+ Public Property B As Single = 1
+ Public Property A As Single = 1
+End Class
diff --git a/Pilz.Simple3DFileParser/My Project/Application.Designer.vb b/Pilz.Simple3DFileParser/My Project/Application.Designer.vb
new file mode 100644
index 0000000..8ab460b
--- /dev/null
+++ b/Pilz.Simple3DFileParser/My Project/Application.Designer.vb
@@ -0,0 +1,13 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
diff --git a/Pilz.Simple3DFileParser/My Project/Application.myapp b/Pilz.Simple3DFileParser/My Project/Application.myapp
new file mode 100644
index 0000000..1243847
--- /dev/null
+++ b/Pilz.Simple3DFileParser/My Project/Application.myapp
@@ -0,0 +1,11 @@
+
+
+ true
+ Form1
+ false
+ 0
+ true
+ 0
+ 0
+ true
+
diff --git a/Pilz.Simple3DFileParser/My Project/AssemblyInfo.vb b/Pilz.Simple3DFileParser/My Project/AssemblyInfo.vb
new file mode 100644
index 0000000..d6dd9e2
--- /dev/null
+++ b/Pilz.Simple3DFileParser/My Project/AssemblyInfo.vb
@@ -0,0 +1,35 @@
+Imports System
+Imports System.Reflection
+Imports System.Runtime.InteropServices
+
+' Allgemeine Informationen über eine Assembly werden über die folgenden
+' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
+' die einer Assembly zugeordnet sind.
+
+' Werte der Assemblyattribute überprüfen
+
+
+
+
+
+
+
+
+
+
+'Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird.
+
+
+' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
+'
+' Hauptversion
+' Nebenversion
+' Buildnummer
+' Revision
+'
+' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
+' übernehmen, indem Sie "*" eingeben:
+'
+
+
+
diff --git a/Pilz.Simple3DFileParser/My Project/Resources.Designer.vb b/Pilz.Simple3DFileParser/My Project/Resources.Designer.vb
new file mode 100644
index 0000000..0832c08
--- /dev/null
+++ b/Pilz.Simple3DFileParser/My Project/Resources.Designer.vb
@@ -0,0 +1,63 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+Imports System
+
+Namespace My.Resources
+
+ 'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
+ '-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
+ 'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
+ 'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
+ '''
+ ''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
+ '''
+ _
+ Friend Module Resources
+
+ Private resourceMan As Global.System.Resources.ResourceManager
+
+ Private resourceCulture As Global.System.Globalization.CultureInfo
+
+ '''
+ ''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
+ '''
+ _
+ Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
+ Get
+ If Object.ReferenceEquals(resourceMan, Nothing) Then
+ Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Pilz.S3DFileParser.Resources", GetType(Resources).Assembly)
+ resourceMan = temp
+ End If
+ Return resourceMan
+ End Get
+ End Property
+
+ '''
+ ''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
+ ''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
+ '''
+ _
+ Friend Property Culture() As Global.System.Globalization.CultureInfo
+ Get
+ Return resourceCulture
+ End Get
+ Set
+ resourceCulture = value
+ End Set
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Simple3DFileParser/My Project/Resources.resx b/Pilz.Simple3DFileParser/My Project/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Pilz.Simple3DFileParser/My Project/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Pilz.Simple3DFileParser/My Project/Settings.Designer.vb b/Pilz.Simple3DFileParser/My Project/Settings.Designer.vb
new file mode 100644
index 0000000..60c5980
--- /dev/null
+++ b/Pilz.Simple3DFileParser/My Project/Settings.Designer.vb
@@ -0,0 +1,73 @@
+'------------------------------------------------------------------------------
+'
+' Dieser Code wurde von einem Tool generiert.
+' Laufzeitversion:4.0.30319.42000
+'
+' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
+' der Code erneut generiert wird.
+'
+'------------------------------------------------------------------------------
+
+Option Strict On
+Option Explicit On
+
+
+Namespace My
+
+ _
+ Partial Friend NotInheritable Class MySettings
+ Inherits Global.System.Configuration.ApplicationSettingsBase
+
+ Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
+
+#Region "Automatische My.Settings-Speicherfunktion"
+#If _MyType = "WindowsForms" Then
+ Private Shared addedHandler As Boolean
+
+ Private Shared addedHandlerLockObject As New Object
+
+ _
+ Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
+ If My.Application.SaveMySettingsOnExit Then
+ My.Settings.Save()
+ End If
+ End Sub
+#End If
+#End Region
+
+ Public Shared ReadOnly Property [Default]() As MySettings
+ Get
+
+#If _MyType = "WindowsForms" Then
+ If Not addedHandler Then
+ SyncLock addedHandlerLockObject
+ If Not addedHandler Then
+ AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
+ addedHandler = True
+ End If
+ End SyncLock
+ End If
+#End If
+ Return defaultInstance
+ End Get
+ End Property
+ End Class
+End Namespace
+
+Namespace My
+
+ _
+ Friend Module MySettingsProperty
+
+ _
+ Friend ReadOnly Property Settings() As Global.Pilz.S3DFileParser.My.MySettings
+ Get
+ Return Global.Pilz.S3DFileParser.My.MySettings.Default
+ End Get
+ End Property
+ End Module
+End Namespace
diff --git a/Pilz.Simple3DFileParser/My Project/Settings.settings b/Pilz.Simple3DFileParser/My Project/Settings.settings
new file mode 100644
index 0000000..85b890b
--- /dev/null
+++ b/Pilz.Simple3DFileParser/My Project/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Pilz.Simple3DFileParser/Other/Exceptions.vb b/Pilz.Simple3DFileParser/Other/Exceptions.vb
new file mode 100644
index 0000000..df3a620
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Other/Exceptions.vb
@@ -0,0 +1,14 @@
+Namespace Exceptions
+
+ Public Class MaterialException
+ Inherits Exception
+
+ Public Sub New()
+ MyBase.New
+ End Sub
+ Public Sub New(message As String)
+ MyBase.New(message)
+ End Sub
+ End Class
+
+End Namespace
diff --git a/Pilz.Simple3DFileParser/Other/Extensions.vb b/Pilz.Simple3DFileParser/Other/Extensions.vb
new file mode 100644
index 0000000..59da39b
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Other/Extensions.vb
@@ -0,0 +1,26 @@
+Imports System.IO
+Imports System.Runtime.CompilerServices
+
+Friend Module Extensions
+
+
+ Public Function GetPropertyValue(base As Object, propertyName As String) As Object
+ Return base?.GetType.GetProperty(propertyName, Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Static)?.GetValue(base)
+ End Function
+
+
+ Public Function IsTheSameAs(base As Bitmap, image As Bitmap) As Boolean
+ If base.Size <> image.Size Then Return False
+
+ For y As Integer = 0 To base.Height - 1
+ For x As Integer = 0 To base.Width - 1
+ Dim p1 As Color = base.GetPixel(x, y)
+ Dim p2 As Color = image.GetPixel(x, y)
+ If p1 <> p2 Then Return False
+ Next
+ Next
+
+ Return True
+ End Function
+
+End Module
diff --git a/Pilz.Simple3DFileParser/Other/LoaderModule.vb b/Pilz.Simple3DFileParser/Other/LoaderModule.vb
new file mode 100644
index 0000000..a34a287
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Other/LoaderModule.vb
@@ -0,0 +1,144 @@
+Imports System.Reflection
+Imports Assimp.Unmanaged
+
+Public Class File3DLoaderModule
+
+ Public Delegate Function LoaderAction(fileName As String, options As LoaderOptions) As Object3D
+ Public Delegate Sub ExporterAction(obj As Object3D, fileName As String)
+
+ Private Shared _LoaderModules As File3DLoaderModule() = Nothing
+ Private Shared _ExporterModules As File3DLoaderModule() = Nothing
+
+ Private ReadOnly method As [Delegate] = Nothing
+ Public ReadOnly Property Name As String
+ Public ReadOnly Property SupportedFormats As IReadOnlyDictionary(Of String, String)
+
+ Public Sub New(name As String, method As LoaderAction, supportedFormats As IReadOnlyDictionary(Of String, String))
+ Me.Name = name
+ Me.method = method
+ Me.SupportedFormats = supportedFormats
+ End Sub
+
+ Public Sub New(name As String, method As ExporterAction, supportedFormats As IReadOnlyDictionary(Of String, String))
+ Me.Name = name
+ Me.method = method
+ Me.SupportedFormats = supportedFormats
+ End Sub
+
+ Public Function InvokeAsync(obj As Object3D, fileName As String) As Task
+ Return Task.Run(Sub() Invoke(obj, fileName))
+ End Function
+
+ Public Sub Invoke(obj As Object3D, fileName As String)
+ method.Method.Invoke(Nothing, {obj, fileName})
+ End Sub
+
+ Public Function InvokeAsync(fileName As String, options As LoaderOptions) As Task(Of Object3D)
+ Return Task.Run(Function() Invoke(fileName, options))
+ End Function
+
+ Public Function Invoke(fileName As String, options As LoaderOptions) As Object3D
+ Return method.Method.Invoke(Nothing, {fileName, options})
+ End Function
+
+ Public Shared ReadOnly Property LoaderModules As File3DLoaderModule()
+ Get
+ If _LoaderModules Is Nothing Then
+ _LoaderModules = GetLoaderModules()
+ End If
+ Return _LoaderModules
+ End Get
+ End Property
+
+ Public Shared ReadOnly Property ExporterModules As File3DLoaderModule()
+ Get
+ If _ExporterModules Is Nothing Then
+ _ExporterModules = GetExporterModules()
+ End If
+ Return _ExporterModules
+ End Get
+ End Property
+
+ Private Shared Function GetLoaderModules() As File3DLoaderModule()
+ Dim list As New List(Of File3DLoaderModule)
+
+ list.Add(New File3DLoaderModule("Simple File Parser",
+ AddressOf LoadViaSimpleFileParser,
+ New Dictionary(Of String, String) From {{"obj", "OBJ"}}))
+
+ AssimpModule.AssimpLoader.LoadAssimpLibs()
+ Dim exts As New Dictionary(Of String, String)
+ For Each fd As Assimp.ExportFormatDescription In AssimpLibrary.Instance.GetExportFormatDescriptions
+ If Not exts.ContainsKey(fd.FileExtension) Then exts.Add(fd.FileExtension, fd.FormatId & " - " & fd.Description)
+ Next
+
+ list.Add(New File3DLoaderModule("Assimp",
+ AddressOf LoadViaAssimp,
+ exts))
+
+ list.Add(New File3DLoaderModule("Aspose.3D",
+ AddressOf LoadViaAspose3D,
+ New Dictionary(Of String, String) From {
+ {"obj", "OBJ"},
+ {"dae", "DAE"},
+ {"fbx", "FBX"},
+ {"stl", "STL"},
+ {"3ds", "3DS"},
+ {"3d", "3D"},
+ {"gltf", "glTF"},
+ {"drc", "DRC"},
+ {"rvm", "RVM"},
+ {"pdf", "PDF"},
+ {"x", "X"},
+ {"jt", "JT"},
+ {"dfx", "DFX"},
+ {"ply", "PLY"},
+ {"3mf", "3MF"},
+ {"ase", "ASE"}}))
+
+ Return list.ToArray
+ End Function
+
+ Private Shared Function GetExporterModules() As File3DLoaderModule()
+ Dim list As New List(Of File3DLoaderModule)
+
+ list.Add(New File3DLoaderModule("Simple File Parser",
+ AddressOf ExportViaSimpleFileParser,
+ New Dictionary(Of String, String) From {{"obj", "OBJ"}}))
+
+ AssimpModule.AssimpLoader.LoadAssimpLibs()
+ Dim exts As New Dictionary(Of String, String)
+ For Each fd As Assimp.ExportFormatDescription In AssimpLibrary.Instance.GetExportFormatDescriptions
+ If Not exts.ContainsKey(fd.FileExtension) Then exts.Add(fd.FileExtension, fd.FormatId & " - " & fd.Description)
+ Next
+
+ list.Add(New File3DLoaderModule("Assimp",
+ AddressOf ExportViaAssimp,
+ exts))
+
+ Return list.ToArray
+ End Function
+
+ Private Shared Function LoadViaSimpleFileParser(fileName As String, options As LoaderOptions) As Object3D
+ Return ObjModule.ObjFile.FromFile(fileName, options.LoadMaterials, options.UpAxis)
+ End Function
+
+ Private Shared Function LoadViaAssimp(fileName As String, options As LoaderOptions) As Object3D
+ AssimpModule.AssimpLoader.LoadAssimpLibs()
+ Return AssimpModule.AssimpLoader.FromFile(fileName, options.LoadMaterials, options.UpAxis)
+ End Function
+
+ Private Shared Function LoadViaAspose3D(fileName As String, options As LoaderOptions) As Object3D
+ Return Aspose3DModule.Aspose3DLoader.FromFile(fileName, options.LoadMaterials, options.UpAxis)
+ End Function
+
+ Private Shared Sub ExportViaSimpleFileParser(o As Object3D, fileName As String)
+ ObjModule.ObjFile.ToFile(fileName, o)
+ End Sub
+
+ Private Shared Sub ExportViaAssimp(o As Object3D, fileName As String)
+ AssimpModule.AssimpLoader.LoadAssimpLibs()
+ AssimpModule.AssimpLoader.ToFile(fileName, o)
+ End Sub
+
+End Class
diff --git a/Pilz.Simple3DFileParser/Other/LoaderOptions.vb b/Pilz.Simple3DFileParser/Other/LoaderOptions.vb
new file mode 100644
index 0000000..a41d785
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Other/LoaderOptions.vb
@@ -0,0 +1,14 @@
+Public Class LoaderOptions
+
+ Public Property LoadMaterials As Boolean = False
+ Public Property UpAxis As UpAxis = False
+
+ Public Sub New()
+ End Sub
+
+ Public Sub New(loadMaterials As Boolean, upAxis As UpAxis)
+ Me.LoadMaterials = loadMaterials
+ Me.UpAxis = upAxis
+ End Sub
+
+End Class
diff --git a/Pilz.Simple3DFileParser/Pilz.Simple3DFileParser.vbproj b/Pilz.Simple3DFileParser/Pilz.Simple3DFileParser.vbproj
new file mode 100644
index 0000000..058d877
--- /dev/null
+++ b/Pilz.Simple3DFileParser/Pilz.Simple3DFileParser.vbproj
@@ -0,0 +1,154 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {AC955819-7910-450C-940C-7C1989483D4B}
+ Library
+
+
+ Pilz.S3DFileParser
+ Pilz.Simple3DFileParser
+ 512
+ Windows
+ v4.5
+
+
+
+
+ AnyCPU
+ true
+ full
+ true
+ true
+ bin\Debug\
+ Pilz.Simple3DFileParser.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ AnyCPU
+ pdbonly
+ false
+ true
+ true
+ bin\Release\
+ Pilz.Simple3DFileParser.xml
+ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022
+
+
+ On
+
+
+ Binary
+
+
+ Off
+
+
+ On
+
+
+
+ ..\packages\Aspose.3D.18.4.0\lib\net40\Aspose.3D.dll
+
+
+ False
+ ..\Shared Libs\AssimpNet.dll
+
+
+ ..\..\..\DLL's\ColladaSchema.dll
+
+
+
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\portable-net45+win8+wp8+wpa81\System.Numerics.Vectors.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ Application.myapp
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+ VbMyResourcesResXFileCodeGenerator
+ Resources.Designer.vb
+ My.Resources
+ Designer
+
+
+
+
+ MyApplicationCodeGenerator
+ Application.Designer.vb
+
+
+ SettingsSingleFileGenerator
+ My
+ Settings.Designer.vb
+
+
+
+
+
+
+ {67593ff7-c1d1-4529-98c4-61cbd0615f08}
+ Pilz.LicenseHelper
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Simple3DFileParser/packages.config b/Pilz.Simple3DFileParser/packages.config
new file mode 100644
index 0000000..8267bb7
--- /dev/null
+++ b/Pilz.Simple3DFileParser/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Pilz.Threading/CrossThreadsInvokeing.vb b/Pilz.Threading/CrossThreadsInvokeing.vb
index a37f0ae..a43f643 100644
--- a/Pilz.Threading/CrossThreadsInvokeing.vb
+++ b/Pilz.Threading/CrossThreadsInvokeing.vb
@@ -16,15 +16,17 @@ Imports System.Windows.Forms
Public Class CrossThreadsInvokeing
Public Shared Sub RunAsync(Of T1, T2, T3)(ByVal Action As Action(Of T1, T2, T3), ByVal Arg1 As T1, ByVal Arg2 As T2, ByVal Arg3 As T3)
- ' Aufruf von Action.EndInvoke() gewährleisten, indem er als Callback-Argument mitgegeben wird
Action.BeginInvoke(Arg1, Arg2, Arg3, AddressOf Action.EndInvoke, Nothing)
End Sub
+
Public Shared Sub RunAsync(Of T1, T2)(ByVal Action As Action(Of T1, T2), ByVal Arg1 As T1, ByVal Arg2 As T2)
Action.BeginInvoke(Arg1, Arg2, AddressOf Action.EndInvoke, Nothing)
End Sub
+
Public Shared Sub RunAsync(Of T1)(ByVal Action As Action(Of T1), ByVal Arg1 As T1)
Action.BeginInvoke(Arg1, AddressOf Action.EndInvoke, Nothing)
End Sub
+
Public Shared Sub RunAsync(ByVal Action As Action)
Action.BeginInvoke(AddressOf Action.EndInvoke, Nothing)
End Sub
@@ -32,14 +34,6 @@ Public Class CrossThreadsInvokeing
Private Shared Function GuiCrossInvoke(ByVal Action As [Delegate], ByVal ParamArray Args() As Object) As Boolean
Dim frms As FormCollection = Application.OpenForms
- 'If frms.Count = 0 Then
- ' 'wenn kein Form mehr da ist, so tun, als ob das Invoking ausgeführt wäre
- ' Return True
- 'ElseIf frms(0).InvokeRequired Then
- 'frms(0).BeginInvoke(Action, Args)
- 'Return True
- 'End If
-
If frms.Count > 0 AndAlso frms(0).InvokeRequired Then
frms(0).BeginInvoke(Action, Args)
Return True
@@ -49,15 +43,17 @@ Public Class CrossThreadsInvokeing
End Function
Public Shared Sub RunGui(Of T1, T2, T3)(ByVal Action As Action(Of T1, T2, T3), ByVal Arg1 As T1, ByVal Arg2 As T2, ByVal Arg3 As T3)
- 'falls Invoking nicht erforderlich, die Action direkt ausführen
If Not GuiCrossInvoke(Action, Arg1, Arg2, Arg3) Then Action(Arg1, Arg2, Arg3)
End Sub
+
Public Shared Sub RunGui(Of T1, T2)(ByVal Action As Action(Of T1, T2), ByVal Arg1 As T1, ByVal Arg2 As T2)
If Not GuiCrossInvoke(Action, Arg1, Arg2) Then Action(Arg1, Arg2)
End Sub
+
Public Shared Sub RunGui(Of T1)(ByVal Action As Action(Of T1), ByVal Arg1 As T1)
If Not GuiCrossInvoke(Action, Arg1) Then Action(Arg1)
End Sub
+
Public Shared Sub RunGui(ByVal Action As Action)
If Not GuiCrossInvoke(Action) Then Action()
End Sub
diff --git a/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb b/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb
index 09bb875..d76539a 100644
--- a/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb
+++ b/Pilz.UI/PaintingControl/DefaultDrawMethodes.vb
@@ -31,21 +31,33 @@ Public Class DefaultDrawMethodes
Public Shared Sub DrawPicture(e As PaintingObjectPaintEventArgs)
Dim obj As PaintingObject = e.PaintingObject
Dim objImg As Image
+ Dim objImgSize As Size
Dim result As RectangleF
Dim image As Bitmap
+ Dim zoomf As SizeF
+ Dim hasNoParent As Boolean = e.PaintingObject.Parent Is Nothing
+ Dim syncObj As Object
- SyncLock e.PaintingObject.Parent
+ If hasNoParent Then
+ zoomf = New SizeF(1, 1)
+ Static newSyncObj As New Object
+ syncObj = newSyncObj
+ Else
+ zoomf = e.PaintingObject.Parent.ZoomFactor
+ syncObj = e.PaintingObject.Parent
+ End If
+
+ SyncLock syncObj
If obj?.Image Is Nothing Then Return
objImg = obj.Image
+ objImgSize = objImg.Size
End SyncLock
image = obj.BufferedImage
- result = CalculateImageResolution(obj, objImg.Size)
+ result = CalculateImageResolution(obj, objImgSize, zoomf)
If obj.ImageProperties.Rotate = 90 OrElse obj.ImageProperties.Rotate = 270 Then
- result = CalculateImageResolution(obj, New SizeF(objImg.Size.Height, objImg.Size.Width))
- Else
- result = result
+ result = CalculateImageResolution(obj, New SizeF(objImgSize.Height, objImgSize.Width), zoomf)
End If
If image Is Nothing Then
@@ -71,7 +83,7 @@ Public Class DefaultDrawMethodes
End If
If needRescaleImageBecauseRot Then
- result = CalculateImageResolution(obj, New SizeF(objImg.Size.Height, objImg.Size.Width))
+ result = CalculateImageResolution(obj, New SizeF(objImgSize.Height, objImgSize.Width), zoomf)
image = DrawToNewImage(image, result.Size)
End If
@@ -79,12 +91,15 @@ Public Class DefaultDrawMethodes
End If
If image IsNot Nothing Then
- e.Graphics.DrawImageUnscaled(image, New Rectangle(New Point(obj.Location.X + result.Location.X - e.Offset.X, obj.Location.Y + result.Location.Y - e.Offset.Y), result.Size.ToSize))
+ SyncLock syncObj
+ e.Graphics.DrawImageUnscaled(image, New Rectangle(New Point(obj.Location.X + result.Location.X - e.Offset.X, obj.Location.Y + result.Location.Y - e.Offset.Y), result.Size.ToSize))
+ End SyncLock
End If
End Sub
Private Shared Function DrawToNewImage(image As Bitmap, newSize As SizeF) As Bitmap
- Dim bmp As New Bitmap(CInt(newSize.Width), CInt(newSize.Height))
+ Dim bmp As New Bitmap(CInt(If(newSize.Width < 0, newSize.Width * -1, newSize.Width)),
+ CInt(If(newSize.Height < 0, newSize.Height * -1, newSize.Height)))
Dim gimage As Graphics = Graphics.FromImage(bmp)
gimage.SmoothingMode = SmoothingMode.HighQuality
gimage.PixelOffsetMode = PixelOffsetMode.HighQuality
@@ -103,10 +118,10 @@ Public Class DefaultDrawMethodes
e.Graphics.DrawLine(p2, no, no + obj.Size)
End Sub
- Private Shared Function CalculateImageResolution(obj As PaintingObject, imageSize As SizeF) As RectangleF
+ Private Shared Function CalculateImageResolution(obj As PaintingObject, imageSize As SizeF, zoom As SizeF) As RectangleF
Dim result As New RectangleF
Dim objrect As New RectangleF(obj.Location, obj.Size)
- Dim size As SizeF = imageSize
+ Dim size As SizeF = New SizeF(imageSize.Width * zoom.Width, imageSize.Height * zoom.Height)
Dim clientRectangle As RectangleF = objrect
Dim val As Single = clientRectangle.Width / size.Width
diff --git a/Pilz.UI/PaintingControl/PaintingControl.vb b/Pilz.UI/PaintingControl/PaintingControl.vb
index 5143f04..bbc72a7 100644
--- a/Pilz.UI/PaintingControl/PaintingControl.vb
+++ b/Pilz.UI/PaintingControl/PaintingControl.vb
@@ -107,6 +107,7 @@ Public Class PaintingControl
Set
If _ZoomFactor <> Value Then
_ZoomFactor = Value
+ ResetAllBufferedImages()
RaiseEvent ZoomFactorChanged(Me, New EventArgs)
End If
End Set
@@ -116,6 +117,13 @@ Public Class PaintingControl
DoubleBuffered = True
End Sub
+ Private Sub ResetAllBufferedImages()
+ For Each ob As PaintingObject In PaintingObjects
+ ob.ResetImageBuffer()
+ Next
+ Refresh()
+ End Sub
+
Private Sub CheckKeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown, Me.KeyUp
pressedShift = e.Shift
pressedControl = e.Control
@@ -166,6 +174,7 @@ Public Class PaintingControl
End If
Next
End If
+
If AutoSingleSelection Then
Dim objtosel As PaintingObject = curObjMouseDown
If objtosel?.EnableSelection Then
@@ -218,8 +227,10 @@ Public Class PaintingControl
If _IsMovingObjects Then
_IsMovingObjects = False
+ For Each obj As PaintingObject In GetSelectedObjects()
+ obj.RaiseMoved(New EventArgs)
+ Next
AutoArrangeToGrid()
- 'CalculateScrollValues()
End If
If curObjMouseDown IsNot Nothing Then
@@ -304,43 +315,38 @@ Public Class PaintingControl
End If
Next
End Sub
+
Private Sub UpdateObjectPositions(e As MouseEventArgs)
UpdateObjectPositions(e, GetSelectedObjects)
End Sub
+
Private Sub UpdateObjectPositions(e As MouseEventArgs, objs As IList(Of PaintingObject), Optional movedObjs As List(Of PaintingObject) = Nothing)
If IsResizingObjs(objs) Then Return
If movedObjs Is Nothing Then movedObjs = New List(Of PaintingObject)
- Dim updateprocesses As New List(Of Task)
SuspendDrawing()
For Each obj As PaintingObject In objs
- updateprocesses.Add(Task.Run(
- Sub()
- Dim sp As PointF = savedPos(obj)
+ Dim sp As PointF = savedPos(obj)
- If Not movedObjs.Contains(obj) Then
- UpdateObjectPosition(e, obj, sp)
- movedObjs.Add(obj)
- End If
+ If Not movedObjs.Contains(obj) Then
+ UpdateObjectPosition(e, obj, sp)
+ movedObjs.Add(obj)
+ End If
- If obj.PinnedObjects.Count > 0 Then
- UpdateObjectPositions(e, obj.PinnedObjects, movedObjs)
- movedObjs.AddRange(obj.PinnedObjects.ToArray)
- End If
- End Sub))
- Next
-
- For Each a In updateprocesses
- Do Until a.IsCompleted
- Loop
+ If obj.PinnedObjects.Count > 0 Then
+ UpdateObjectPositions(e, obj.PinnedObjects, movedObjs)
+ movedObjs.AddRange(obj.PinnedObjects.ToArray)
+ End If
Next
ResumeDrawing(False)
End Sub
+
Private Sub UpdateObjectPosition(e As MouseEventArgs, obj As PaintingObject, sp As PointF)
obj.Location = New Point(e.X - sp.X + Offset.X,
e.Y - sp.Y + Offset.Y)
+ obj.RaiseMoving(New EventArgs)
End Sub
Private Function IsResizingObjs(objs As IList(Of PaintingObject)) As Boolean
@@ -355,19 +361,25 @@ Public Class PaintingControl
End Function
Public Function GetObject(p As PointF, Optional UseExtRect As Boolean = False) As PaintingObject
- For Each obj As PaintingObject In PaintingObjects
- If UseExtRect Then
- If HelpfulDrawingFunctions.IsPointInRectangle(p, obj.RectangleExtended) Then
- Return obj
- End If
- Else
- If HelpfulDrawingFunctions.IsPointInRectangle(p, obj.Rectangle) Then
- Return obj
+ Dim val As PaintingObject = Nothing
+
+ For i As Integer = PaintingObjects.Count - 1 To 0 Step -1
+ Dim obj As PaintingObject = PaintingObjects(i)
+
+ If val Is Nothing Then
+ If UseExtRect Then
+ If HelpfulDrawingFunctions.IsPointInRectangle(p, obj.RectangleExtended) Then
+ val = obj
+ End If
+ Else
+ If HelpfulDrawingFunctions.IsPointInRectangle(p, obj.Rectangle) Then
+ val = obj
+ End If
End If
End If
Next
- Return Nothing
+ Return val
End Function
Public Function GetObjects(p As Point) As PaintingObject()
@@ -439,46 +451,6 @@ Public Class PaintingControl
MyBase.OnPaintBackground(e)
End Sub
- Private Function GetCurrentHashValue() As Integer
- Dim hashes As New List(Of Integer)
-
- hashes.AddRange({Offset.X,
- Offset.Y,
- Size.Width,
- Size.Height})
-
- For Each p As PaintingObject In PaintingObjects
- hashes.AddRange({p.Location.X,
- p.Location.Y,
- p.Size.Width,
- p.Size.Height,
- p.DrawMethodes.Count,
- p.FillColor.ToArgb,
- p.OutlineColor.ToArgb,
- p.SelectionColor.ToArgb,
- p.TextColor.ToArgb,
- p.Type,
- p.Text.GetHashCode / p.Text.Length,
- p.Visible,
- p.VerticalTextAlignment,
- p.HorizontalTextAlignment})
- Next
-
- Dim hash As Integer = 0
-
- For Each h As Integer In hashes
- Try
- hash += h
- Catch ex As Exception
- If h <> 0 AndAlso h <> 1 Then
- hash /= h
- End If
- End Try
- Next
-
- Return hash
- End Function
-
Protected Overrides Sub OnPaint(e As PaintEventArgs)
'Do default Drawing Methode
MyBase.OnPaint(e)
@@ -579,6 +551,15 @@ Public Class PaintingControl
End If
End Sub
+ Public Function IsPinnedObject(o As PaintingObject) As Boolean
+ For Each obj As PaintingObject In PaintingObjects
+ If obj.PinnedObjects.Contains(o) Then
+ Return True
+ End If
+ Next
+ Return False
+ End Function
+
Public Sub AutoArrangeToGrid()
If GridEnabled Then
For Each obj As PaintingObject In GetSelectedObjects()
diff --git a/Pilz.UI/PaintingControl/PaintingObject.vb b/Pilz.UI/PaintingControl/PaintingObject.vb
index 5ceaa73..97c90d8 100644
--- a/Pilz.UI/PaintingControl/PaintingObject.vb
+++ b/Pilz.UI/PaintingControl/PaintingObject.vb
@@ -47,6 +47,7 @@ Imports Newtonsoft.Json
Public Property MouseTransparency As Boolean = False
Public ReadOnly Property Layering As New PaintingObjectLayering(Me)
Public ReadOnly Property PaintingObjects As New PaintingObjectList(_Parent) With {.EnableRaisingEvents = False}
+ Public ReadOnly Property ErrorsAtDrawing As ULong = 0
Public Event MouseClick(sender As PaintingObject, e As MouseEventArgs)
Public Event MouseDown(sender As PaintingObject, e As MouseEventArgs)
@@ -56,6 +57,8 @@ Imports Newtonsoft.Json
Public Event Paint(sender As PaintingObject, e As PaintEventArgs)
Public Event ParentChanged(sender As PaintingObject, e As EventArgs)
Public Event VisibleChanged(sender As PaintingObject, e As EventArgs)
+ Public Event Moved(sender As PaintingObject, e As EventArgs)
+ Public Event Moving(sender As PaintingObject, e As EventArgs)
Public Sub New()
End Sub
@@ -69,21 +72,27 @@ Imports Newtonsoft.Json
Me.DrawMethodes.AddRange(drawMethodes)
End Sub
- Public Sub RaiseMouseClick(e As MouseEventArgs)
+ Friend Sub RaiseMouseClick(e As MouseEventArgs)
RaiseEvent MouseClick(Me, e)
End Sub
- Public Sub RaiseMouseDown(e As MouseEventArgs)
+ Friend Sub RaiseMouseDown(e As MouseEventArgs)
RaiseEvent MouseDown(Me, e)
End Sub
- Public Sub RaiseMouseUp(e As MouseEventArgs)
+ Friend Sub RaiseMouseUp(e As MouseEventArgs)
RaiseEvent MouseUp(Me, e)
End Sub
- Public Sub RaiseMouseMove(e As MouseEventArgs)
+ Friend Sub RaiseMouseMove(e As MouseEventArgs)
RaiseEvent MouseMove(Me, e)
End Sub
Private Sub RaisePaint(e As PaintEventArgs)
RaiseEvent Paint(Me, e)
End Sub
+ Friend Sub RaiseMoved(e As EventArgs)
+ RaiseEvent Moved(Me, e)
+ End Sub
+ Friend Sub RaiseMoving(e As EventArgs)
+ RaiseEvent Moving(Me, e)
+ End Sub
Public Property Type As PaintingObjectType
Get
@@ -376,16 +385,22 @@ Imports Newtonsoft.Json
End Set
End Property
- Public ReadOnly Property Right As Integer
+ Public Property Right As Integer
Get
Return X + Width
End Get
+ Set(value As Integer)
+ X = value - Width
+ End Set
End Property
- Public ReadOnly Property Bottom() As Integer
+ Public Property Bottom() As Integer
Get
Return Y + Height
End Get
+ Set(value As Integer)
+ Y = value - Height
+ End Set
End Property
Public Property EnableResize As Boolean
@@ -439,7 +454,11 @@ Imports Newtonsoft.Json
Dim poevargs As New PaintingObjectPaintEventArgs(Me, g, offset)
For Each dm As DelegateDrawPaintingObjectMethode In DrawMethodes
- dm?.Invoke(poevargs)
+ Try
+ dm?.Invoke(poevargs)
+ Catch ex As Exception
+ _ErrorsAtDrawing += 1
+ End Try
Next
If Selected AndAlso DrawSelectionMethode IsNot Nothing Then
@@ -454,20 +473,27 @@ Imports Newtonsoft.Json
Public Function Clone(includePinnedObject As Boolean) As Object
Dim obj As New PaintingObject
- Dim t As Type = Me.GetType
- Dim blackField As New List(Of String) From {
+ Dim metype As Type = Me.GetType
+ Dim blackField As String() = {
NameOf(_PinnedObjects),
NameOf(resizeEngine),
NameOf(_Parent),
- NameOf(BufferedImage)
+ NameOf(BufferedImage),
+ NameOf(_ImageProperties)
}
- Dim fields As FieldInfo() = t.GetFields(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.IgnoreCase Or BindingFlags.Instance)
- For Each field As FieldInfo In fields
- If Not blackField.Contains(field.Name) Then
- field.SetValue(obj, field.GetValue(Me))
- End If
- Next
+ Dim copyFields =
+ Sub(source As Object, dest As Object, blackFields As String(), t As Type)
+ Dim fields As New List(Of FieldInfo)(t.GetFields(BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.IgnoreCase Or BindingFlags.Instance))
+ For Each field As FieldInfo In fields
+ If Not blackFields.Contains(field.Name) Then
+ field.SetValue(dest, field.GetValue(source))
+ End If
+ Next
+ End Sub
+
+ copyFields(Me, obj, blackField, metype)
+ copyfields(ImageProperties, obj.ImageProperties, {}, ImageProperties.GetType)
If includePinnedObject Then
obj.PinnedObjects.AddRange(PinnedObjects)
diff --git a/Pilz.UI/PaintingControl/PaintingObjectResizing.vb b/Pilz.UI/PaintingControl/PaintingObjectResizing.vb
index 002e303..76f1b9a 100644
--- a/Pilz.UI/PaintingControl/PaintingObjectResizing.vb
+++ b/Pilz.UI/PaintingControl/PaintingObjectResizing.vb
@@ -95,8 +95,12 @@ Imports Pilz.Drawing
ElseIf Not mMouseDown Then
- Dim eX As Integer = e.X - mObj.X + mObj.Parent.Offset.X
- Dim eY As Integer = e.Y - mObj.Y + mObj.Parent.Offset.Y
+ Dim eXo As Integer = e.X
+ Dim eYo As Integer = e.Y
+ Dim eXwo As Integer = eXo - mObj.X
+ Dim eYwo As Integer = eYo - mObj.Y
+ Dim eX As Integer = eXwo + mObj.Parent.Offset.X
+ Dim eY As Integer = eYwo + mObj.Parent.Offset.Y
Dim eLocation As New Point(eX, eY)
Dim extRect As RectangleF = mObj.RectangleExtended
Dim oldRect As RectangleF = mObj.Rectangle
@@ -108,8 +112,9 @@ Imports Pilz.Drawing
newRect.Height = (extRect.Height - oldRect.Height) / 2
Dim setToNone As Boolean = False
+ Dim isOnTop As Boolean = mObj.Parent.GetObject(New PointF(eXo, eYo), True) Is mObj
- If Enabled Then
+ If Enabled AndAlso isOnTop Then
Select Case True
Case HelpfulDrawingFunctions.IsPointInRectangle(eLocation, New Rectangle(newRect.X, newRect.Y, newRect.Width, newRect.Height))
mObj.Cursor = Cursors.SizeNWSE
diff --git a/Pilz.sln b/Pilz.sln
index f366730..aba4084 100644
--- a/Pilz.sln
+++ b/Pilz.sln
@@ -23,6 +23,12 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Configuration", "Pilz.
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Reflection.PluginSystem", "Pilz.Reflection.PluginSystem\Pilz.Reflection.PluginSystem.vbproj", "{F7975470-4CA3-4FAB-BB6A-A3AF3978ABB7}"
EndProject
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Drawing.Drawing3D.OpenGLFactory", "Pilz.Drawing.Drawing3D.OpenGLRenderer\Pilz.Drawing.Drawing3D.OpenGLFactory.vbproj", "{5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}"
+EndProject
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pilz.Simple3DFileParser", "Pilz.Simple3DFileParser\Pilz.Simple3DFileParser.vbproj", "{AC955819-7910-450C-940C-7C1989483D4B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pilz.LicenseHelper", "Pilz.LicenseHelper\Pilz.LicenseHelper.csproj", "{67593FF7-C1D1-4529-98C4-61CBD0615F08}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -111,6 +117,30 @@ Global
{F7975470-4CA3-4FAB-BB6A-A3AF3978ABB7}.Release|Any CPU.Build.0 = Release|Any CPU
{F7975470-4CA3-4FAB-BB6A-A3AF3978ABB7}.Release|x86.ActiveCfg = Release|Any CPU
{F7975470-4CA3-4FAB-BB6A-A3AF3978ABB7}.Release|x86.Build.0 = Release|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Debug|x86.Build.0 = Debug|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Release|x86.ActiveCfg = Release|Any CPU
+ {5E9F0B0A-F7B8-49A9-80FC-6DFE0D44CC84}.Release|x86.Build.0 = Release|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Debug|x86.Build.0 = Debug|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Release|x86.ActiveCfg = Release|Any CPU
+ {AC955819-7910-450C-940C-7C1989483D4B}.Release|x86.Build.0 = Release|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Debug|x86.Build.0 = Debug|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Release|x86.ActiveCfg = Release|Any CPU
+ {67593FF7-C1D1-4529-98C4-61CBD0615F08}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE