The first project I did when learning OpenGL was a very simple project with one goal: create something pretty. We were challenged to create an object that would render on screen with a given OpenGL project sample and I decided I would create a heart. Check out this video for the rundown on the project:
Here's the code I used to render the heart:
//set up for all the different things needed to draw the heart
float a1, a2;
a1 = 2.0;
a2 = -2.0;
int steps = 10;
int numSegments = 5;
float xmod = 1;
float ymod = 1;
float xmod1 = 1;
float ymod1 = 1;
float shift = 0;
float shift1 = 0;
float segshift = 0;
float segshiftNext = 0.35;
//This first for loop draws the two halves of the heart
//Later on I use i to modify the vertices to mirror the
//half of the heart, skipping i == 0 to do some black magic
for (int i = -1; i <= 1; ++i) {
if (i == 0) continue;
//reset the modifiers for each half of the heart
xmod = 1;
ymod = 1;
xmod1 = 1;
ymod1 = 1;
shift = 0;
shift1 = 0;
segshift = 0;
segshiftNext = 0.2;
float color1 = 0.0;
float color2 = 0.5;
float color3 = 1;
int color_inc = 0;
float color_add = 2;
//Draw each strip of the heart
//Any more than six segments with the current
//code makes some funky effects
for (int j = 1; j <= numSegments; ++j) {
//start the triangle strip topology
glBegin(GL_TRIANGLE_STRIP);
//Some math to modify how quickly each segment shrinks
//modify xmod, ymod, and shift
float modbase = (float)(j) / 10;
float modbase1 = modbase * modbase;
float modbase2 = modbase1 * modbase;
xmod1 -= modbase1;
ymod1 -= 0.1;
shift1 +=modbase2;
//Then walk around the edge of the cardioid
//Special note here that 90 to 450 is 360 degrees,
//but this loop goes one step further, this is to fully
//complete the ring and avoid holes in the mesh
for (int t = 90; t < 450 + steps; t += steps) {
//Convert from degress to radians
float rad = (3.14159 / 180.0)*t;
//calculate the radius of the cardioid at the given angle in radians
float r2 = a1 + a2 * sin(rad) + sin(rad)*(sqrt(fabs(cos(rad))) / (sin(rad) + 1.4));
//a much less interesting cardioid that I didn't end up using
float r = (a1 + a2 * sin(rad));
//now convert from polar coordinates to rectangular
float x = r2 * cos(rad);
float y = r2 * sin(rad);
//Set the color for the vertex, the colors increment every two vertices
float rgb[3];
float hsv[3] = { color1, color2, color3 };
HsvRgb(hsv, rgb);
glColor3f(rgb[0], rgb[1], rgb[2]);
//Draw this current ring
glVertex3f((float)(x * xmod), (float)(y*ymod - shift), (float)(i)*segshift);
//Draw the next ring out with modified values
//Don't need no stinkin transformation functions!
glVertex3f((float)(x * xmod1), (float)(y*ymod1 - shift1), (float)(i)*(segshift + segshiftNext));
//Update the colors in HSV
//Original colors were named for RGB
//So the names are kinda weird and I'm lazy
if (color1 < 360) {
color1 += color_add;
}
else {
if (color2 < 1) {
color2 += 0.1;
}
else {
color1 = 0.0; //hue starts at 0
color2 = 0.5; //saturation starts at 0.5
color3 = 1; //value is always 1
}
}
}
//End this part of the topology
glEnd();
//Change the modifiers for the next ring
segshift = segshift + segshiftNext;
xmod = xmod1;
ymod = ymod1;
shift = shift1;
}
//draw end caps
//This is the same code for the very last ring
//except using a polygon instead of a triangle strip
for (int j = 1; j <= numSegments; ++j) {
glBegin(GL_POLYGON);
for (int t = 90; t < 450 + steps; t += steps) {
float rad = (3.14159 / 180.0)*t;
float r2 = a1 + a2 * sin(rad) + sin(rad)*(sqrt(fabs(cos(rad))) / (sin(rad) + 1.4));
float r = (a1 + a2 * sin(rad));
float x = r2 * cos(rad);
float y = r2 * sin(rad);
glVertex3f((float)(x * xmod), (float)(y*ymod - shift), (float)(i)*segshift);
}
glEnd();
}
}