#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>    
#include <math.h>
#define SPACE 32
#define ESCAPE 27

GLint window;       
GLint window_height;
GLint Xsize=400;
GLint Ysize=500;
int zoom=40;
int grid[100][100];
int modulus = 1;
int flag;

void modulo(){
     int i , j;
     for (i=0;i<modulus;i++){
          for (j=0;j<modulus;j++){
                  grid[i][j]= (i*j)%modulus;
          }
     }
}

GLvoid Transform(GLfloat Width, GLfloat Height)
{
  glViewport(0, 0, Width, Height);              /* Set the viewport */
  glMatrixMode(GL_PROJECTION);                  /* Select the projection matrix */
  glLoadIdentity();				                /* Reset the projection matrix */
  gluPerspective(45.0,Width/Height,-100.0,100.0);  /* Calculate the aspect ratio of the window */
  glMatrixMode(GL_MODELVIEW);                   /* Switch back to the modelview matrix */
  window_height = Height;
}

GLvoid InitGL(GLfloat Width, GLfloat Height)	
{

GLfloat LightAmbient[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat LightDiffuse[] = { 1.0, 1.0, 1.0, 1.0 };  
GLfloat LightPosition[] = { 100.5, 100.5, 100.5, 0.0 };

  glClearColor(1.0, 1.0, 1.0, 1.0);
  glShadeModel(GL_SMOOTH);
  glEnable(GL_NORMALIZE);
  glEnable(GL_COLOR_MATERIAL);
  glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); 
  glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);
  glLightfv(GL_LIGHT0, GL_POSITION,LightPosition); 
  glEnable(GL_LIGHT0);                           

  Transform( Width, Height );                  
}


GLvoid ReSizeGLScene(GLint Width, GLint Height)
{
  if (Height<Ysize)    Height=Ysize;                   /* Sanity checks */
  if (Width<Xsize)     Width=Xsize;
  Transform( Width, Height );                   /* Perform the transformation */
}


static void
DrawText(GLint x, GLint y, char* s, GLfloat r, GLfloat g, GLfloat b)
{
    int lines;
    char* p;

    glMatrixMode(GL_PROJECTION);
     glPushMatrix();
     glLoadIdentity();
     glOrtho(0.0, glutGet(GLUT_WINDOW_WIDTH), 0.0, glutGet(GLUT_WINDOW_HEIGHT), -1.0, 1.0);
     glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glLoadIdentity();
      glColor3f(r,g,b);
      glRasterPos2i(x, y);
      for(p = s, lines = 0; *p; p++) {
	  if (*p == '\n') {
	      lines++;
	      glRasterPos2i(x, y-(lines*12));
	  }
	  glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *p);
      }
      glPopMatrix();
     glMatrixMode(GL_PROJECTION);
     glPopMatrix();
     glMatrixMode(GL_MODELVIEW);
}


GLvoid DrawGLScene()
{
  int i , j, k;
  char txt[8];     
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	/* Clear The Screen And The Depth Buffer */

  glPushMatrix();
  glLoadIdentity();
  gluLookAt(0,0,(90+zoom), 0, 0, 0, 0, 1, 0);
  DrawText( 5 , window_height-15 , "The primes extracted from MMOD(n, (0..n-1))\nh/shift+h - toggles on/off hammings\nSpace - Increments n\n" , 0 , 0 ,  0 ); 
  snprintf( txt, 8, "n = %d", modulus );   
  DrawText( 7 , 15 , txt , 0 , 0 ,  0 );
  
     for (i=0;i<modulus;i++){
         for (j=0;j<modulus;j++){

               glPushMatrix();
               glTranslatef(((2*i)-modulus),((2*j)-modulus),-2*modulus);
               switch (grid[i][j]){
               case 0:glColor3d(1,1,1);break;
               case 1:glColor3d(1,1,1);break;
case 2: case 3: case  5: case  7: case  11: case  13: case  17: case  19: case  23: 
case  29: case  31: case  37: case  41: case  43: case  47: case  53: case  59: 
case 61: case  67: case  71: case  73: case  79: case  83: case  89: case  97:

               if(!flag){glColor3d(1,0,0);} else {glColor3d(1,1,1);} break;
               default: if (!flag){glColor3d(1,1,1);} else {if (grid[i][j]%2==0||
                                                                grid[i][j]%3==0||
                                                                grid[i][j]%5==0)
                                                                glColor3d(0,0,1);} break;
               }

               glutSolidCube(1.0);
               glPopMatrix(); 
         }         
     }
                        
  glPopMatrix();
  glFlush(); 

}

void NormalKey(GLubyte key, GLint x, GLint y) 
{
    switch ( key )    { 
     case ESCAPE :
        printf("escape pressed. exit.\n");
	    glutDestroyWindow(window);	
	    exit(0); 		                 
     break;				
     case SPACE :
          if(modulus<100){modulus++;}else{modulus=1;}
          modulo();
     break;
     case 'h' :
           flag=1;
     break;
     case 'H' :
          flag=0;
     break;
    }
    glutPostRedisplay();
}


/*************************** Main ***************************************************************/

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



  glutInit(&argc, argv);              

  glutInitDisplayMode(GLUT_RGBA|GLUT_SINGLE|GLUT_DEPTH);    
  glutInitWindowSize(Xsize,Ysize);        
  glutInitWindowPosition(0,0);        
  window = glutCreateWindow("PMMOD"); 
  InitGL(Xsize,Ysize);
  glEnable(GL_DEPTH_TEST);                     
  glEnable(GL_LIGHTING);
  glutDisplayFunc(DrawGLScene);        
  glutReshapeFunc(ReSizeGLScene);
  glutKeyboardFunc(NormalKey);         
  glutMainLoop();                      
  return 1;
}

