January 30, 2014

Polar graphs - Part 4

So this is getting pretty cool!

Added floating point parsing functionality, so I can pass in decimal points now. And I made it so the separate graphs will display in different colors, so you know which one's which.  Removed the annoying exclamation point when it displays it in the equation window.

Further improvements that could be made:
- Allow for whitespace in the equation
- Expand the equation display screen if needed (right now it's a fixed size)
- More robust error handling - for now the parser assumes everything is valid input
- Make my "remove from char array" functions more flexible (removeCharFromEnd is probably kind of stupid)
- Most importantly, start refactoring the code.  I hate long methods and that's exactly what I have.  Also, all of this shouldn't be in one file.  Some of my variable names could be better.  I can probably hook up the colors together better - right now it's the programmer's responsibility to make sure my int declarations of colors (RED, ORANGE, GREEN, etc.) match up with the order in my colors matrix (ooh - dictionary).

Anyways, click here to see my messy code:

And my crazy picture:

I actually really like the first couple (PI/4 and PI/2).  Of course it all looks pretty cool.  But the beginning ones look.. wispy.  I like that.

January 29, 2014

Polar Graphs - part 3

Made some progress!

Some improvements: I now display the graph and equations in separate windows, so that it's not terribly confusing to have multiple graphs on the same square.  Now I just need to add the equations I wanna display to one vector<string> and it'll draw those graphs and also display the equations in the window.

Yup, I went ahead and did the recursive descent parser.  It could still use improvements - I have to end it with an arbitrary character so the program won't try and parse invalid data (right now I'm using an exclamation point).  It's not good at error handling and it assumes the data is fed to it perfectly.  It won't even handle white space yet, and I can only use whole numbers because it doesn't know how to deal with decimal points yet.  So I'll need to work on that but it's a start.

Also, all of this is in one file and I don't like that.  The recursive descent parser should at least be in a separate file, it not more functions.  With C# or Java it's really easy to separate out things into different files, not quite fluent with C++ so simple things like this are really difficult.

Of course this program could use a lot of improvement but a lot of the extra functionality I wanted to include are in here now.

Click here to see my code:


Picture:



Not too fond of how it displays the exclamation points still in the display but I'll fix that

January 27, 2014

Polar Graphs part 2

I made a number of small improvements to my previous program.

Displayed the equation on the graph - and moved the generation of the equation earlier up in my code (string equation and the function implementation for float radius are closer together) to make it easier to sync between the two.  Optimally I would only have to define it once but that would be a hairy thing to try and implement now (would require a recursive descent parser).

I have a matrix of string angles, which will display how far the angle was drawn.  It's nice because I can easily switch between increments of PI/2, PI/3, and PI/4 by declaring angle_index to either 0, 1, 2.  I don't have to worry about changing the display or changing the increments because angle_index hooks up all of that.

You know, when taking my C class I never thought I would ever have to do bit manipulation but I actually use it in my display function.  It's not perfect yet, but I made it so I can display more squares (my below post could only support 4, but I can easily make it display 9 squares by changing numOfSquares to 9 instead of 4, and changing the mask to 0x3 instead of 0x1).  I've managed to parameterize out most of the math but I haven't figured out a mathematical equation to map numOfSquares to mask so it has to be hardcoded for now.  Basically the premise is to, with a single pass, manipulate the iterator so that it'll display all combinations of {000, 001, 010, ..., 100} which will put each square in a different spot on the screen.

So here's the code:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glext.h>
using namespace std;

int header_space = 30;
int window_width = 500, window_height = 500 + header_space;
int xPos = 10, yPos = 10;
string equation = ".05 * (angle + 2)";

string angles[3][11] = {
{"PI/2", "PI", "3PI/2", "2PI", "5PI/2", "3PI", "7PI/2", "4PI", "9PI/2", "5PI", "11PI/2"},
{"PI/3", "2PI/3", "PI", "4PI/3", "5PI/3", "2PI", "7PI/3", "10PI/3", "11PI/3", "4PI", "13PI/3"},
{"PI/4", "PI/2", "3PI/4", "PI", "9PI/4", "5PI/2", "11PI/4", "3PI", "13PI/4", "7PI/2", "15PI/4"}
};
int angle_index = 2;

#define PI 3.1415926535897932384626433832795

float radius(float angle) {
return .05 * (angle + 2);
}

void writeText(int xPos, int yPos, float size, string message) {
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, window_width, 0.0, window_height, -1.0, 1.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(xPos, yPos, 0);
  glScalef(size, size, 0);
 
  glColor3f(1, 1, 1);
  for (size_t i = 0; i < message.length(); i++) {
 glutStrokeCharacter(GLUT_STROKE_ROMAN, message[i]);
  }
}

float determineAngleIncrement() {
float angle_increment;
switch (angle_index) {
case 0:
angle_increment = PI/2;
break;
case 1:
angle_increment = PI/3;
break;
case 2:
angle_increment = PI/4;
break;
}

return angle_increment;
}

void drawAngle(int i) {

glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();

glBegin(GL_POINTS);
float angle_increment = determineAngleIncrement();
for (float angle = 0; angle < i * angle_increment + angle_increment; angle += .005) {
float r = radius(angle);
float x = r * cos(angle);
float y = r * sin(angle);

glVertex3f(x, y, 0);
}
glEnd();

glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
glPopMatrix ();
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(1,1,1,1);

float header_font_size = .2, text_size = .3;

int numOfSquares = 9;
int numOfCols = sqrt(numOfSquares);
int mask = 0x3;

writeText(xPos, window_height - header_space, header_font_size, "r = " + equation);
int space = 10, yScale = (window_height - header_space) / numOfCols, xScale = window_width / numOfCols;

for (int i = 0; i < numOfSquares; i++) {
int xToggle = (i % numOfCols) & mask, yToggle = (i / numOfCols) & mask;
int xMin = xToggle * xScale, yMin = yToggle * yScale;
int xCorrection = xToggle * (space / numOfCols), yCorrection = yToggle * (space / numOfCols);
int width = xScale - (space / numOfCols), height = yScale - (space / numOfCols);

glViewport(xMin + xCorrection, yMin + yCorrection, width, height);
drawAngle(i);
writeText(xPos, yPos, .3, angles[angle_index][i]);
}

glFlush();
}


///////////////////////////////////////////////////////////////

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitWindowSize(window_width, window_height);
  glutCreateWindow("polar equations graph");
  glutDisplayFunc(display);
  glutMainLoop();
}

With some pictures:

I'd like to note that if I were trying to teach this to someone my explanations would be a bit better.. I realize my explanations up top weren't completely intelligible.

January 23, 2014

Polar graphs Part 1

I've recently been really interested in polar graphs.  I mean, you can make some really cool things with them:

 

And it's kind of tedious to punch in values into an online polar graphing app and see how the graph varies with different parameters, different ranges.  Maybe I just didn't look hard enough.  But I wanted to see if I could code my own.

So I did.  Here it is:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glext.h>
using namespace std;

int window_width = 500, window_height = 500;
int xPos = 10, yPos = 10;
string angles[] = {"PI/2", "PI", "3PI/2", "2PI"};

#define PI 3.1415926535897932384626433832795

void writeText(int xPos, int yPos, string message) {
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, window_width, 0.0, window_height, -1.0, 1.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(xPos, yPos, 0);
  glScalef(.3, .3, 0);
 
  glColor3f(.1176, .562, 1);
  for (size_t i = 0; i < message.length(); i++) {
 glutStrokeCharacter(GLUT_STROKE_ROMAN, message[i]);
  }
}

void drawAngle(int i) {

glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();

glBegin(GL_POINTS);
for (float angle = 0; angle < i*(PI/2) + PI/2; angle += .005) {
float radius = angle * .1;
//message.append("1");
float x = radius * cos(angle);
float y = radius * sin(angle);

glVertex3f(x, y, 0);
}
glEnd();

glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
glPopMatrix ();
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(.1176,.562,1,1);

int space = 10, yScale = window_height / 2, xScale = window_width / 2;

for (int i = 0; i < 4; i++) {
int xToggle = i & 0x1, yToggle = (i >> 1) & 0x1;
int xMin = xToggle * xScale, yMin = yToggle * yScale;
int xCorrection = xToggle * (space / 2), yCorrection = yToggle * (space / 2);
int width = xScale - (space / 2), height = yScale - (space / 2);

glViewport(xMin + xCorrection, yMin + yCorrection, width, height);
drawAngle(i);
writeText(xPos, yPos, angles[i]);
}

glFlush();
}


///////////////////////////////////////////////////////////////

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitWindowSize(window_width, window_height);
  glutCreateWindow("polar coordinates graph");
  glutDisplayFunc(display);
  glutMainLoop();
}

Again, don't completely understand everything up above (especially the matrix stuff) but the understanding is solidifying.

Sample output:



There are some things I'd like to do: display the equation above or below the graph (was having trouble with the Viewports), make even more ranges, have less hard-coded values and have the program eventually parse the r value as a string (which I would need to use recursive descent parsing for..)

But I think this helps a lot.  It automates a lot of the things I was doing by hand before.

January 22, 2014

OpenGL - Writing text

Making text on OpenGL is a lot more complicated than I would have thought..  And I still don't really understand everything in the code below.  Or if I'm following the right conventions or something.

Sigh.  Being a complete beginner is rough.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glext.h>
using namespace std;

int width = 500;
int height = 500;

void writeText(string message) {
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 0);

  glMatrixMode(GL_MODELVIEW);

  glLoadIdentity();
  glTranslatef(1.5, 1, 0);

  glLoadIdentity();
  glScalef(.0005,.0005,0);
 
  glColor3f(.1176,.562,1);
  for (size_t i = 0; i < message.length(); i++) {
 glutStrokeCharacter(GLUT_STROKE_ROMAN, message[i]);
  }
}

void display()
{
  glClear(GL_COLOR_BUFFER_BIT);

  string message = "Sup World";
  writeText(message);
  glFlush();
}


///////////////////////////////////////////////////////////////

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitWindowSize(width, height);
  glutCreateWindow("text");
  glutDisplayFunc(display);
  glutMainLoop();
}

Sup:

January 21, 2014

OpenGL: Messing with input

Thought I would try my hand at messing with input.  So what this code does is record all of the points on the screen that the user clicked and displays them.

I'm realizing that functions like display(), mykey, mymouse are what my C teacher was talking about (function pointers) and I didn't really understand them at the time.  I guess C# makes it easier with delegates, but it's nice to see what it is on a lower level.

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glext.h>

struct vertex {
double x;
double y;
};

std::vector<vertex> vertices;

//////////////////////////////////////////////////////

void display()
{
glClearColor(0,0,0,1); 
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 

glPointSize(10);
glBegin(GL_POINTS); 

glVertex3f(-1,-1,0);

glColor3f(1, .0784, .576);
for (size_t i = 0; i < vertices.size(); i++) {
vertex temp = vertices[i];
glVertex3f((temp.x/600)* 2 - 1, -1*((temp.y/600) * 2 - 1), 0);
}
glEnd(); 

glutSwapBuffers(); 
}

///////////////////////////////////////////////////////////

void mymouse(int button, int state, int x, int y)
{
if (state == GLUT_DOWN) {
vertex new_vertex;
new_vertex.x = (double)x;
new_vertex.y = (double)y;
vertices.push_back(new_vertex);
}

glutPostRedisplay();
}

///////////////////////////////////////////////////////////////

void mykey(unsigned char key, int x, int y)
{
 switch(key) {
case 'q': exit(1);
break; 

case 'w':
for (size_t i = 0; i < vertices.size(); i++) {
printf("%d %d, ", vertices[i].x, vertices[i].y);
}
printf("\n\n");
break;
}
}
///////////////////////////////////////////////////////////////

int main(int argc, char** argv) 
{
glutInit(&argc, argv); 
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE); 
glutInitWindowSize(600,600); 

glutCreateWindow("Record mouse clicks"); 
glutDisplayFunc(display); 
glutMouseFunc(mymouse); 
glutKeyboardFunc(mykey); 
glutMainLoop(); 
}




I'm doing a bunch of small things right now, but I'm hoping they are all building blocks to something cool I'll be able to do in the future.

January 18, 2014

Rainbow - part 5

I didn't realize this before - converting RGB values to OpenGL colors is really easy - just convert the RGB value by dividing by 255.  I wanted DeepBlueSky with RGB values (0, 212, 255), so the corresponding OpenGL colors are (0, 0.83, 1).

I did a bit more refactoring.  The rainbow is now smaller and its two ends are covered by "clouds" - just two ellipses for now.  And the background is blue.  For some reason there's two notches in the sides of each curved line in the rainbow but I'm not gonna worry about that for now.

So here's my new code:

#define PI 3.1415926535897932384626433832795

float colors[] =
{1.0, 0.0, 0.0,
 1.0, 0.5, 0.0,
 1.0, 1.0, 0.0,
 0.0, 1.0, 0.0,
 0.0, 0.0, 1.0,
 1.0, 0.0, 1.0,
 1.0, 1.0, 1.0};

typedef struct
{
  float x;
  float y;
} ELLIPSE;

int RED = 0, ORANGE = 3, YELLOW = 6, GREEN = 9, BLUE = 12, PURPLE = 15, WHITE = 18;

void drawCurvedLine(float a, float b, int color, float yPos) {
  ELLIPSE ellipse;
  glColor3f(colors[color], colors[color + 1], colors[color + 2]);

  for (float i = 0; i < PI; i+=.1) {
 ellipse.x = a * cos((float)i);
 ellipse.y = b * sin((float)i);
 glVertex3f(ellipse.x, ellipse.y + yPos, 0);

 ellipse.x = a * cos((float)(i + .1));
 ellipse.y = b * sin((float)(i + .1));
 glVertex3f(ellipse.x, ellipse.y + yPos, 0);
  }
}

void drawRainbow(float thickness) {
  float b = .8, a = .9, y = -0.1;
  float yEpsilon = .05, aEpsilon = .035;

  glLineWidth(thickness);
  glBegin(GL_LINES);

  drawCurvedLine(a, b, RED, y);
  drawCurvedLine(a - aEpsilon, b, ORANGE, y - yEpsilon);
  drawCurvedLine(a - 2*aEpsilon, b, YELLOW, y - 2*yEpsilon);
  drawCurvedLine(a - 3*aEpsilon, b, GREEN, y - 3*yEpsilon);
  drawCurvedLine(a - 4*aEpsilon, b, BLUE, y - 4*yEpsilon);
  drawCurvedLine(a - 5*aEpsilon, b, PURPLE, y - 5*yEpsilon);

  glEnd();
}

void drawEllipse(float a, float b, int color, float xPos, float yPos) {
glColor3f(colors[color], colors[color + 1], colors[color + 2]);

glBegin(GL_TRIANGLE_FAN);
glVertex2f(xPos,yPos);

for (float angle = 1; angle <= 360; angle += 0.2)
{
float xTemp = sin(angle)*a + xPos;
float yTemp = cos(angle)*b + yPos;
glVertex2f(xTemp,yTemp);
}

glEnd();
}

void display()
{
  glClearColor(0,.83,1,1);
  glClear(GL_COLOR_BUFFER_BIT);

  float thickness = 9;
  drawRainbow(thickness);

  float width = .3, height = .22;
  float xPos = -.68, yPos = -.2, xOtherSide = 1.37;
  drawEllipse(width, height, WHITE, xPos, yPos);
  drawEllipse(width, height, WHITE, xPos + xOtherSide, yPos);

  glutSwapBuffers();
}

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
  glutInitWindowSize(600,600);

  glutCreateWindow("better rainbow");
  glutDisplayFunc(display);

  glutMainLoop();
}

And here it is now:

January 17, 2014

Rainbow - part 4

Improved on the previous by modifying my code to draw ellipses instead of circles.

#define PI 3.1415926535897932384626433832795

float colors[] =
{1.0, 0.0, 0.0,
1.0, 0.5, 0.0,
1.0, 1.0, 0.0,
 0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0};

typedef struct
{
  float x;
  float y;
} ELLIPSE;

int RED = 0, ORANGE = 3, YELLOW = 6, GREEN = 9, BLUE = 12, PURPLE = 15;

void createEllipse(float a, float b, int color, float yPos, float thickness) {
  ELLIPSE ellipse;
  glLineWidth(thickness);

  glBegin(GL_LINES);
  glColor3f(colors[color], colors[color + 1], colors[color + 2]);

    for (float i = 0; i < PI; i+=.1) {
      ellipse.x = a * cos(i);
      ellipse.y = b * sin(i);
      glVertex3f(ellipse.x, ellipse.y + yPos, 0);

      ellipse.x = a * cos(i + 0.1);
      ellipse.y = b * sin(i + 0.1);
      glVertex3f(ellipse.x, ellipse.y + yPos, 0);
    }
    glEnd();
}

void display()
{
  glClearColor(1,1,1,1);
  glClear(GL_COLOR_BUFFER_BIT);

  float thickness = 7, b = 1, a = 1.33, y = -0.1;
  float yEpsilon = .05, aEpsilon = .01;

  createEllipse(a, b, RED, y, thickness);
  createEllipse(a - aEpsilon, b, ORANGE, y - yEpsilon, thickness);
  createEllipse(a - 2*aEpsilon, b, YELLOW, y - 2*yEpsilon, thickness);
  createEllipse(a - 3*aEpsilon, b, GREEN, y - 3*yEpsilon, thickness);
  createEllipse(a - 4*aEpsilon, b, BLUE, y - 4*yEpsilon, thickness);
  createEllipse(a - 5*aEpsilon, b, PURPLE, y - 5*yEpsilon, thickness);

  glutSwapBuffers();
}

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
  glutInitWindowSize(600,600);

  glutCreateWindow("not a rainbow but i can still pretend");
  glutDisplayFunc(display);

  glutMainLoop();
}

Looking more like a rainbow now!



Yay!

January 16, 2014

Rainbow - part 3

Made some adjustments, looked online for some help and played with some trig.

#define PI 3.1415926535897932384626433832795

float colors[] =
{1.0, 0.0, 0.0,
1.0, 0.5, 0.0,
1.0, 1.0, 0.0,
 0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0};

typedef struct
{
  float x;
  float y;
} CIRCLE;

int RED = 0, ORANGE = 3, YELLOW = 6, GREEN = 9, BLUE = 12, PURPLE = 15;

void createCircle(int r, int color, float yPos) {
  CIRCLE circle;
  glBegin(GL_LINES);
  glColor3f(colors[color], colors[color + 1], colors[color + 2]);

    for (float i = 0; i < PI; i+=.1) {
      circle.x = r * cos(i);
      circle.y = r * sin(i);
      glVertex3f(circle.x, circle.y + yPos, 0);

      circle.x = r * cos(i + 0.1);
      circle.y = r * sin(i + 0.1);
      glVertex3f(circle.x, circle.y + yPos, 0);
    }
    glEnd();
}

void display()
{
  glClearColor(1,1,1,1);
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_LINES);

  createCircle(1, RED, 0);
  createCircle(1, ORANGE, -.05);
  createCircle(1, YELLOW, -.1);
  createCircle(1, GREEN, -.15);
  createCircle(1, BLUE, -.2);
  createCircle(1, PURPLE, -.25);

  glEnd();
  glutSwapBuffers();
}

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
  glutInitWindowSize(600,600);

  glutCreateWindow("not a rainbow but i can still pretend");
  glutDisplayFunc(display);

  glutMainLoop();
}

And here is the end result:


It still looks a little weird but it's looking more like a rainbow!  Yay!

January 15, 2014

Rainbow - part 2

float colors[] =
{1.0, 0.0, 0.0,
1.0, 0.5, 0.0,
1.0, 1.0, 0.0,
 0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0};

int startX = -1.0, middleX = 0.0, endX = 1.0;
int RED = 0, ORANGE = 3, YELLOW = 6, GREEN = 9, BLUE = 12, PURPLE = 15;

void drawLine(float rainbowBottom, int color)
{
glBegin(GL_LINES);
glColor3f(colors[color], colors[color + 1], colors[color + 2]);
glVertex3f(startX, rainbowBottom, 0.0);
glVertex3f(middleX, rainbowBottom + .08, 0.0);
glVertex3f(middleX, rainbowBottom + .08, 0.0);
glVertex3f(endX, rainbowBottom, 0.0);
glEnd();
}

void display()
{
  glClearColor(1,1,1,1);
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_LINES);

  drawLine(.5, RED);
  drawLine(.45, ORANGE);
  drawLine(.4, YELLOW);
  drawLine(.35, GREEN);
  drawLine(.3, BLUE);
  drawLine(.25, PURPLE);

  glEnd();
  glutSwapBuffers();
}

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
  glutInitWindowSize(600,600);

  glutCreateWindow("not a rainbow but i can still pretend");
  glutDisplayFunc(display);

  glutMainLoop();
}

Still does the same thing, but in a clearer way to understand.

I do realize I could be using github.

January 13, 2014

My first openGL program! Rainbow - part 1

I am finally taking graphics classes and I am so excited!  We haven't had any real assignments yet, we just had to run a sample program on OpenGL and see "Hello Triangle!"  I tried playing around on my own today to familiarize myself with this program I will be using a lot.  I wanted to make a rainbow today.  It's not quite a rainbow yet but it's trying.

Here is my source code so I don't lose it!  And with comments that hopefully will clear things up for myself when I look at it down the road.

void display()
{
glClearColor(1,1,1,1); // made the background white
glClear(GL_COLOR_BUFFER_BIT); // not sure what this does but it doesn't clear properly without it

glBegin(GL_LINES);

// draws red part
glColor3f(1.0, 0.0, 0.0);
    glVertex3f(-1.0, 0.5, 0.0);
glVertex3f(0.0, 0.55, 0.0);
glVertex3f(0.0, 0.55, 0.0);
glVertex3f(1.0, 0.5, 0.0);

// draws orange part
glColor3f(1.0, 0.5, 0.0);
glVertex3f(-1.0, 0.45, 0.0);
glVertex3f(0.0, 0.5, 0);
glVertex3f(0.0, 0.5, 0.0);
glVertex3f(1.0, 0.45, 0);

// draws yellow part
glColor3f(1.0, 1.0, 0.0);
glVertex3f(-1.0, 0.40, 0.0);
glVertex3f(0.0, 0.45, 0);
glVertex3f(0.0, 0.45, 0.0);
glVertex3f(1.0, 0.40, 0);

// draws green part
glColor3f(0.0, 1.0, 0.0);
glVertex3f(-1.0, 0.35, 0.0);
glVertex3f(0.0, 0.4, 0);
glVertex3f(0.0, 0.4, 0.0);
glVertex3f(1.0, 0.35, 0);

// draws blue part
glColor3f(0.0, 0.0, 1.0);
glVertex3f(-1.0, 0.3, 0.0);
glVertex3f(0.0, 0.35, 0.0);
glVertex3f(0.0, 0.35, 0.0);
glVertex3f(1.0, 0.3, 0.0);

// draws purple part
glColor3f(1.0, 0.0, 1.0);
glVertex3f(-1.0, 0.25, 0.0);
glVertex3f(0.0, 0.3, 0);
glVertex3f(0.0, 0.3, 0);
glVertex3f(1.0, 0.25, 0);

// every begin needs a matching end
// every specific shape needs a separate begin, end (can't draw triangles in between this, for example)
glEnd();

glutSwapBuffer(); // not sure what this does but without it, the entire image becomes white
}

int main(int argc, char** argv)
{
glutInit(&argc, argv); // still worked when this was commented out.. hmm..
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(600,600);

glutCreateWindow("not a rainbow but i can still pretend");
glutDisplayFunc(display);

glutMainLoop(); // no compiler errors when this was off but it just closed after a second
}

I realize it could have been done a lot.. better..  But I'm gonna call the beginner card on this one.

Here it is haha:
Poor rainbow.  It's struggling