I did, however, take a moment to knock up a small standalone example that demonstrates the principal:

Code: Select all
;/ opengl swept surface - Phil James 11/2024
; 'Lathe' function converted from: https://stackoverflow.com/questions/7904281/opengl-rotate-a-curve-about-the-y-axis
; LMB to adjust profile (holding LMB Or clicking LMB results in two different modes)
; RMB to rotate model
EnableExplicit
#Width = 1024 : #Height = 768
#Slices = 48 ; how many rotations for a full revolution, the larger the finer the model, slower to calculate & render (96 looks smooth)
#Points = 1024 : #ScaleY = 0.03 ; you can increase the horizontal resolution here (adjust scale to better fit screen)
Enumeration ; window
#myWin_Main
EndEnumeration
Enumeration ; gadgets
#myGad_GL
#myGad_Button_Smooth
#myGad_Checkbox_AutoSmooth
EndEnumeration
Enumeration ; timer
#myTimer_Render
EndEnumeration
Structure sVec2f : x.f : y.f : EndStructure
Structure sVec3f : x.f : y.f : z.f : EndStructure
Structure sVertex : position.sVec3f : Normal.sVec3f : EndStructure
Structure sSystem
Event.i : Exit.i
LMB.i : RMB.I
Rotation.svec3f
Render.i : UpdateProfile.i
Mouse.point : MouseOld.point
EndStructure
Global Dim model.sVertex(32)
Global Dim Points.sVec2f(#Points)
Global Dim Profile.f(#Points)
Global System.sSystem
;/ normal calculation for correct lighting
Macro Vec3f_Subtract(n, v, w)
n\x = v\x - w\x
n\y = v\y - w\y
n\z = v\z - w\z
EndMacro
Procedure Normalize(*V.sVec3f)
Define.d magSq, oneOverMag
magSq = *V\x * *V\x + *V\y * *V\y + *V\z * *V\z
If magsq > 0
oneOverMag = 1.0 / Sqr(magSq)
*V\x * oneOverMag
*V\y * oneOverMag
*V\z * oneOverMag
EndIf
EndProcedure
Procedure NormalFace(*n.sVec3f, *v1.sVec3f, *v2.sVec3f, *v3.sVec3f)
Protected.sVec3f v2v1, v3v1
Vec3f_Subtract(v2v1, *v2, *v1)
Vec3f_Subtract(v3v1, *v3, *v1)
*n\x = v2v1\y * v3v1\z - v2v1\z * v3v1\y
*n\y = v2v1\z * v3v1\x - v2v1\x * v3v1\z
*n\z = v2v1\x * v3v1\y - v2v1\y * v3v1\x
Normalize(*n)
EndProcedure
Procedure Lathe(Array points.sVec2f(1), segments = 32)
Protected onPoint = 0, time = ElapsedMilliseconds(), i, j, angle.f, ptSize, normal.svec3f
; precalculate circle points
Dim circlePts.sVec2f(segments)
For i = 0 To segments
angle = (i / segments) * #PI * 2.0
circlePts(i)\x = Cos(angle) : circlePts(i)\y = Sin(angle)
Next
; fill each layer
ptSize = ArraySize(points(), 1)
Dim layers.sVec3f(ptSize, segments)
For i = 0 To ptSize
For j = 0 To segments
layers(i, j)\x = circlePts(j)\x * points(i)\x
layers(i, j)\y = circlePts(j)\y * points(i)\x
layers(i, j)\z = points(i)\y
Next
Next
; move through layers generating triangles
Dim Model.sVertex(ptSize * segments * 6)
For i = 1 To ptSize
For j = 1 To segments
NormalFace(normal, @layers(i-1, j-1), @layers(i, j), @layers(i, j-1))
Model(onPoint + 0)\position = layers(i-1, j-1)
Model(onPoint + 1)\position = layers(i, j)
Model(onPoint + 2)\position = layers(i, j-1)
Model(onPoint + 0)\Normal = normal : Model(onPoint + 1)\Normal = normal : Model(onPoint + 2)\Normal = normal
NormalFace(normal, @layers(i-1, j-1), @layers(i-1, j), @layers(i, j))
Model(onPoint + 3)\position = layers(i - 1, j - 1)
Model(onPoint + 4)\position = layers(i-1, j)
Model(onPoint + 5)\position = layers(i, j)
Model(onPoint + 3)\Normal = normal : Model(onPoint + 4)\Normal = normal : Model(onPoint + 5)\Normal = normal
onPoint + 6
Next
Next
SetWindowTitle(#myWin_Main, "Model calculation time: "+Str(ElapsedMilliseconds() - time)+"ms")
EndProcedure
Procedure Profile_SetHeight(pos, Val)
Static lastVal, lastPos
If val > 300 : ProcedureReturn : EndIf ; prevent setting too far outside of draw area
Protected x, valChg.f, lp.f
If val < 0 : val = 0 : ElseIf val > 256 : val = 256 : EndIf
If lastPos < Pos
For x = lastPos To pos
If x => 0 And x < #Points-1 : profile(x) = val : EndIf
Next
Else
For x = Pos To lastPos
If x => 0 And x < #Points-1 : profile(x) = val : EndIf
Next
EndIf
System\UpdateProfile = #True
lastVal = Val : lastPos = pos
EndProcedure
Procedure Profile_Smooth(Iterations = 64) ; basic smoothing
Protected x, spread = 9, iter
Dim tmpProfile.f(#points)
For iter = 1 To Iterations
CopyArray(Profile(),tmpProfile())
For x = 3 To #Points-3 ; constrained to avoid smoothing end caps
Profile(x) = (tmpProfile(x) * 0.4) + (tmpProfile(x-1) * 0.3) + (tmpProfile(x+1) * 0.3)
Next
Next
System\UpdateProfile = #True
EndProcedure
Procedure Profile_Init() ; mathemetical start point
Protected myLoop
For myLoop = 0 To #Points
Profile(myLoop) = 128.0 + 100.0 * Sin(myLoop / 128.0)
Next
Profile(#Points-1) = 0
System\UpdateProfile = #True
EndProcedure
Procedure Profile_Update() ; load the Points() array with the Profile() array
Protected myLoop
For myLoop = 0 To #Points - 1
Points(myLoop)\y = (myLoop - (#Points * 0.5)) * #ScaleY ; position along spindle
Points(myLoop)\x = profile(myLoop) * 0.0325 ; radius
Next
Lathe(Points(), #Slices)
EndProcedure
Procedure Render() ; use opengl to render the model and the 2d profile
Protected profileHeight.f = 256, myLoop
glClearColor_(0.6, 0.6, 0.6, 1.0)
glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
glEnable_(#GL_DEPTH_TEST) : glEnable_(#GL_COLOR_MATERIAL)
glEnable_(#GL_LIGHTING) : glEnable_(#GL_LIGHT0)
glMatrixMode_(#GL_PROJECTION) : glLoadIdentity_()
gluPerspective_(50, WindowWidth(0)/WindowHeight(0), 0.01, 70);
glMatrixMode_(#GL_MODELVIEW) : glLoadIdentity_()
gluLookAt_(0, 10, 35, 0, 0, -20, 0, 1, 0)
glRotatef_(System\Rotation\x, 0, 1, 0)
glRotatef_(-System\Rotation\y, 1, 0, 0)
; draw model
glColor3ub_(205, 127, 50)
glEnableClientState_(#GL_VERTEX_ARRAY)
glEnableClientState_(#GL_NORMAL_ARRAY)
glVertexPointer_(3, #GL_FLOAT, SizeOf(sVertex), @model(0)\position)
glNormalPointer_(#GL_FLOAT, SizeOf(sVertex), @model(0)\normal)
glDrawArrays_(#GL_TRIANGLES, 0, ArraySize(model(), 1))
glDisableClientState_(#GL_VERTEX_ARRAY)
glDisableClientState_(#GL_NORMAL_ARRAY)
; draw the profile are
glMatrixMode_(#GL_PROJECTION) : glLoadIdentity_()
Protected Width = #Width * DesktopResolutionX()
Protected Height = #Height * DesktopResolutionY()
glOrtho_(0, Width, Height, 0, -1, 1)
glMatrixMode_(#GL_MODELVIEW) : glLoadIdentity_()
glDisable_(#GL_LIGHTING) : glDisable_(#GL_DEPTH_TEST) : glDisable_(#GL_COLOR_MATERIAL)
glEnable_(#GL_BLEND) : glBlendFunc_(#GL_SRC_ALPHA, #GL_ONE_MINUS_SRC_ALPHA)
glBegin_(#GL_QUADS)
glColor4f_(0.7, 0.72, 0.72, 0.3)
glVertex2f_(0, profileHeight) : glVertex2f_(#points, profileHeight) : glVertex2f_(#points, 0) : glVertex2f_(0, 0)
glEnd_()
glBegin_(#GL_LINES)
glColor4f_(0.3, 0.53, 0.7, 0.5)
For myLoop = 0 To #points - 1
glVertex2f_(myLoop, 0) : glVertex2f_(myLoop, profile(myLoop))
Next
glColor4f_(0.1, 0.1, 0.1, 1.0)
glVertex2f_(0, profileHeight) : glVertex2f_(#points, profileHeight)
glVertex2f_(#points, profileHeight) : glVertex2f_(#points, 0)
glEnd_()
SetGadgetAttribute(#myGad_GL, #PB_OpenGL_FlipBuffers, #True)
EndProcedure
Procedure Init_Main()
OpenWindow(#myWin_Main, 0, 0, #Width, #Height + 32, "OpenGL Lathe", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
AddWindowTimer(#myWin_Main, #myTimer_Render, 15)
OpenGLGadget(#myGad_GL, 0, 0, #Width, #Height,#PB_OpenGL_Keyboard|#PB_OpenGL_NoFlipSynchronization|#PB_OpenGL_24BitDepthBuffer)
ButtonGadget(#myGad_Button_Smooth,0,#Height+2,100,24,"Smooth")
CheckBoxGadget(#myGad_Checkbox_AutoSmooth,104,#Height+2,100,24,"Auto Smooth")
SetGadgetState(#myGad_Checkbox_AutoSmooth,1)
Profile_Init()
System\Rotation\x = 60
EndProcedure
Init_Main()
Repeat
Repeat
System\Event = WindowEvent()
Select System\Event
Case #PB_Event_Gadget
Select EventGadget()
Case #myGad_Button_Smooth : Profile_Smooth()
Case #myGad_GL
System\MouseOld = System\mouse
System\mouse\x = GetGadgetAttribute(#myGad_GL, #PB_OpenGL_MouseX) : System\mouse\y = GetGadgetAttribute(#myGad_GL, #PB_OpenGL_MouseY)
Select EventType()
Case #PB_EventType_LeftButtonDown
System\LMB = #True
Profile_SetHeight(System\mouse\x,System\mouse\y)
Case #PB_EventType_LeftButtonUp : System\LMB = #False
Case #PB_EventType_MouseMove
If System\LMB = #True
Profile_SetHeight(System\mouse\x,System\mouse\y)
If GetGadgetState(#myGad_Checkbox_AutoSmooth) : Profile_Smooth(2) : EndIf
ElseIf System\RMB = #True
System\Rotation\x + ((System\mouse\x - System\MouseOld\x) * 0.2)
System\Rotation\y - ((System\mouse\y - System\MouseOld\y) * 0.2)
EndIf
Case #PB_EventType_RightButtonDown : System\RMB = #True
Case #PB_EventType_RightButtonUp : System\RMB = #False
EndSelect
EndSelect
Case #PB_Event_CloseWindow : System\Exit = #True
Case #PB_Event_Timer : System\Render = #True
EndSelect
Until System\Event = 0
If System\Render = #True : System\Render = #False : Render() : EndIf
If System\UpdateProfile = #True : System\UpdateProfile = #False : Profile_Update() : EndIf
Until System\Exit = #True