You have to tesselate it.
You need to sweep a circle around a helix.
- Generate the points for a circle.
- Translate this out along an axis.
- Rotate about the origin some parameterized amount.
- Translate upwards by some small parameterized amount.
- Increase parameterized amount and goto 1
This will points which you then either render or mexh.
You can render as you go but it ain’t essential.
Here’s some code I wrote to draw a torus, copy it and add a translation (stage 4 above). It also has tangent & binormals & other stuff which you probably don’t need.
I just ripped it out of an old project I had with some editing but it should be very close to useable in your program.
#define MINOR_DIV 32
#define MAJOR_DIV 48
#define RadiusMajor 23.0f
#define RadiusMinor 6.0f
#define RepeatsMajor 10.0f
#define RepeatsMinor 4.0f
void DrawTorus(float lod_bias, int numpasses, int pass)
{
float minor_x, minor_z;
double major_inc, minor_inc;
double r_minor, r_major;
double sin_major1, cos_major1, sin_major2, cos_major2;
float deltas, deltat;
static float vert[6*(MAJOR_DIV)*(MINOR_DIV+1)];
static float norm[6*(MAJOR_DIV+2)*(MINOR_DIV+1)];
int vert_pos = 0;
static float tex[4*(MAJOR_DIV)*(MINOR_DIV+1)];
int tex_pos = 0;
static float tangent[8*(MAJOR_DIV)*(MINOR_DIV+1)];
static float binorm[8*(MAJOR_DIV)*(MINOR_DIV+1)];
int tangent_pos = 0;
int maj_pos, min_pos;
static int first = 1;
float tex_shift[4*(MAJOR_DIV)*(MINOR_DIV+1)];
float brightness = 1.0f/numpasses;
float VdotN, VprojB, VprojT;
float tmp_vec[3];
float pass_mult;
float Ts, Bs;
major_inc = M_PI*2/MAJOR_DIV;
minor_inc = M_PI*2/MINOR_DIV;
if(first)
{
first = 0;
for (r_major = 0.0f; r_major <= M_PI*2.0-.000001; r_major += major_inc)
{
sin_major1 = sin(r_major);
cos_major1 = cos(r_major);
sin_major2 = sin(r_major+major_inc);
cos_major2 = cos(r_major+major_inc);
for(r_minor = 0.0f; r_minor < M_PI*2.0+.000001; r_minor += minor_inc)
{
minor_x = RadiusMinor*(float)sin(r_minor);
minor_z = RadiusMinor*(float)cos(r_minor);
tex[tex_pos++] = (RepeatsMajor/2.0f) * (float)(r_major/M_PI);
tex[tex_pos++] = 0.5f + (RepeatsMinor/2.0f) * (float)(r_minor/M_PI);
tangent[tangent_pos++] = 0.0f;
tangent[tangent_pos++] = (float)-cos_major1;
tangent[tangent_pos++] = (float)sin_major1;
// texture repeats per unit = repeats / Pi*diameter
binorm[tangent_pos] = RepeatsMinor / ((float)M_PI * (RadiusMinor + RadiusMinor));
tangent[tangent_pos++] = RepeatsMajor / ((float)-M_PI * ((minor_z-RadiusMajor) + (minor_z-RadiusMajor)));
Normalize(tangent+tangent_pos-4);
norm[vert_pos] = minor_x;
vert[vert_pos++] = minor_x;
norm[vert_pos] = (float)sin_major1*minor_z;
vert[vert_pos++] = (float)sin_major1*(minor_z-RadiusMajor);
norm[vert_pos] = (float)cos_major1*minor_z;
vert[vert_pos++] = (float)cos_major1*(minor_z-RadiusMajor);
Normalize(norm+vert_pos-3);
Cross(binorm+tangent_pos-4, norm+vert_pos-3, tangent+tangent_pos-4);
tex[tex_pos++] = (RepeatsMajor/2.0f) * (float)((r_major+major_inc)/M_PI);
tex[tex_pos++] = 0.5f + (RepeatsMinor/2.0f) * (float)(r_minor/M_PI);
tangent[tangent_pos++] = 0.0f;
tangent[tangent_pos++] = (float)-cos_major2;
tangent[tangent_pos++] = (float)sin_major2;
// texture repeats per unit = repeats / Pi*diameter
binorm[tangent_pos] = RepeatsMinor / ((float)M_PI * (RadiusMinor + RadiusMinor));
tangent[tangent_pos++] = RepeatsMajor / ((float)-M_PI * ((minor_z-RadiusMajor) + (minor_z-RadiusMajor)));
Normalize(tangent+tangent_pos-4);
norm[vert_pos] = minor_x;
vert[vert_pos++] = minor_x;
norm[vert_pos] = (float)sin_major2*minor_z;
vert[vert_pos++] = (float)sin_major2*(minor_z-RadiusMajor);
norm[vert_pos] = (float)cos_major2*minor_z;
vert[vert_pos++] = (float)cos_major2*(minor_z-RadiusMajor);
Normalize(norm+vert_pos-3);
Cross(binorm+tangent_pos-4, norm+vert_pos-3, tangent+tangent_pos-4);
}
}
}
glEnable(GL_TEXTURE_2D);
if(wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
vert_pos = 0;
for(maj_pos = 0; maj_pos < MAJOR_DIV; maj_pos++)
{
glBegin(GL_TRIANGLE_STRIP);
for(min_pos = 0; min_pos <= MINOR_DIV; min_pos++)
{
glTexCoord2f(tex_shift[vert_pos*4], tex_shift[vert_pos*4+1]);
glNormal3f(norm[vert_pos*6], norm[vert_pos*6+1], norm[vert_pos*6+2]);
glVertex3f(vert[vert_pos*6], vert[vert_pos*6+1], vert[vert_pos*6+2]);
glTexCoord2f(tex_shift[vert_pos*4+2], tex_shift[vert_pos*4+3]);
glNormal3f(norm[vert_pos*6+3], norm[vert_pos*6+4], norm[vert_pos*6+5]);
glVertex3f(vert[vert_pos*6+3], vert[vert_pos*6+4], vert[vert_pos*6+5]);
vert_pos ++;
}
glEnd();
}
if(wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_TEXTURE_2D);
if(hedgehog && pass == numpasses)
{
// draws normal, tangent and binormal vectors
// different sides of mesh get drawn two shades with displacement
// this is to verify matching normals on adjacent meshes
vert_pos = 0;
for(maj_pos = 0; maj_pos < MAJOR_DIV; maj_pos++)
{
glBegin(GL_LINES);
for(min_pos = 0; min_pos <= MINOR_DIV; min_pos++)
{
// Ts & Bs can be used scale the coordinate frame to texture space,
// scale is stored in 4th component
Ts = 1.0f;// /tangent[vert_pos*8+3];
Bs = 1.0f;// /binorm[vert_pos*8+3];
// normal
glColor3f(0.5, 0.0, 0.0);
glVertex3f(vert[vert_pos*6], vert[vert_pos*6+1], vert[vert_pos*6+2]);
glVertex3f(vert[vert_pos*6]+norm[vert_pos*6]*.5f, vert[vert_pos*6+1]+norm[vert_pos*6+1]*.5f, vert[vert_pos*6+2]+norm[vert_pos*6+2]*.5f);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(vert[vert_pos*6+3]+norm[vert_pos*6+3]*.5f, vert[vert_pos*6+4]+norm[vert_pos*6+4]*.5f, vert[vert_pos*6+5]+norm[vert_pos*6+5]*.5f);
glVertex3f(vert[vert_pos*6+3]+norm[vert_pos*6+3], vert[vert_pos*6+4]+norm[vert_pos*6+4], vert[vert_pos*6+5]+norm[vert_pos*6+5]);
// tangent
glColor3f(0.0, 0.5, 0.0);
glVertex3f(vert[vert_pos*6], vert[vert_pos*6+1], vert[vert_pos*6+2]);
glVertex3f(vert[vert_pos*6]+tangent[vert_pos*8]*.5f*Ts, vert[vert_pos*6+1]+tangent[vert_pos*8+1]*.5f*Ts, vert[vert_pos*6+2]+tangent[vert_pos*8+2]*.5f*Ts);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(vert[vert_pos*6+3]+tangent[vert_pos*8+4]*.5f*Ts, vert[vert_pos*6+4]+tangent[vert_pos*8+5]*.5f*Ts, vert[vert_pos*6+5]+tangent[vert_pos*8+6]*.5f*Ts);
glVertex3f(vert[vert_pos*6+3]+tangent[vert_pos*8+4]*Ts, vert[vert_pos*6+4]+tangent[vert_pos*8+5]*Ts, vert[vert_pos*6+5]+tangent[vert_pos*8+6]*Ts);
// binormal
glColor3f(0.0, 0.0, 0.5);
glVertex3f(vert[vert_pos*6], vert[vert_pos*6+1], vert[vert_pos*6+2]);
glVertex3f(vert[vert_pos*6]+binorm[vert_pos*8]*.5f*Bs, vert[vert_pos*6+1]+binorm[vert_pos*8+1]*.5f*Bs, vert[vert_pos*6+2]+binorm[vert_pos*8+2]*.5f*Bs);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(vert[vert_pos*6+3]+binorm[vert_pos*8+4]*.5f*Bs, vert[vert_pos*6+4]+binorm[vert_pos*8+5]*.5f*Bs, vert[vert_pos*6+5]+binorm[vert_pos*8+6]*.5f*Bs);
glVertex3f(vert[vert_pos*6+3]+binorm[vert_pos*8+4]*Bs, vert[vert_pos*6+4]+binorm[vert_pos*8+5]*Bs, vert[vert_pos*6+5]+binorm[vert_pos*8+6]*Bs);
vert_pos ++;
}
glEnd();
}
}
}