March 20, 2019, 04:00:11 AM

Author Topic: OpenB3D: TQuaternion function issue  (Read 855 times)

Offline Krischan

  • Full Member
  • ***
  • Posts: 192
    • Krischan's Homepage
OpenB3D: TQuaternion function issue
« on: October 26, 2017, 09:09:21 PM »
I digged out a cool demo I wrote in miniB3D before I started with OpenB3D but I can't get it running in OpenB3D (it still runs fine in miniB3D). I compared the two TQuaternion.bmx includes and something has changed in OpenB3D with some vars but I don't know how to fix my code. Do you know what I need to change?

Just uncomment the "Framework openb3d.b3dglgraphics" line and comment or delete the "Framework sidesign.minib3d" line.

Code: BlitzMax
  1. SuperStrict
  2.  
  3. Framework sidesign.minib3d
  4. 'Framework openb3d.b3dglgraphics
  5.  
  6. Graphics3D DesktopWidth(), DesktopHeight(), 32, 2
  7.  
  8. SeedRnd 1
  9.  
  10. Const eccentricity:Float = 45           ' angle between 0 and 90
  11. Const planets:Int = 10                          ' number of planets
  12. Const speed:Float = 0.1                         ' simulation speed
  13. Const maxsegments:Int = 1440            ' maximum segments of outer planet orbit
  14.  
  15. Global MouseWheel:Int = 1
  16.  
  17. ' ------------------------------------------------------------------------------------------------
  18. ' Initialize Scene and Camera
  19. ' ------------------------------------------------------------------------------------------------
  20. Global pivot:TPivot = CreatePivot()
  21.  
  22. Global cam:TCamera = CreateCamera(pivot)
  23. PositionEntity cam, 0, 5, -15
  24.  
  25. Global star:TMesh = CreateSphere(32)
  26. ScaleEntity star, 0.5, 0.5, 0.5
  27. EntityColor star, 255, 192, 0
  28. EntityFX star, 1
  29.  
  30. PointEntity cam, star
  31.  
  32. ' ------------------------------------------------------------------------------------------------
  33. ' Stores Planet properties
  34. ' ------------------------------------------------------------------------------------------------
  35. Type TPlanet
  36.  
  37.         Field id:Int
  38.         Field rotation:Float[]
  39.         Field ent:TEntity
  40.         Field piv:TPivot
  41.         Field radius:Float
  42.         Field rgb:Int[] = [255, 255, 255]
  43.        
  44.         Field orbit:TOrbit = New TOrbit
  45.        
  46. End Type
  47.  
  48. ' ------------------------------------------------------------------------------------------------
  49. ' Stores Orbit Coordinates
  50. ' ------------------------------------------------------------------------------------------------
  51. Type TOrbit
  52.  
  53.         Field steps:Float
  54.         Field x:Float[maxsegments + 1]
  55.         Field y:Float[maxsegments + 1]
  56.         Field z:Float[maxsegments + 1]
  57.  
  58. End Type
  59.  
  60. ' ------------------------------------------------------------------------------------------------
  61. ' Initialize Planets
  62. ' ------------------------------------------------------------------------------------------------
  63. Global planetlist:TList = CreateList()
  64. Global p:TPlanet
  65.  
  66. For Local i:Int = 1 To planets
  67.        
  68.         p = New TPlanet
  69.         p.id = i
  70.         p.radius = Normalize(i, 1, planets, 1, 10)
  71.         p.rotation = [Float(Rnd(-eccentricity, eccentricity)), Float(Rnd(360)), 0.0]
  72.         p.rgb = [Rand(255), Rand(255), Rand(255)]
  73.        
  74.         p.orbit.steps = maxsegments / (planets + 1 - p.id)
  75.        
  76.         ' planet pivot
  77.         p.piv = CreatePivot()
  78.        
  79.         ' create planet
  80.         p.ent = CreateSphere(8, p.piv)
  81.         EntityFX p.ent, 1
  82.         'EntityColor p.ent, p.rgb[0], p.rgb[1], p.rgb[2]
  83.         ScaleEntity p.ent, 0.1, 0.1, 0.1
  84.        
  85.         ' pivot initial rotation
  86.         RotateEntity p.piv, 0, 0, 0
  87.         Turn p.piv, p.rotation[0], p.rotation[1], p.rotation[2]
  88.        
  89.         ' position planet
  90.         PositionEntity p.ent, 0, 0, 0
  91.         MoveEntity p.ent, 0, 0, p.radius
  92.        
  93.         ListAddLast planetlist, p
  94.  
  95.         ' store current position in Type for later use
  96.         For Local i:Int = 0 To p.orbit.steps
  97.        
  98.                 p.orbit.x[i] = EntityX(p.ent, 1)
  99.                 p.orbit.y[i] = EntityY(p.ent, 1)
  100.                 p.orbit.z[i] = EntityZ(p.ent, 1)
  101.                
  102.                 ' rotate pivot
  103.                 Turn p.piv, 0, 360.0 / p.orbit.steps, 0
  104.                                
  105.         Next
  106.                
  107. Next
  108.  
  109. MoveMouse GraphicsWidth() / 2, GraphicsHeight() / 2
  110.  
  111. ' Mousewheel logic
  112. AddHook EmitEventHook, EventHook
  113.  
  114. ' ------------------------------------------------------------------------------------------------
  115. ' Main Loop
  116. ' ------------------------------------------------------------------------------------------------
  117. While Not AppTerminate()
  118.  
  119.         If KeyHit(KEY_ESCAPE) Then End
  120.        
  121.         Turn pivot, Normalize(MouseY(), 0, GraphicsHeight() - 1, -1, 1), Normalize(MouseX(), 0, GraphicsWidth() - 1, 1, -1), 0
  122.                                
  123.         CameraZoom cam, MouseWheel
  124.        
  125.         RenderWorld
  126.        
  127.         ' enable OpenGL Lines
  128.         ' it is IMPORTANT to use this between Renderworld and BeginMax2D or it won't work
  129.         glEnable(GL_COLOR_MATERIAL)
  130.         glBegin(GL_LINES)
  131.        
  132.         Local x1:Float, y1:Float, z1:Float
  133.         Local x2:Float, y2:Float, z2:Float
  134.        
  135.         ' cycle all planets
  136.         For Local p:TPlanet = EachIn planetlist
  137.                        
  138.                 ' a full rotation
  139.                 For Local i:Int = 0 To p.orbit.steps
  140.                
  141.                         ' look ahead for next XYZ position
  142.                         Local j:Int = (i + 1) Mod p.orbit.steps
  143.                        
  144.                         ' get current coordinates
  145.                         x1 = p.orbit.x[i]
  146.                         y1 = p.orbit.y[i]
  147.                         z1 = p.orbit.z[i]
  148.                                                
  149.                         ' get next coordinates
  150.                         x2 = p.orbit.x[j]
  151.                         y2 = p.orbit.y[j]
  152.                         z2 = p.orbit.z[j]
  153.                                        
  154.                         ' draw 3D line
  155.                         Line3D(x1, y1, z1, x2, y2, z2, p.rgb[0], p.rgb[1], p.rgb[2], 1)
  156.  
  157.                 Next
  158.  
  159.                 ' turn pivot = move planet around star
  160.                 Turn p.piv, 0, (planets + 1 - p.radius) * speed, 0
  161.                                
  162.         Next
  163.        
  164.         glEnd
  165.         glDisable(GL_COLOR_MATERIAL)
  166.        
  167.         BeginMax2D()
  168.        
  169.                 DrawText "Maximum Eccentricity: " + eccentricity, 0, 0
  170.        
  171.         EndMax2D()
  172.        
  173.         Flip True
  174.  
  175. Wend
  176.  
  177. End
  178.  
  179. ' ------------------------------------------------------------------------------------------------
  180. ' Normalizes a value to given range
  181. ' ------------------------------------------------------------------------------------------------
  182. Function Normalize:Float(Value:Float, vmin:Float, vmax:Float, nmin:Float, nmax:Float, limit:Int = False)
  183.  
  184.         ' normalize    
  185.         Local result:Float = ((Value - vmin) / (vmax - vmin)) * (nmax - nmin) + nmin
  186.  
  187.         ' limit
  188.         If limit Then
  189.        
  190.                 If Value >= nmax Then result = nmax
  191.                 If Value <= nmin Then result = nmin
  192.  
  193.         EndIf
  194.  
  195.         Return result
  196.        
  197. End Function
  198.  
  199. ' ------------------------------------------------------------------------------------------------
  200. ' Draw a 3D line using OpenGL functions:
  201. ' glEnable(GL_COLOR_MATERIAL) / glBegin(GL_LINES) [...] glEnd() / glDisable(GL_COLOR_MATERIAL)
  202. ' ------------------------------------------------------------------------------------------------
  203. Function Line3D:TMesh(x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float, r:Int = 255, g:Int = 255, b:Int = 255, a:Float = 1.0)
  204.                
  205.         SetColor r, g, b
  206.         SetAlpha(a)
  207.                
  208.         glVertex3f(x0, y0, -z0)
  209.         glVertex3f(x1, y1, -z1)
  210.        
  211.         SetAlpha(1.0)
  212.                        
  213. End Function
  214.  
  215. ' ------------------------------------------------------------------------------------------------
  216. ' Turn Entity using Quaternions
  217. ' ------------------------------------------------------------------------------------------------
  218. Function Turn(Ent:TEntity, X:Float, Y:Float, Z:Float, Glob:Int = False)
  219.  
  220.         Local Pitch:Float = 0.0
  221.         Local Yaw:Float = 0.0
  222.         Local Roll:Float = 0.0
  223.        
  224.         Local Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  225.         Local Turn_Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  226.        
  227.         If Glob = False
  228.        
  229.                 Quat = EulerToQuat(EntityPitch(Ent, True), EntityYaw(Ent, True), EntityRoll(Ent, True))
  230.                 Turn_Quat = EulerToQuat(X, Y, Z)
  231.                 Quat = MultiplyQuats(Quat, Turn_Quat)
  232.                 Quat = NormalizeQuat(Quat)
  233.                 QuatToEuler2(Quat.x, Quat.y, Quat.z, Quat.w, Pitch, Yaw, Roll)
  234.                 RotateEntity Ent, Pitch, Yaw, Roll
  235.         Else
  236.        
  237.                 RotateEntity Ent, EntityPitch(Ent) + X, EntityYaw(Ent) + Y, EntityRoll(Ent) + Z
  238.                
  239.         EndIf
  240.        
  241. End Function
  242.  
  243. ' ------------------------------------------------------------------------------------------------
  244. ' Euler to Quaternion
  245. ' ------------------------------------------------------------------------------------------------
  246. Function EulerToQuat:TQuaternion(pitch:Float, yaw:Float, roll:Float)
  247.  
  248.         Local cr:Float = Cos(-roll / 2.0)
  249.         Local cp:Float = Cos(pitch / 2.0)
  250.         Local cy:Float = Cos(yaw / 2.0)
  251.         Local sr:Float = Sin(-roll / 2.0)
  252.         Local sp:Float = Sin(pitch / 2.0)
  253.         Local sy:Float = Sin(yaw / 2.0)
  254.         Local cpcy:Float = cp * cy
  255.         Local spsy:Float = sp * sy
  256.         Local spcy:Float = sp * cy
  257.         Local cpsy:Float = cp * sy
  258.        
  259.         Local q:TQuaternion = New TQuaternion
  260.        
  261.         q.w:Float = cr * cpcy + sr * spsy
  262.         q.x:Float = sr * cpcy - cr * spsy
  263.         q.y:Float = cr * spcy + sr * cpsy
  264.         q.z:Float = cr * cpsy - sr * spcy
  265.        
  266.         Return q
  267.        
  268. End Function
  269.  
  270. ' ------------------------------------------------------------------------------------------------
  271. ' Quaternion to Euler
  272. ' ------------------------------------------------------------------------------------------------
  273. Function QuatToEuler2(x:Float, y:Float, z:Float, w:Float, pitch:Float Var, yaw:Float Var, roll:Float Var)
  274.  
  275.         Local QuatToEulerAccuracy:Double = 1.0 / 2 ^ 31
  276.  
  277.         Local sint:Float = (2.0 * w * y) - (2.0 * x * z)
  278.         Local cost_temp:Float = 1.0 - (sint * sint)
  279.         Local cost:Float
  280.  
  281.         If Abs(cost_temp) > QuatToEulerAccuracy
  282.  
  283.                 cost = Sqr(cost_temp)
  284.  
  285.         Else
  286.  
  287.                 cost = 0.0
  288.  
  289.         EndIf
  290.  
  291.         Local sinv:Float, cosv:Float, sinf:Float, cosf:Float
  292.        
  293.         If Abs(cost) > QuatToEulerAccuracy
  294.        
  295.                 sinv = ((2.0 * y * z) + (2.0 * w * x)) / cost
  296.                 cosv = (1.0 - (2.0 * x * x) - (2.0 * y * y)) / cost
  297.                 sinf = ((2.0 * x * y) + (2.0 * w * z)) / cost
  298.                 cosf = (1.0 - (2.0 * y * y) - (2.0 * z * z)) / cost
  299.                
  300.         Else
  301.                
  302.                 sinv = (2.0 * w * x) - (2.0 * y * z)
  303.                 cosv = 1.0 - (2.0 * x * x) - (2.0 * z * z)
  304.                 sinf = 0.0
  305.                 cosf = 1.0
  306.                
  307.         EndIf
  308.        
  309.         pitch = ATan2(sint, cost)
  310.         yaw = ATan2(sinf, cosf)
  311.         roll = -ATan2(sinv, cosv)
  312.        
  313. End Function
  314.  
  315. ' ------------------------------------------------------------------------------------------------
  316. ' Multiply Quaternion
  317. ' ------------------------------------------------------------------------------------------------
  318. Function MultiplyQuats:TQuaternion(q1:TQuaternion, q2:TQuaternion)
  319.  
  320.         Local q:TQuaternion = New TQuaternion
  321.        
  322.         q.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
  323.         q.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
  324.         q.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z
  325.         q.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
  326.  
  327.         Return q
  328.  
  329. End Function
  330.  
  331. ' ------------------------------------------------------------------------------------------------
  332. ' Normalize Quaternion
  333. ' ------------------------------------------------------------------------------------------------
  334. Function NormalizeQuat:TQuaternion(q:TQuaternion)
  335.  
  336.         Local uv:Float = Sqr(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z)
  337.  
  338.         q.w = q.w / uv
  339.         q.x = q.x / uv
  340.         q.y = q.y / uv
  341.         q.z = q.z / uv
  342.  
  343.         Return q
  344.  
  345. End Function
  346.  
  347. ' ------------------------------------------------------------------------------------------------
  348. ' Events
  349. ' ------------------------------------------------------------------------------------------------
  350. Function EventHook:Object(id:Int, Data:Object, Context:Object)
  351.  
  352.         Local Event:TEvent = TEvent(data)
  353.         If Event = Null Then Return Event
  354.  
  355.         Select Event.id
  356.                                                        
  357.                 Case EVENT_MOUSEWHEEL
  358.                                                
  359.                         If Event.Data > 0 Then
  360.  
  361.                                 MouseWheel:+1
  362.                                 If MouseWheel > 5 Then MouseWheel = 5
  363.  
  364.                                 Else
  365.  
  366.                                         MouseWheel:-1
  367.                                 If MouseWheel < 1 Then MouseWheel = 1
  368.  
  369.                         EndIf
  370.  
  371.         End Select
  372.        
  373. End Function
Kind regards
Krischan

Windows 10 Pro | i7 9700K@ 3.6GHz | RTX 2080 8GB]
My Blitzbasic Archive | Extrasolar Project

Offline markcwm

  • Sr. Member
  • ****
  • Posts: 351
Re: OpenB3D: TQuaternion function issue
« Reply #1 on: October 27, 2017, 11:13:33 PM »
Hi,

yes I changed Quaternions to a wrapper for Openb3d's because I noticed they didn't work exactly the same when I was porting the 3DS loader from Warner, the old quats were from Minib3d. So now you just use q:TQuaternion=CreateQuaternion() instead of New and q.w is now a pointer so q.w[0] etc. I edited your demo and it works fine now. I like what you're doing here, I might add some of these functions to the wrapper if that's okay. Where did you get the quat functions from?

Code: BlitzMax
  1.     SuperStrict
  2.      
  3.     'Framework sidesign.minib3d
  4.     Framework openb3d.b3dglgraphics
  5.      
  6.     Graphics3D DesktopWidth(), DesktopHeight(), 32, 2
  7.      
  8.     SeedRnd 1
  9.      
  10.     Const eccentricity:Float = 45           ' angle between 0 and 90
  11.     Const planets:Int = 10                          ' number of planets
  12.     Const speed:Float = 0.1                         ' simulation speed
  13.     Const maxsegments:Int = 1440            ' maximum segments of outer planet orbit
  14.      
  15.     Global MouseWheel:Int = 1
  16.      
  17.     ' ------------------------------------------------------------------------------------------------
  18.     ' Initialize Scene and Camera
  19.     ' ------------------------------------------------------------------------------------------------
  20.     Global pivot:TPivot = CreatePivot()
  21.      
  22.     Global cam:TCamera = CreateCamera(pivot)
  23.     PositionEntity cam, 0, 5, -15
  24.      
  25.     Global star:TMesh = CreateSphere(32)
  26.     ScaleEntity star, 0.5, 0.5, 0.5
  27.     EntityColor star, 255, 192, 0
  28.     EntityFX star, 1
  29.      
  30.     PointEntity cam, star
  31.      
  32.     ' ------------------------------------------------------------------------------------------------
  33.     ' Stores Planet properties
  34.     ' ------------------------------------------------------------------------------------------------
  35.     Type TPlanet
  36.      
  37.             Field id:Int
  38.             Field rotation:Float[]
  39.             Field ent:TEntity
  40.             Field piv:TPivot
  41.             Field radius:Float
  42.             Field rgb:Int[] = [255, 255, 255]
  43.            
  44.             Field orbit:TOrbit = New TOrbit
  45.            
  46.     End Type
  47.      
  48.     ' ------------------------------------------------------------------------------------------------
  49.     ' Stores Orbit Coordinates
  50.     ' ------------------------------------------------------------------------------------------------
  51.     Type TOrbit
  52.      
  53.             Field steps:Float
  54.             Field x:Float[maxsegments + 1]
  55.             Field y:Float[maxsegments + 1]
  56.             Field z:Float[maxsegments + 1]
  57.      
  58.     End Type
  59.      
  60.     ' ------------------------------------------------------------------------------------------------
  61.     ' Initialize Planets
  62.     ' ------------------------------------------------------------------------------------------------
  63.     Global planetlist:TList = CreateList()
  64.     Global p:TPlanet
  65.      
  66.     For Local i:Int = 1 To planets
  67.            
  68.             p = New TPlanet
  69.             p.id = i
  70.             p.radius = Normalize(i, 1, planets, 1, 10)
  71.             p.rotation = [Float(Rnd(-eccentricity, eccentricity)), Float(Rnd(360)), 0.0]
  72.             p.rgb = [Rand(255), Rand(255), Rand(255)]
  73.            
  74.             p.orbit.steps = maxsegments / (planets + 1 - p.id)
  75.            
  76.             ' planet pivot
  77.             p.piv = CreatePivot()
  78.            
  79.             ' create planet
  80.             p.ent = CreateSphere(8, p.piv)
  81.             EntityFX p.ent, 1
  82.             'EntityColor p.ent, p.rgb[0], p.rgb[1], p.rgb[2]
  83.             ScaleEntity p.ent, 0.1, 0.1, 0.1
  84.            
  85.             ' pivot initial rotation
  86.             RotateEntity p.piv, 0, 0, 0
  87.             Turn p.piv, p.rotation[0], p.rotation[1], p.rotation[2]
  88.            
  89.             ' position planet
  90.             PositionEntity p.ent, 0, 0, 0
  91.             MoveEntity p.ent, 0, 0, p.radius
  92.            
  93.             ListAddLast planetlist, p
  94.      
  95.             ' store current position in Type for later use
  96.             For Local i:Int = 0 To p.orbit.steps
  97.            
  98.                     p.orbit.x[i] = EntityX(p.ent, 1)
  99.                     p.orbit.y[i] = EntityY(p.ent, 1)
  100.                     p.orbit.z[i] = EntityZ(p.ent, 1)
  101.                    
  102.                     ' rotate pivot
  103.                     Turn p.piv, 0, 360.0 / p.orbit.steps, 0
  104.                                    
  105.             Next
  106.                    
  107.     Next
  108.      
  109.     MoveMouse GraphicsWidth() / 2, GraphicsHeight() / 2
  110.      
  111.     ' Mousewheel logic
  112.     AddHook EmitEventHook, EventHook
  113.      
  114.     ' ------------------------------------------------------------------------------------------------
  115.     ' Main Loop
  116.     ' ------------------------------------------------------------------------------------------------
  117.     While Not AppTerminate()
  118.      
  119.             If KeyHit(KEY_ESCAPE) Then End
  120.            
  121.             Turn pivot, Normalize(MouseY(), 0, GraphicsHeight() - 1, -1, 1), Normalize(MouseX(), 0, GraphicsWidth() - 1, 1, -1), 0
  122.                                    
  123.             CameraZoom cam, MouseWheel
  124.            
  125.             RenderWorld
  126.            
  127.             ' enable OpenGL Lines
  128.             ' it is IMPORTANT to use this between Renderworld and BeginMax2D or it won't work
  129.             glEnable(GL_COLOR_MATERIAL)
  130.             glBegin(GL_LINES)
  131.            
  132.             Local x1:Float, y1:Float, z1:Float
  133.             Local x2:Float, y2:Float, z2:Float
  134.            
  135.             ' cycle all planets
  136.             For Local p:TPlanet = EachIn planetlist
  137.                            
  138.                     ' a full rotation
  139.                     For Local i:Int = 0 To p.orbit.steps
  140.                    
  141.                             ' look ahead for next XYZ position
  142.                             Local j:Int = (i + 1) Mod p.orbit.steps
  143.                            
  144.                             ' get current coordinates
  145.                             x1 = p.orbit.x[i]
  146.                             y1 = p.orbit.y[i]
  147.                             z1 = p.orbit.z[i]
  148.                                                    
  149.                             ' get next coordinates
  150.                             x2 = p.orbit.x[j]
  151.                             y2 = p.orbit.y[j]
  152.                             z2 = p.orbit.z[j]
  153.                                            
  154.                             ' draw 3D line
  155.                             Line3D(x1, y1, z1, x2, y2, z2, p.rgb[0], p.rgb[1], p.rgb[2], 1)
  156.      
  157.                     Next
  158.      
  159.                     ' turn pivot = move planet around star
  160.                     Turn p.piv, 0, (planets + 1 - p.radius) * speed, 0
  161.                                    
  162.             Next
  163.            
  164.             glEnd
  165.             glDisable(GL_COLOR_MATERIAL)
  166.            
  167.             BeginMax2D()
  168.            
  169.                     DrawText "Maximum Eccentricity: " + eccentricity, 0, 0
  170.            
  171.             EndMax2D()
  172.            
  173.             Flip True
  174.      
  175.     Wend
  176.      
  177.     End
  178.      
  179.     ' ------------------------------------------------------------------------------------------------
  180.     ' Normalizes a value to given range
  181.     ' ------------------------------------------------------------------------------------------------
  182.     Function Normalize:Float(Value:Float, vmin:Float, vmax:Float, nmin:Float, nmax:Float, limit:Int = False)
  183.      
  184.             ' normalize    
  185.             Local result:Float = ((Value - vmin) / (vmax - vmin)) * (nmax - nmin) + nmin
  186.      
  187.             ' limit
  188.             If limit Then
  189.            
  190.                     If Value >= nmax Then result = nmax
  191.                     If Value <= nmin Then result = nmin
  192.      
  193.             EndIf
  194.      
  195.             Return result
  196.            
  197.     End Function
  198.      
  199.     ' ------------------------------------------------------------------------------------------------
  200.     ' Draw a 3D line using OpenGL functions:
  201.     ' glEnable(GL_COLOR_MATERIAL) / glBegin(GL_LINES) [...] glEnd() / glDisable(GL_COLOR_MATERIAL)
  202.     ' ------------------------------------------------------------------------------------------------
  203.     Function Line3D:TMesh(x0:Float, y0:Float, z0:Float, x1:Float, y1:Float, z1:Float, r:Int = 255, g:Int = 255, b:Int = 255, a:Float = 1.0)
  204.                    
  205.             SetColor r, g, b
  206.             SetAlpha(a)
  207.                    
  208.             glVertex3f(x0, y0, -z0)
  209.             glVertex3f(x1, y1, -z1)
  210.            
  211.             SetAlpha(1.0)
  212.                            
  213.     End Function
  214.      
  215.     ' ------------------------------------------------------------------------------------------------
  216.     ' Turn Entity using Quaternions
  217.     ' ------------------------------------------------------------------------------------------------
  218.     Function Turn(Ent:TEntity, X:Float, Y:Float, Z:Float, Glob:Int = False)
  219.      
  220.             Local Pitch:Float = 0.0
  221.             Local Yaw:Float = 0.0
  222.             Local Roll:Float = 0.0
  223.            
  224.             Local Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  225.             Local Turn_Quat:TQuaternion = EulerToQuat(0.0, 0.0, 0.0)
  226.            
  227.             If Glob = False
  228.            
  229.                     Quat = EulerToQuat(EntityPitch(Ent, True), EntityYaw(Ent, True), EntityRoll(Ent, True))
  230.                     Turn_Quat = EulerToQuat(X, Y, Z)
  231.                     Quat = MultiplyQuats(Quat, Turn_Quat)
  232.                     Quat = NormalizeQuat(Quat)
  233.                     QuatToEuler2(Quat.x[0], Quat.y[0], Quat.z[0], Quat.w[0], Pitch, Yaw, Roll)
  234.                     RotateEntity Ent, Pitch, Yaw, Roll
  235.             Else
  236.            
  237.                     RotateEntity Ent, EntityPitch(Ent) + X, EntityYaw(Ent) + Y, EntityRoll(Ent) + Z
  238.                    
  239.             EndIf
  240.            
  241.     End Function
  242.      
  243.     ' ------------------------------------------------------------------------------------------------
  244.     ' Euler to Quaternion
  245.     ' ------------------------------------------------------------------------------------------------
  246.     Function EulerToQuat:TQuaternion(pitch:Float, yaw:Float, roll:Float)
  247.      
  248.             Local cr:Float = Cos(-roll / 2.0)
  249.             Local cp:Float = Cos(pitch / 2.0)
  250.             Local cy:Float = Cos(yaw / 2.0)
  251.             Local sr:Float = Sin(-roll / 2.0)
  252.             Local sp:Float = Sin(pitch / 2.0)
  253.             Local sy:Float = Sin(yaw / 2.0)
  254.             Local cpcy:Float = cp * cy
  255.             Local spsy:Float = sp * sy
  256.             Local spcy:Float = sp * cy
  257.             Local cpsy:Float = cp * sy
  258.            
  259.             Local q:TQuaternion = CreateQuaternion()
  260.            
  261.             q.w[0] = cr * cpcy + sr * spsy
  262.             q.x[0] = sr * cpcy - cr * spsy
  263.             q.y[0] = cr * spcy + sr * cpsy
  264.             q.z[0] = cr * cpsy - sr * spcy
  265.            
  266.             Return q
  267.            
  268.     End Function
  269.      
  270.     ' ------------------------------------------------------------------------------------------------
  271.     ' Quaternion to Euler
  272.     ' ------------------------------------------------------------------------------------------------
  273.     Function QuatToEuler2(x:Float, y:Float, z:Float, w:Float, pitch:Float Var, yaw:Float Var, roll:Float Var)
  274.      
  275.             Local QuatToEulerAccuracy:Double = 1.0 / 2 ^ 31
  276.      
  277.             Local sint:Float = (2.0 * w * y) - (2.0 * x * z)
  278.             Local cost_temp:Float = 1.0 - (sint * sint)
  279.             Local cost:Float
  280.      
  281.             If Abs(cost_temp) > QuatToEulerAccuracy
  282.      
  283.                     cost = Sqr(cost_temp)
  284.      
  285.             Else
  286.      
  287.                     cost = 0.0
  288.      
  289.             EndIf
  290.      
  291.             Local sinv:Float, cosv:Float, sinf:Float, cosf:Float
  292.            
  293.             If Abs(cost) > QuatToEulerAccuracy
  294.            
  295.                     sinv = ((2.0 * y * z) + (2.0 * w * x)) / cost
  296.                     cosv = (1.0 - (2.0 * x * x) - (2.0 * y * y)) / cost
  297.                     sinf = ((2.0 * x * y) + (2.0 * w * z)) / cost
  298.                     cosf = (1.0 - (2.0 * y * y) - (2.0 * z * z)) / cost
  299.                    
  300.             Else
  301.                    
  302.                     sinv = (2.0 * w * x) - (2.0 * y * z)
  303.                     cosv = 1.0 - (2.0 * x * x) - (2.0 * z * z)
  304.                     sinf = 0.0
  305.                     cosf = 1.0
  306.                    
  307.             EndIf
  308.            
  309.             pitch = ATan2(sint, cost)
  310.             yaw = ATan2(sinf, cosf)
  311.             roll = -ATan2(sinv, cosv)
  312.            
  313.     End Function
  314.      
  315.     ' ------------------------------------------------------------------------------------------------
  316.     ' Multiply Quaternion
  317.     ' ------------------------------------------------------------------------------------------------
  318.     Function MultiplyQuats:TQuaternion(q1:TQuaternion, q2:TQuaternion)
  319.      
  320.             Local q:TQuaternion = CreateQuaternion()
  321.            
  322.             q.w[0] = q1.w[0] * q2.w[0] - q1.x[0] * q2.x[0] - q1.y[0] * q2.y[0] - q1.z[0] * q2.z[0]
  323.             q.x[0] = q1.w[0] * q2.x[0] + q1.x[0] * q2.w[0] + q1.y[0] * q2.z[0] - q1.z[0] * q2.y[0]
  324.             q.y[0] = q1.w[0] * q2.y[0] + q1.y[0] * q2.w[0] + q1.z[0] * q2.x[0] - q1.x[0] * q2.z[0]
  325.             q.z[0] = q1.w[0] * q2.z[0] + q1.z[0] * q2.w[0] + q1.x[0] * q2.y[0] - q1.y[0] * q2.x[0]
  326.      
  327.             Return q
  328.      
  329.     End Function
  330.      
  331.     ' ------------------------------------------------------------------------------------------------
  332.     ' Normalize Quaternion
  333.     ' ------------------------------------------------------------------------------------------------
  334.     Function NormalizeQuat:TQuaternion(q:TQuaternion)
  335.      
  336.             Local uv:Float = Sqr(q.w[0] * q.w[0] + q.x[0] * q.x[0] + q.y[0] * q.y[0] + q.z[0] * q.z[0])
  337.      
  338.             q.w[0] = q.w[0] / uv
  339.             q.x[0] = q.x[0] / uv
  340.             q.y[0] = q.y[0] / uv
  341.             q.z[0] = q.z[0] / uv
  342.      
  343.             Return q
  344.      
  345.     End Function
  346.      
  347.     ' ------------------------------------------------------------------------------------------------
  348.     ' Events
  349.     ' ------------------------------------------------------------------------------------------------
  350.     Function EventHook:Object(id:Int, Data:Object, Context:Object)
  351.      
  352.             Local Event:TEvent = TEvent(data)
  353.             If Event = Null Then Return Event
  354.      
  355.             Select Event.id
  356.                                                            
  357.                     Case EVENT_MOUSEWHEEL
  358.                                                    
  359.                             If Event.Data > 0 Then
  360.      
  361.                                     MouseWheel:+1
  362.                                     If MouseWheel > 5 Then MouseWheel = 5
  363.      
  364.                                     Else
  365.      
  366.                                             MouseWheel:-1
  367.                                     If MouseWheel < 1 Then MouseWheel = 1
  368.      
  369.                             EndIf
  370.      
  371.             End Select
  372.            
  373.     End Function
  374.