Hehe just finshed the library. The torus command turned out to be a simple edit of the draw_sphere command.
anyway free source and a pic. Procedurally generating solids is very fun for me.
The code is in blitzmax but one could convert to other languages. Everything looks to be solid and bug free. It would be best to use these commands in a list if you plan to draw alot of primatives because I'm sure my code is not optimized. it could have been done in terms of point arrays but extra commands are not a huge deal if you use lists as said.
Strict
GLGraphics 480, 480
glEnable GL_DEPTH_TEST
glEnable GL_LIGHTING
glEnable GL_LIGHT0
glShadeModel(GL_SMOOTH)
glMatrixMode GL_PROJECTION
glLoadIdentity
glClearColor(.25, .25, .25, 1)
glFrustum - 0.1, 0.1, - 0.1, 0.1, 0.1, 10000.0
glMatrixMode GL_MODELVIEW
glLoadIdentity
Global xrot:Float
Global yrot:Float
Type surface_normal
Field x:Float, y:Float, z:Float
EndType ' something to hold data for surface normal
Function create_surface_normal:surface_normal(p1x:Float, p1y:Float, p1z:Float, p2x:Float, p2y:Float, p2z:Float, p3x:Float, p3y:Float, p3z:Float, bool_side = 0)
Local nx:Float = ((p3y - p2y) * (p2z - p1z)) - ((p3z - p2z) * (p2y - p1y))
Local ny:Float = ((p3z - p2z) * (p2x - p1x)) - ((p3x - p2x) * (p2z - p1z))
Local nz:Float = ((p3x - p2x) * (p2y - p1y)) - ((p3y - p2y) * (p2x - p1x))
Local N:Float = Sqr((nx * nx) + (ny * ny) + (nz * nz))
If bool_side = 1
N = n * -1.0
EndIf
Local a:Float = (1.0 / N) * nx
Local b:Float = (1.0 / N) * ny
Local c:Float = (1.0 / N) * nz
Local v:surface_normal = New surface_normal
v.x = a
v.y = b
v.z = c
Return v
endfunction
Function radius_inscribed:Float(nsides:Float, side_length:Float)
Local half_angle#=360.0/(nsides*2.0)
Local half_side#=side_length/2.0
Return half_side/Tan(half_angle)
End Function
Function radius_circumscribed#(nsides#,side_length#)
Local half_angle#=360.0/(nsides*2.0)
Local half_side#=side_length/2.0
Return half_side/Sin(half_angle)
End Function
Function draw_cell(numsides:Float, thickness:Float)
Local sub:Float = 360.0 / numsides
Local radius:Float = radius_circumscribed(numsides, 32.0)
Local radius2:Float = radius - 2.0
Local topz:Float = -thickness / 2.0
Local n:surface_normal = New surface_normal
'top face
glBegin(GL_TRIANGLE_FAN)
n = create_surface_normal(0.0, 0.0, topz, Cos(0 * sub) * radius2, Sin(0 * sub) * radius2, topz, Cos((1) * sub) * radius2, Sin((1) * sub) * radius2, topz, 0)
glNormal3f(n.x, n.y, n.z)
glVertex3f(0.0, 0.0, topz)
For Local i = 0 To numsides
glVertex3f(Cos(I * sub) * radius2, Sin(i * sub) * radius2, topz)
Next
glEnd
'bottom face
n = create_surface_normal(0.0, 0.0, topz, Cos(0 * -sub) * radius2, Sin(0 * -sub) * radius2, - topz, Cos((1) * -sub) * radius2, Sin((1) * -sub) * radius2, - topz, 0)
glBegin(GL_TRIANGLE_FAN)
glNormal3f(n.x, n.y, n.z)
glVertex3f(0.0, 0.0, - topz)
For Local j = 0 To numsides
glVertex3f(Cos(j * -sub) * radius2, Sin(j * -sub) * radius2, - topz)
Next
glEnd
'middle belt
glBegin(GL_QUADS)
glNormal3f(0.0, 0.0, - topz)
For Local k = 0 To numsides - 1
n = create_surface_normal(Cos(k * -sub) * radius, Sin(k * -sub) * radius, - topz / 2.0, Cos((k - 1) * -sub) * radius, Sin((k - 1) * -sub) * radius, - topz / 2.0, Cos((k - 1) * -sub) * radius, Sin((k - 1) * -sub) * radius, topz / 2.0, 0)
glNormal3f(n.x, n.y, n.z)
glVertex3f(Cos(k * -sub) * radius, Sin(k * -sub) * radius, - topz / 2.0)
glVertex3f(Cos((k - 1) * -sub) * radius, Sin((k - 1) * -sub) * radius, - topz / 2.0)
glVertex3f(Cos((k - 1) * -sub) * radius, Sin((k - 1) * -sub) * radius, topz / 2.0)
glVertex3f(Cos(k * -sub) * radius, Sin(k * -sub) * radius, topz / 2.0)
Next
glEnd
glBegin(GL_QUADS)
glNormal3f(0.0, 0.0, - topz)
' bridge belt to top
For Local l = 0 To numsides - 1
n = create_surface_normal(Cos(l * -sub) * radius2, Sin(l * -sub) * radius2, - topz, Cos((l - 1) * -sub) * radius2, Sin((l - 1) * -sub) * radius2, - topz, Cos((l - 1) * -sub) * radius, Sin((l - 1) * -sub) * radius, - topz / 2.0, 0)
glNormal3f(n.x, n.y, n.z)
glVertex3f(Cos(l * -sub) * radius2, Sin(l * -sub) * radius2, - topz)
glVertex3f(Cos((l - 1) * -sub) * radius2, Sin((l - 1) * -sub) * radius2, - topz)
glVertex3f(Cos((l - 1) * -sub) * radius, Sin((l - 1) * -sub) * radius, - topz / 2.0)
glVertex3f(Cos(l * -sub) * radius, Sin(l * -sub) * radius, - topz / 2.0)
Next
glEnd
' bridge belt to bottom
glBegin(GL_QUADS)
For Local m = 0 To numsides - 1
n = create_surface_normal(Cos(m * sub) * radius2, Sin(m * sub) * radius2, topz, Cos((m - 1) * sub) * radius2, Sin((m - 1) * sub) * radius2, topz, Cos((m - 1) * sub) * radius, Sin((m - 1) * sub) * radius, topz / 2.0, 0)
glNormal3f(n.x, n.y, n.z)
glVertex3f(Cos(m * sub) * radius2, Sin(m * sub) * radius2, topz)
glVertex3f(Cos((m - 1) * sub) * radius2, Sin((m - 1) * sub) * radius2, topz)
glVertex3f(Cos((m - 1) * sub) * radius, Sin((m - 1) * sub) * radius, topz / 2.0)
glVertex3f(Cos(m * sub) * radius, Sin(m * sub) * radius, topz / 2.0)
Next
glEnd
End Function
Function draw_tube(Hdivisions:Float, vdivisions:Float, Height:Float, radius:Float, capped:Byte)
'use a double for loop
Local belt_height:Float = Height / vdivisions
Local half_height:Float = Height / 2.0
Local sub:Float = 360 / hdivisions
Local n:surface_normal = New surface_normal
glBegin(GL_QUADS)
For Local x:Float = 0 To hdivisions - 1
For Local y:Float = 0 To vdivisions - 1
n = create_surface_normal(Cos(sub * x) * radius, - half_height + (Y * belt_height), Sin(sub * x) * radius, Cos(sub * (x + 1)) * radius, - half_height + (Y * belt_height), Sin(sub * (x + 1)) * radius, Cos(sub * (x + 1)) * radius, - half_height + ((Y + 1) * belt_height), Sin(sub * (x + 1)) * radius, 0)
glNormal3f(n.x, n.y, n.z)
glVertex3f(Cos(sub * x) * radius, - half_height + (Y * belt_height), Sin(sub * x) * radius)
glVertex3f(Cos(sub * (x + 1)) * radius, - half_height + (Y * belt_height), Sin(sub * (x + 1)) * radius)
glVertex3f(Cos(sub * (x + 1)) * radius, - half_height + ((Y + 1) * belt_height), Sin(sub * (x + 1)) * radius)
glVertex3f(Cos(sub * x) * radius, - half_height + ((Y + 1) * belt_height), Sin(sub * x) * radius)
Next
Next
' draw the top and bottom
If capped = 1
glBegin(GL_TRIANGLES)
glNormal3f(0, - 1.0, 0)
For Local x:Float = 0 To hdivisions - 1
glVertex3f(0, - half_height, 0)
glVertex3f(Cos(sub * x) * radius, - half_height, Sin(sub * x) * radius)
glVertex3f(Cos(sub * (x - 1)) * radius, - half_height, Sin(sub * (x - 1)) * radius)
Next
glEnd
glBegin(GL_TRIANGLES)
glNormal3f(0, 1.0, 0)
For Local x:Float = 0 To hdivisions - 1
glVertex3f(0, half_height, 0)
glVertex3f(Cos(sub * x) * radius, half_height, Sin(sub * x) * radius)
glVertex3f(Cos(sub * (x - 1)) * radius, half_height, Sin(sub * (x - 1)) * radius)
Next
glEnd
End If
glEnd
End Function
Function draw_cone(Hdivisions:Float, Height:Float, radius:Float, capped:Byte)
Local half_height:Float = Height / 2.0
Local sub:Float = 360 / hdivisions
Local n:surface_normal = New surface_normal
glBegin(GL_TRIANGLES)
For Local x:Float = 0 To hdivisions - 1
n = create_surface_normal(0, - half_height, 0, Cos(sub * (x + 1)) * radius, half_height, Sin(sub * (x + 1)) * radius, Cos(sub * x) * radius, half_height, Sin(sub * x) * radius)
glNormal3f(n.x, n.y, n.z)
glVertex3f(0, - half_height, 0)
glVertex3f(Cos(sub * (x + 1)) * radius, half_height, Sin(sub * (x + 1)) * radius)
glVertex3f(Cos(sub * x) * radius, half_height, Sin(sub * x) * radius)
Next
' draw the top and bottom
If capped = 1
glBegin(GL_TRIANGLES)
glNormal3f(0, 1.0, 0)
For Local x:Float = 0 To hdivisions - 1
glVertex3f(0, half_height, 0)
glVertex3f(Cos(sub * x) * radius, half_height, Sin(sub * x) * radius)
glVertex3f(Cos(sub * (x - 1)) * radius, half_height, Sin(sub * (x - 1)) * radius)
Next
glEnd
End If
glEnd
End Function
Function draw_sphere(Hdivisions:Float, vdivisions:Float, radius:Float)
'use a double for loop
Local Height:Float = radius * 2.0
Local half_height:Float = Height / 2.0
Local sub:Float = 360 / hdivisions
Local n:surface_normal
Local XZ_sub:Float = 180 / vdivisions
glBegin(GL_QUADS)
For Local x:Float = 0 To hdivisions - 1
For Local y:Float = 0 To vdivisions - 1
'find the first y value radius
Local r:Float = Sin(y * xz_sub) * radius
' find second y value radius
Local r2:Float = Sin((y + 1) * xz_sub) * radius
n = create_surface_normal(Cos(sub * x) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * x) * r2, Cos(sub * (x + 1)) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r2, Cos(sub * (x + 1)) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r)
glNormal3f(n.x, n.y, n.z)
glVertex3f(Cos(sub * x) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * x) * r2)
glVertex3f(Cos(sub * (x + 1)) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r2)
glVertex3f(Cos(sub * (x + 1)) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r)
glVertex3f(Cos(sub * x) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * x) * r)
Next
Next
glEnd
End Function
Function draw_hemisphere(Hdivisions:Float, vdivisions:Float, radius:Float, capped:Byte)
'use a double for loop
vdivisions:*2.0
Local Height:Float = radius * 2.0
Local half_height:Float = Height / 2.0
Local sub:Float = 360 / hdivisions
Local n:surface_normal
Local XZ_sub:Float = 180 / vdivisions
glBegin(GL_QUADS)
For Local x:Float = 0 To hdivisions - 1
For Local y:Float = 0 To (vdivisions / 2.0) - 1
'find the first y value radius
Local r:Float = Sin(y * xz_sub) * radius
' find second y value radius
Local r2:Float = Sin((y + 1) * xz_sub) * radius
n = create_surface_normal(Cos(sub * x) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * x) * r2, Cos(sub * (x + 1)) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r2, Cos(sub * (x + 1)) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r)
glNormal3f(n.x, n.y, n.z)
glVertex3f(Cos(sub * x) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * x) * r2)
glVertex3f(Cos(sub * (x + 1)) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r2)
glVertex3f(Cos(sub * (x + 1)) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r)
glVertex3f(Cos(sub * x) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * x) * r)
Next
Next
glEnd
If capped = 1
glBegin(GL_TRIANGLES)
glNormal3f(0, - 1.0, 0)
For Local x:Float = 0 To hdivisions - 1
glVertex3f(0, 0, 0)
glVertex3f(Cos(sub * x) * radius, 0, Sin(sub * x) * radius)
glVertex3f(Cos(sub * (x - 1)) * radius, 0, Sin(sub * (x - 1)) * radius)
Next
glEnd
EndIf
EndFunction
Function draw_torus(Hdivisions:Float, vdivisions:Float, radius:Float, radius2:Float)
vdivisions:/2.0
Local Height:Float = radius * 2.0
Local half_height:Float = Height / 2.0
Local sub:Float = 360 / hdivisions
Local n:surface_normal
Local XZ_sub:Float = 180 / vdivisions
glBegin(GL_QUADS)
For Local x:Float = 0 To hdivisions - 1
For Local y:Float = 0 To (vdivisions * 2.0) - 1
'find the first y value radius
Local r:Float = radius2 + Sin(y * xz_sub) * radius
' find second y value radius
Local r2:Float = radius2 + Sin((y + 1) * xz_sub) * radius
n = create_surface_normal(Cos(sub * x) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * x) * r2, Cos(sub * (x + 1)) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r2, Cos(sub * (x + 1)) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r)
glNormal3f(n.x, n.y, n.z)
glVertex3f(Cos(sub * x) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * x) * r2)
glVertex3f(Cos(sub * (x + 1)) * r2, Cos((y + 1) * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r2)
glVertex3f(Cos(sub * (x + 1)) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * (x + 1)) * r)
glVertex3f(Cos(sub * x) * r, Cos(y * (180 / vdivisions)) * radius, Sin(sub * x) * r)
Next
Next
glEnd
End Function
' test the library here
While Not KeyHit( KEY_ESCAPE )
glClear GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT 'Clear The Screen And The Depth Buffer
glLoadIdentity()
glTranslatef 40, - 40, - 100.0
glRotatef xrot, 0.0, 1.0, 0.0
glRotatef yrot, 1.0, 0.0, 0.0
draw_torus(12, 12, 8, 16)
glLoadIdentity()
glTranslatef 40, 40, - 100.0
glRotatef xrot, 0.0, 1.0, 0.0
glRotatef yrot, 1.0, 0.0, 0.0
draw_hemisphere(12, 12, 32, 1)
glLoadIdentity()
glTranslatef - 40, - 40, - 100.0
glRotatef xrot, 0.0, 1.0, 0.0
glRotatef yrot, 1.0, 0.0, 0.0
draw_tube(12, 1, 32, 32, 1)
glLoadIdentity()
glTranslatef - 40, 40, - 100.0
glRotatef xrot, 0.0, 1.0, 0.0
glRotatef yrot, 1.0, 0.0, 0.0
draw_cone(12, 32, 32, 1)
glLoadIdentity()
glTranslatef 0, 0, - 100.0
glRotatef xrot, 0.0, 1.0, 0.0
glRotatef yrot, 1.0, 0.0, 0.0
draw_sphere(12, 12, 16)
xrot:+(KeyDown(KEY_LEFT) - KeyDown(KEY_RIGHT)) * 2
yrot:+(KeyDown(KEY_UP) - KeyDown(KEY_DOWN)) * 2
Flip
Wend