#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

void draw_points(void)
{
	glPushMatrix();
	glTranslatef(-1.0, +2.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glPointSize(4.0);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_POINTS);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f( 1.0, -1.0, 0.0);
		glVertex3f( 1.0,  1.0, 0.0);
		glVertex3f(-1.0,  1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_lines(void)
{
	glPushMatrix();
	glTranslatef(-1.0, +1.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_LINES);
		glVertex3f(-1.0, +1.0, 0.0); glVertex3f(+1.0, +1.0, 0.0);
		glVertex3f(-1.0,  0.0, 0.0); glVertex3f(+1.0,  0.0, 0.0);
		glVertex3f(-1.0, -1.0, 0.0); glVertex3f(+1.0, -1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_line_strip(void)
{
	glPushMatrix();
	glTranslatef( 0.0, +1.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_LINE_STRIP);
		glVertex3f(-1.0, +1.0, 0.0);
		glVertex3f(+1.0, +1.0, 0.0);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f(+1.0, -1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_triangles(void)
{
	glPushMatrix();
	glTranslatef(-1.0, 0.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	// triangle 1
	glTranslatef(-0.2, 0.0, 0.0);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_TRIANGLES);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f(+1.0, +1.0, 0.0);
		glVertex3f(-1.0, +1.0, 0.0);
	glEnd();
	// triangle 2
	glTranslatef(0.4, 0.0, 0.0);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_TRIANGLES);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f(+1.0, -1.0, 0.0);
		glVertex3f(+1.0, +1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_triangle_fan(void)
{
	glPushMatrix();
	glTranslatef( 0.0, 0.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_TRIANGLE_FAN);
		glVertex3f( 0.0,  0.0, 0.0);
		glVertex3f(+1.0,  0.0, 0.0);
		glVertex3f(+1.0, +1.0, 0.0);
		glVertex3f(-1.0, +1.0, 0.0);
		glVertex3f(-1.0, -1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_triangle_strip(void)
{
	glPushMatrix();
	glTranslatef(1.0, 0.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_TRIANGLE_STRIP);
		glVertex3f(-1.0, +1.0, 0.0);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f( 0.0, +1.0, 0.0);
		glVertex3f(+1.0, -1.0, 0.0);
		glVertex3f(+2.0, +1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_quads(void)
{
	glPushMatrix();
	glTranslatef(-1.0, -1.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_QUADS);
		glVertex3f( 1.0,  1.0, 0.0);
		glVertex3f(-1.0,  1.0, 0.0);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f( 1.0, -1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_quad_strip(void)
{
	glPushMatrix();
	glTranslatef( 0.0, -1.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_QUAD_STRIP);
		glVertex3f(-1.0, +1.0, 0.0);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f( 0.0, +1.0, 0.0);
		glVertex3f( 0.0, -1.0, 0.0);
		glVertex3f(+1.0, +1.0, 0.0);
		glVertex3f(+1.0, -1.0, 0.0);
		glVertex3f(+2.0, +1.0, 0.0);
		glVertex3f(+2.0, -1.0, 0.0);
	glEnd();
	glPopMatrix();
}

void draw_polygon(void)
{
	glPushMatrix();
	glTranslatef(-1.0, -2.0, 0.0);
	glScalef(0.25, 0.25, 0.25);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glBegin(GL_POLYGON);
		glVertex3f(-1.0, -1.0, 0.0);
		glVertex3f(+1.0, -1.0, 0.0);
		glVertex3f(+1.3,  0.0, 0.0);
		glVertex3f( 0.0, +1.0, 0.0);
		glVertex3f(-1.3,  0.0, 0.0);
	glEnd();
	glPopMatrix();
}

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glLoadIdentity();

	gluLookAt(
		0.0,  0.0,  6.0,
		0.0,  0.0,  0.0,
		0.0,  1.0,  0.0);
	
	draw_points();
	draw_lines();
	draw_line_strip();
	draw_triangles();
	draw_triangle_fan();
	draw_triangle_strip();
	draw_quads();
	draw_quad_strip();
	draw_polygon();

	glFlush();
	glutSwapBuffers();
}

void reshape(int w, int h)
{
	// prevent division by 0
	if (h == 0) h = 1;
	
	// define viewport
	glViewport(0, 0, w, h);

	// configuration of projection matrix
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 1.0, 100.0);

	// configuration of model view matrix
	glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char ** argv)
{
	// general initialisation
	glutInit(&argc, argv);
	glutInitWindowSize(300, 300);
	glutInitWindowPosition(0, 0);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA);
	glutCreateWindow("OpenGL Demo 3");
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);

	// configuration
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);

	// go
	glutMainLoop();
	return 0;
}
