in a previous post i have posted a knot example but with points and then with big points, because i don't know then how to make custom or free oriented tubes. until i have found a freebasic code which have inside it an algorithm to align rings *circles" perpendicular to a curve at a corresponding points, look my new post in 3D section for details: 
http://www.purebasic.fr/english/viewtop ... 36&t=56642
now here is the knot made from tube, it is displayed great, but with a very small annoyance, it takes it too much time compared to the corresponding example i have posted for PB Ogre.
this MP3D code have 
#NUM_RINGS = 180 ; number of rings over all the tube
#NUM_BANDS = 16  ; number of points of every ring (circle)
and it is displayed after 4 seconds on my old pc with Geforce 210,
but in my example for PB ogre it is:
#NUM_RINGS = 360 ; number of rings over all the tube
#NUM_BANDS = 32  ; number of points of every ring (circle)
and it is displayed immediately, using 360 and 32 in MP3D will displayed after 25 seconds. so could it be something in my code ??. 
notes:
1- press S to save the tube to "knot.x" file
2-a fun part when you press "D"  key to delete parts of the tube
Code: Select all
#TWOPI = 2 * #PI    ;PI For rotation 
#NUM_RINGS = 180 ; number of rings over all the tube
#NUM_BANDS = 16 ; number of points of every ring (circle)
#BAND_RAD  = 0.5 ;tube thickness
#BUTTON = 6
;Global.f rot = 1
Global stop = 0
Structure vector3d
  x.f
  y.f
  z.f
EndStructure
	 
Declare DrawTube (Rings.l, Bands.l,BandRadius.f)
Quit.b = #False
ExamineDesktops()
MP_Graphics3D (DesktopWidth(0),DesktopHeight(0),0,2) ; Erstelle ein WindowsFenster #Window = 0
SetWindowTitle(0, "Tubes .. press space to toggle rotation, press S  to save to knot.x file") 
ButtonGadget(#BUTTON, 0, DesktopHeight(0)-60, 60, 30, "rotate/stop") 
MP_Viewport(0,0,DesktopWidth(0),DesktopHeight(0)-60)
camera=MP_CreateCamera()
light=MP_CreateLight(2)
MP_LightSetColor (light, RGB(255,255,255))
MP_PositionCamera(camera, 0, 5, 10)
MP_CameraLookAt(camera,0,0,0)
MP_PositionEntity(light, 0, 10, 20)
MP_EntityLookAt(light,0,0,0)
Global Mesh = MP_CreateMesh()
SetActiveGadget(#BUTTON)
  
Quit.b = #False 
;==============================================================
tex$ = #PB_Compiler_Home + "Examples/3D/Data/Textures/" + "terrain_texture.jpg"
Texture = MP_LoadTexture(tex$)
MP_EntitySetTexture (Mesh, Texture )
MP_MaterialEmissiveColor (Texture,0,255,255,255)
MP_PositionCamera(camera, 0, 0, 10)
MP_CameraLookAt(camera,0,0,0)
MP_PositionEntity(light, 0 , 0, 10)
MP_EntityLookAt(light,0,0,0)
DrawTube (#NUM_RINGS, #NUM_BANDS, #BAND_RAD )
MP_PositionEntity (Mesh,0,0,-3)
;MP_ScaleEntity(Mesh, 0.5, 0.5, 0.5)
rot.l=1 :stopFlag = 1 : wireFrame.b = 0
xs.f = 1:ys.f = 1:zs.f = 1
x.f: y.f :z.f: x0.f: y0.f=1 :z0.f
rotx.f:roty.f=0.5:rotz.f :rotx0.f: roty0.f: rotz0.f
h.f=0:up.f=0.1:depth.f=3
x.f=90: y.f=0: z.f=0 :indx = 126
Repeat
  Event = WindowEvent()
  If Event = #PB_Event_Gadget
    Select EventGadget()
      Case #BUTTON
        If rot = 0
          rot = 1
          rotx= rotx0:roty=roty0:rotz=rotz0 ; restore rotation status
          stopFlag = 1
          
        Else
          rot = 0
          rotx0= rotx:roty0=roty:rotz0=rotz ;back up rotation status
          rotx=0:roty=0:rotz=0
          stopFlag = 0
          
        EndIf
                    
    EndSelect
  EndIf 
  If stopFlag=1
    x + rotx
    y + roty
    z + rotz
  EndIf
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
  If MP_KeyDown(#PB_Key_Up)  ; rotate left
    rotx=1:roty=0:rotz=0
    rotx0 = rotx: roty0 = roty :rotz0 = rotz
    x + rotx
    y + roty
    z + rotz
    stopFlag=0
    rot = 0
  ElseIf MP_KeyDown(#PB_Key_Down) ; rotate right
    rotx=-1:roty=0:rotz=0
    rotx0 = rotx: roty0 = roty :rotz0 = rotz
    x + rotx
    y + roty
    z + rotz
    stopFlag=0
    rot = 0
  ElseIf MP_KeyDown(#PB_Key_Right)   ; rotate up
    rotx=0:roty=1:rotz=0
    rotx0 = rotx: roty0 = roty :rotz0 = rotz
    x + rotx
    y + roty
    z + rotz
    stopFlag=0
    rot = 0
  ElseIf MP_KeyDown(#PB_Key_Left) ; rotate down
    rotx=0:roty=-1:rotz=0 
    rotx0 = rotx: roty0 = roty :rotz0 = rotz
    x + rotx
    y + roty
    z + rotz
    stopFlag=0
    rot = 0
  EndIf 
  
  If MP_KeyDown(#PB_Key_PageUp) ; scale up model
    xs.f + 0.01:ys.f + 0.01:zs.f + 0.01
    MP_ScaleEntity(Mesh,xs,ys,zs)
    
  ElseIf MP_KeyDown(#PB_Key_PageDown) ; scale down model
    xs -0.01:ys -0.01:zs- 0.01
    If xs<0 :xs=0:ys=0:zs=0:EndIf
    MP_ScaleEntity(Mesh,xs,ys,zs)
    
  EndIf
  If MP_KeyDown(#PB_Key_Pad8) ; up move
    up + 0.01
    MP_PositionEntity(Mesh,h,up,depth)
   ElseIf MP_KeyDown(#PB_Key_Pad2) ; down move
    up - 0.01
    MP_PositionEntity(Mesh,h,up,depth)
  ElseIf MP_KeyDown(#PB_Key_Pad6)
    h + 0.01
    MP_PositionEntity(Mesh,h,up,depth)
    ElseIf MP_KeyDown(#PB_Key_Pad4)
    h - 0.01
    MP_PositionEntity(Mesh,h,up,depth)
    
    ElseIf MP_KeyDown(#PB_Key_Q) ; forward move
    depth - 0.01
    MP_PositionEntity(Mesh,h,up,depth)
    ElseIf MP_KeyDown(#PB_Key_A) ; inward move
    depth + 0.01
    MP_PositionEntity(Mesh,h,up,depth)
    ElseIf MP_KeyHit(#PB_Key_W) ; display wire frame for the material
      If wireFrame=0
      MP_Wireframe (1) 
      wireFrame ! 1
         ElseIf wireFrame=1
           MP_Wireframe (0)
           wireFrame ! 1 
      EndIf
    ElseIf MP_KeyDown(#PB_Key_D) 
      MP_FreeTriangle(Mesh, 1)
      ;indx -1: MP_FreeVertex(Mesh ,indx)
    ElseIf MP_KeyDown(#PB_Key_S)  
      MP_SaveMesh("knot.x",Mesh)
        
  EndIf
   If MP_KeyDown(#PB_Key_Escape)
      Quit = #True
    EndIf
  MP_DrawText (1,1,"press W _wireFrame, D _ delete triangles")  
  MP_DrawText (1,15,"keyPad keys: up.down.left.right")
  MP_RotateEntity(Mesh, 90+x, y, z)
  MP_RenderWorld() ; Erstelle die Welt
  MP_Flip ()  
    
Until Quit = #True Or Event = #PB_Event_CloseWindow
;beginning of frenet approx procedures
Procedure vector_cross(*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = (*v1\y * *v2\z) - (*v2\y * *v1\z)
    *vout\y = (*v1\z * *v2\x) - (*v2\z * *v1\x)
    *vout\z = (*v1\x * *v2\y) - (*v2\x * *v1\y)
EndProcedure
Procedure.f vector_magnitude(*v.vector3d)
    mag.f
    mag = Sqr(*v\x * *v\x + *v\y * *v\y + *v\z * *v\z)
    If mag = 0:mag = 1:EndIf
    ProcedureReturn mag
EndProcedure
Procedure vector_normalize (*v.vector3d)
    mag.f
    mag = vector_magnitude(*v)
    *v\x = *v\x / mag
    *v\y = *v\y / mag
    *v\z = *v\z / mag
EndProcedure
Procedure vector_add (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x + *v2\x
    *vout\y = *v1\y + *v2\y
    *vout\z = *v1\z + *v2\z
EndProcedure
Procedure vector_sub (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x - *v2\x
    *vout\y = *v1\y - *v2\y
    *vout\z = *v1\z - *v2\z
EndProcedure
; main program
Procedure  DrawTube (Rings.l, Bands.l, BandRadius.f)
  x.f: y.f: z.f
	op.f = 1
	    
	txu.f : txv.f
	current_point.vector3d  ; current point on tube curve
  next_point.vector3d     ; next point on tube curve
  T.vector3d
  B.vector3d
  N.vector3d
  p.f
        
	For i = 0 To rings + 1
	    	
        ;center point
        p = op * i * #TWOPI / rings
        current_point\x = Cos(p) + 2.5*Cos(-2*p) 
        current_point\y = Sin(p) + 3.5*Sin(-2*p)
        current_point\z = 2 * Sin(3*p)
        
        ;next point For Frenet square
        p = op * (i + 1) * #TWOPI / rings
        next_point\x = Cos(p) + 2.5*Cos(-2*p)
        next_point\y = Sin(p) + 3.5*Sin(-2*p)
        next_point\z = 2 * Sin(3*p)
        ;T  = P' - P
        vector_sub(next_point, current_point, T)
        ;N = P' + P
        vector_add(next_point, current_point, N)
        ;B = T x N
        vector_cross(T, N, B)
        ;N = B x T
        vector_cross(B, T, N)
        ;Normalize vectors Or Else it won't work
        vector_normalize(B)
        vector_normalize(N)
        
        For j = 0 To bands - 1
           	new_point_x.f
        		new_point_y.f
        		
        		;rotate around the current point using normal rotation makes bands
            new_point_x = Sin(j * #TWOPI / bands) * #BAND_RAD
            new_point_y = Cos(j * #TWOPI / bands) * #BAND_RAD
            
				    ;this is the coords of our point along the curve
            x = N\x * new_point_x + B\x * new_point_y + current_point\x
            y = N\y * new_point_x + B\y * new_point_y + current_point\y
            z = N\z * new_point_x + B\z * new_point_y + current_point\z
            
            MP_AddVertex (Mesh, x, y,z,0,txu,txv)
            txv = txv + 1/bands
                         
			Next 
			txv = 0
			;txu = txu + 1/rings 
			txu = txu + 1/bands 
		Next 
		
		v.l
		 For i = 0 To rings - 1
      For j = 0 To bands - 1
          
          MP_AddTriangle (Mesh,v,v+1,v + bands+1)
          MP_AddTriangle (Mesh,v + bands+1,v + bands+2,v+1 )
          
          v + 1   
          
        Next
        ;MP_EntitySetNormals(Mesh)
     
   Next  
  EndProcedure