dots.c
contents ::
  dots.c
  Makefile



/* This is a block comment! */

/*
** Parts of the lab are freely adapted from:
**
** Computer Graphics using OpenGL (Second Edition)
** F.S. Hill, Jr.
** Prentice Hall (2001)
** 
** -Raymond
*/


/*
** the OpenGL include files
**
** these are system libraries we need.
*/
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

/*
**  some other include files 
*/
#include <stdio.h>          //  include for console and file IO  (not used)
/*#include <stdlib.h>*/       //  include for standard things (not needed here)



/* an example #define,
**
**  this is an instruction to the compiler to replace every instance of
**  'gasketSize' by '10000' *before* doing the compilation.
**  It can be used to create a number of 'interesting' effects - but we
**  will usually only use it to define constants.
*/
#define gasketSize 10000
#define screenHeight 480



/*
** TYPE DECLARATIONS
*/

/*
** this a record structure that contains two GL integers (x, and y).
*/
typedef struct
{
  GLint x, y;
} GLintPoint;

/*
** ... and this is a record of three GL floats (reals) for colour.
**     r, g, and b  can have the real values between 0 and 1.
*/
typedef struct
{
  GLfloat r, g, b;
} GLfloatRGBColour;


/*
** GLOBAL VARIABLES
*/

/*
**  create an array[0..7] of colours; and initialising their values!
*/
GLfloatRGBColour colour[8] = { {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f},
                                  {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f},
                               {0.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 1.0f},
                               {1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 1.0f}};

// a global variable to keep track of which of the palate colours we're using.
int penColour = 0;


/*
** FUNCTION HEADERS - a list of the functions
*/
int my_random(int m);

void clearScreen(void);
void showScreen(void);
void setPenSize(GLfloat size);
void setPenColour(GLfloatRGBColour newColour);

void drawPoint(GLint x, GLint y);

void drawSierpinski(GLintPoint T[3]);

void myDisplay(void);
void myMouse(int button, int state, int x, int y);
void myKeyboard(unsigned char theKey, int mouseX, int mouseY);

void myInit(void);

int  main (int argc,  char** argv);


/*
** UTILITY FUNCTIONS
*/

/* returns an integer in the range 0..(m-1) */
int my_random(int m)
{
  return rand()%m;
}

void clearScreen(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
}

void showScreen(void)
{
  glFlush();
}

void setPenSize(GLfloat size)
{
  glPointSize(size);
}

void setPenColour(GLfloatRGBColour newColour)
{
  glColor3f(newColour.r, newColour.g, newColour.b);
}


void drawPoint(GLint x, GLint y)
{
  glBegin(GL_POINTS);
  glVertex2i(x, y);
  glEnd();
}

/*
**  DRAWING ROUTINES
*/


/*
** Sierpinski Drawing Routine
*/
void drawSierpinski(GLintPoint corner[3])

  int i, index, tcolour=0;
  GLintPoint point;


  clearScreen();
  setPenSize(2);
  point = corner[my_random(3)];
  drawPoint(point.x, point.y);

  for (i = 0; i < gasketSize; i++)
  {
    index = my_random(3);
    point.x = (point.x + corner[index].x)/2;
    point.y = (point.y + corner[index].y)/2;  
    tcolour = (++tcolour)%7;       // col = (col + 1) mod 7;
    setPenColour(colour[tcolour]);
    drawPoint(point.x, point.y);
  }

  showScreen();
}


/*
**  The main display function
*/
void myDisplay(void)
{
  //glClear(GL_COLOR_BUFFER_BIT);
  clearScreen();
  // glBegin(GL_POINTS);
  //glVertex2i(100, 50);
  drawPoint(100, 50);
  //glVertex2i
  drawPoint(100, 130);
  //glVertex2i
  drawPoint(150, 130);
  // glEnd();
  //glFlush();
  showScreen();
}


/*
**  EVENT LISTENERS
*/

/*
**  Mouse Listener
*/
void myMouse(int button, int state, int x, int y)
{
  static GLintPoint corners[3];
  static int numCorners;

  if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
  {
    corners[numCorners].x = x;
    corners[numCorners].y = screenHeight - y - 1;
    if (++numCorners == 3)
    {
      drawSierpinski(corners);
      numCorners = 0;
    }
  }
}

/*
**  Key Listener
*/
void myKeyboard(unsigned char theKey, int mouseX, int mouseY)
{
  // correct (flip) the y coordinate
  mouseY = screenHeight - mouseY - 1;

  switch (theKey)
  {
    // if we type a 'p' - draw a point where the mouse is.
    case 'p':
    case 'P': drawPoint(mouseX, mouseY);
              showScreen();
              break;

    // if we type a 'c' - cycle through the 7 visible colours
    case 'c':
    case 'C': penColour = (++penColour)%7;       // col = (col + 1) mod 7;
              setPenColour(colour[penColour]);
              break;

    // if we type an 'r' - redraw the screen
    case 'r':
    case 'R': myDisplay();
              break;

    // if we type an 'w' - redraw the screen
    case 'w':
    case 'W': clearScreen();
              break;
    // if we type a 'q' - quit the program normally
    case 'q':
    case 'Q': exit(0);

    // otherwise - we don't have anything to do.
    default: break;
  }
}

/*
**  INITIALISERS
*/


/*
**  My Init
*/
void myInit(void)
{
  glClearColor(1.0, 1.0, 1.0, 0.0);
  glColor3f(0.0f, 0.0f, 0.0f);
  glPointSize(4.0);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}


/*
**  Main
*/
int main (int argc,  char** argv)
{

  /* GL initialisers */
  glutInit(&argc, argv);                       //initialise the toolkit
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); //set the display mode

  /* GL initialising the window */
  glutInitWindowSize(640, 480);
  glutInitWindowPosition(100, 150);
  glutCreateWindow("Dots and the Sierpinski Gasket");

  /*
  ** GL register the callback functions to deal with
  ** display, mouse, & keyboard
  */
  glutDisplayFunc(myDisplay);
  glutKeyboardFunc(myKeyboard);
  glutMouseFunc(myMouse);   //  (initially we've no mouse listener)

  /* GL now lets us do our own initialisations */
  myInit();

  /*
  ** Now we enter a special loop, which listens for events to
  ** be processed.
  ** It calls the Display function, and waits.
  */
  glutMainLoop();

  return 0;  // the main function need to return something
}

James Little