/* Simple geometry viewer:  Left mouse: rotate;  Middle mouse:  zoom;  Right mouse:   menu;  ESC to quit

 The function InitGeometry() initializes  the geometry that will be displayed. */

#include <assert.h>

#include <math.h>

#include <stdlib.h>

#include <GL/glut.h>

#define MAX_TRIANGLES (10)

struct Point {float x[3];   float n[3]; };

struct Triangle {   Point v[3];  };

Triangle triangleList[MAX_TRIANGLES];

int triangleCount = 0;

void InitGeometry();

 

/* Viewer state */

float sphi=90.0, stheta=45.0;

float sdepth = 10;

float zNear=1.0, zFar=100.0;

float aspect = 5.0/4.0;

float xcam = 0, ycam = 0;

long xsize, ysize;

int downX, downY;

bool leftButton = false, middleButton = false;

int i,j;

GLfloat light0Position[] = { 0, 1, 0, 1.0};

int displayMenu, mainMenu;

enum {WIREFRAME, HIDDENLINE, FLATSHADED, SMOOTHSHADED};

int displayMode = WIREFRAME;

 

void MyIdleFunc(void) { glutPostRedisplay();} /* things to do while idle */

void RunIdleFunc(void) {   glutIdleFunc(MyIdleFunc); }

void PauseIdleFunc(void) {   glutIdleFunc(NULL); }

 

void DrawSmoothShaded(void) {

  int i;

  assert( triangleCount < MAX_TRIANGLES );

  glColor3f(0.8f, 0.2f, 0.8f);

  glBegin ( GL_TRIANGLES ) ;

  for ( i = 0; i < triangleCount; ++i ) {

    glNormal3fv( triangleList[i].v[0].n );

    glVertex3fv( triangleList[i].v[0].x );

    glNormal3fv( triangleList[i].v[1].n );

    glVertex3fv( triangleList[i].v[1].x );

    glNormal3fv( triangleList[i].v[2].n );

    glVertex3fv( triangleList[i].v[2].x ); }

  glEnd ( ) ; }

 

void DrawWireframe(void) {

  int i;

  glColor3f(1.0, 1.0, 1.0);

  for ( i = 0; i < triangleCount; ++i ) {

    glBegin(GL_LINE_STRIP);

    glVertex3fv( triangleList[i].v[0].x );

    glVertex3fv( triangleList[i].v[1].x );

    glVertex3fv( triangleList[i].v[2].x );

    glVertex3fv( triangleList[i].v[0].x );

    glEnd();   } }

 

void DrawFlatShaded(void) {

  int i;

  glEnable(GL_POLYGON_OFFSET_FILL);

  glColor3f(0.8f, 0.2f, 0.8f);

  glBegin ( GL_TRIANGLES ) ;

  for ( i = 0; i < triangleCount; ++i ) {

    glVertex3fv( triangleList[i].v[0].x );

    glVertex3fv( triangleList[i].v[1].x );

    glVertex3fv( triangleList[i].v[2].x );   }

  glEnd ( ) ;

  glDisable(GL_POLYGON_OFFSET_FILL);}

 

void DrawHiddenLine(void) {

  glEnable(GL_POLYGON_OFFSET_FILL);

  glColor3f(0,0,0);

  glBegin ( GL_TRIANGLES ) ;

  for ( i = 0; i < triangleCount; ++i ) {

    glVertex3fv( triangleList[i].v[0].x );

    glVertex3fv( triangleList[i].v[1].x );

    glVertex3fv( triangleList[i].v[2].x );   }

  glEnd ( ) ;

  glDisable(GL_POLYGON_OFFSET_FILL);

  glColor3f(1.0,1.0,1.0);

  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

  glBegin ( GL_TRIANGLES ) ;

  for ( i = 0; i < triangleCount; ++i ) {

    glVertex3fv( triangleList[i].v[0].x );

    glVertex3fv( triangleList[i].v[1].x );

    glVertex3fv( triangleList[i].v[2].x );   }

  glEnd ( ) ;

  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); }

 

void ReshapeCallback(int width, int height) {

  xsize = width;

  ysize = height;

  aspect = (float)xsize/(float)ysize;

  glViewport(0, 0, xsize, ysize);

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glutPostRedisplay();}

 

void SetDisplayMenu(int value) {

  displayMode = value;

  switch(value) {

    case WIREFRAME: glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); break;

    case HIDDENLINE: glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); break;

    case FLATSHADED: glShadeModel(GL_FLAT); glEnable(GL_LIGHTING); break;

    case SMOOTHSHADED: glShadeModel(GL_SMOOTH); (GL_LIGHTING); break; }

  glutPostRedisplay();}

 

void SetMainMenu(int value) {switch(value) {case 99: exit(0); break;}}

 

void DisplayCallback(void) {

  glMatrixMode(GL_PROJECTION);

  glLoadIdentity();

  gluPerspective(64.0, aspect, zNear, zFar);

  glMatrixMode(GL_MODELVIEW);

  glLoadIdentity();

  glTranslatef(0.0,0.0,-sdepth);

  glRotatef(-stheta, 1.0, 0.0, 0.0);

  glRotatef(sphi, 0.0, 0.0, 1.0);

  switch (displayMode) {

    case WIREFRAME: DrawWireframe();     break;

    case HIDDENLINE: DrawHiddenLine();     break;

    case FLATSHADED: DrawFlatShaded();     break;

    case SMOOTHSHADED: DrawSmoothShaded();     break;   }

  glutSwapBuffers();

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }

 

void KeyboardCallback(unsigned char ch, int x, int y) {

  switch (ch) {case 27: exit(0);break; } glutPostRedisplay(); }

 

void MouseCallback(int button, int state, int x, int y) {

  downX = x; downY = y;

  leftButton = ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN));

  middleButton = ((button == GLUT_MIDDLE_BUTTON) &&  (state == GLUT_DOWN));

  glutPostRedisplay();}

 

void MotionCallback(int x, int y) {

  if (leftButton){sphi+=(float)(x-downX)/4.0;stheta+=(float)(downY-y)/4.0;} // rotate

  if (middleButton){sdepth += (float)(downY - y) / 10.0;  } // scale

  downX = x;   downY = y;

  glutPostRedisplay();}

 

void InitGL() {

  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

  glutInitWindowSize(500, 500);

  glutCreateWindow("cs175 Triangle Viewer");

  glEnable(GL_DEPTH_TEST);

  glDepthFunc(GL_LEQUAL);

  glClearColor(0.0, 0.0, 0.0, 0.0);

  glPolygonOffset(1.0, 1.0);

  glDisable(GL_CULL_FACE);

  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

  glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

  glEnable(GL_COLOR_MATERIAL);

  glColorMaterial(GL_FRONT, GL_DIFFUSE);

  glLightfv (GL_LIGHT0, GL_POSITION, light0Position);

  glEnable(GL_LIGHT0);

  glutReshapeFunc(ReshapeCallback);

  glutDisplayFunc(DisplayCallback);

  glutKeyboardFunc(KeyboardCallback);

  glutMouseFunc(MouseCallback);

  glutMotionFunc(MotionCallback); }

 

void InitMenu() {

  displayMenu = glutCreateMenu(SetDisplayMenu);

  glutAddMenuEntry("Wireframe", WIREFRAME);

  glutAddMenuEntry("Hidden Line", HIDDENLINE);

  glutAddMenuEntry("Flat Shaded", FLATSHADED);

  glutAddMenuEntry("Smooth Shaded", SMOOTHSHADED);

  mainMenu = glutCreateMenu(SetMainMenu);

  glutAddSubMenu("Display", displayMenu);

  glutAddMenuEntry("Exit", 99);

  glutAttachMenu(GLUT_RIGHT_BUTTON); }

 

void InitGeometry() {

  triangleCount = 2;

  /* coordinates */

  triangleList[0].v[0].x[0] = 0;   triangleList[0].v[0].x[1] = 0;   triangleList[0].v[0].x[2] = 0;

  triangleList[0].v[1].x[0] = 0;   triangleList[0].v[1].x[1] = 1;   triangleList[0].v[1].x[2] = 0;

  triangleList[0].v[2].x[0] = 1;   triangleList[0].v[2].x[1] = 0;   triangleList[0].v[2].x[2] = 0;

  triangleList[1].v[0].x[0] = 0;   triangleList[1].v[0].x[1] = 0;   triangleList[1].v[0].x[2] = 0;

  triangleList[1].v[1].x[0] = 0;   triangleList[1].v[1].x[1] = 0;   triangleList[1].v[1].x[2] = 1;

  triangleList[1].v[2].x[0] = 0;   triangleList[1].v[2].x[1] = 1;   triangleList[1].v[2].x[2] = 0;

  /* normals */

  triangleList[0].v[0].n[0] = 0.7;   triangleList[0].v[0].n[1] = 0;   triangleList[0].v[0].n[2] = 0.7;

  triangleList[0].v[1].n[0] = 0.7;   triangleList[0].v[1].n[1] = 0;   triangleList[0].v[1].n[2] = 0.7;

  triangleList[0].v[2].n[0] = 0;   triangleList[0].v[2].n[1] = 0;   triangleList[0].v[2].n[2] = 1;

  triangleList[1].v[0].n[0] = 0.7;   triangleList[1].v[0].n[1] = 0;   triangleList[1].v[0].n[2] = 0.7;

  triangleList[1].v[1].n[0] = 1;   triangleList[1].v[1].n[1] = 0;   triangleList[1].v[1].n[2] = 0;

  triangleList[1].v[2].n[0] = 0.7;    triangleList[1].v[2].n[1] = 0;   triangleList[1].v[2].n[2] = 0.7; }

 

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

  glutInit(&argc, argv);

  InitGL();

  InitMenu();

  InitGeometry();

  glutMainLoop(); }