/***************************************************************************
                          objects.c  -  object specific code
                             -------------------
    begin                : Mon Apr 14 2003
    copyright            : (C) 2003 by not avaliable
    email                : n_winters99 yahoo.com
 ***************************************************************************/

#include "includes.h"

/* load file fname (a .trx file), and execute the opengl commands so that
 * the mesh it defines can be loaded into a display list
 */
enum condition loadNdDraw(char *fname ) {   // make return void in the future?
  // load a triangle mesh (.trx) and draw it
  // this is intended to be called from inside the creation of a display list
  FILE *f;
  int numTriangles, numValues = 0, i, success = 0;
  int wire = 0; // maybe an argument in the future? now just for kicks, and debug
  char key[12];
  GLushort c1, c2, c3;
  GLfloat d1, d2, d3;
  //printf("Loading file %s for viewing\n", fname);
  f = fopen(fname, "r");
  // read the file...
  if (f) numValues = fscanf(f, "%s %d", key, &numTriangles);
  if (numValues == 2 && numTriangles > 0) {
    // good, now read the trianlges
    //if (!wire)
    glBegin(GL_TRIANGLES);
    while (getc(f) != EOF) {
      // for norm
      //printf("norm\n");
      numValues = fscanf(f, "%s [%f, %f, %f]", key, &d1, &d2, &d3);
      //printf("values: %d, %s, %f, %f, %f\n", numValues, key, d1, d2, d3);
      if (numValues < 4) {
        //printf("...!!!...\n");
        success = 1;
        break;
      }
      //if (wire) glBegin(GL_LINE_LOOP);
      // for each vertex (trianlges have 3)
      for (i =0; i<3; i++) {
        // was debug
        c1 = c2 = c3 = 128;
        d1 = d2 = d3 = 0.0;
        key[0] = '\0';// */
        // for color
        numValues = fscanf(f, "%s [%hu, %hu, %hu]", key, &c1, &c2, &c3); 
				// unsigned short ints because I don't know the input code for unsigned bytes...
        // the numbers should be in the proper bounds anyway
        // stress on word SHOULD, too lazy to check though
        glColor3ub((GLubyte)c1,(GLubyte)c2, (GLubyte)c3);
        // for coord
        numValues = fscanf(f, "%s [%f, %f, %f]", key, &d1, &d2, &d3);
        if (numValues < 4) printf("not enough coordinates in vert\n");
        glVertex3f(d1,d2,d3); 
        /* I should ideally test numValues to see if this is an invalid format
        ... but time may not allow it */
      }
      //if (wire) glEnd();
    }
    //if (!wire)
    glEnd();
  } else {
    //sprintf(stderr,
    printf(
      "encountered file error, possibly an invalid first line\n"
      "or an invalid file\n or no file\nor something else\n"
      "when trying to load %s",fname);
  }
  if (f) fclose(f);
  return success;
}


/* load file fname (a .trx file), into an array of collision faces
 * it returns a pointer to that array, and sets the value at numFaces to
 * the number of collisionFaces the array contains
 * null is returned on failure, numFaces then cannot be trusted
 */
collisionFace *loadCollisionFaces(char fname[]) {
  // load a triangle mesh (.trx)
  // this will return the first element of a linked list
  FILE *f;
  int numTriangles, numValues = 0, i, j, done = 0;
  char key[12];
  unsigned short int c1, c2, c3;  // color, unused for colisions
  float d1, d2, d3;
  collisionFace *lastFace, *newFace, *firstFace; // to be returned...

  //printf("Loading file %s for dynamics... \n", fname);
    
  f = fopen(fname, "r");
  // read the file...
  if (f) {
    numValues = fscanf(f, "%s %d", key, &numTriangles);
  } 
  if (numValues == 2 && numTriangles > 0) {
    //printf("contains %d triangles\n", numTriangles);
    // allocate memory
    //thisFace = malloc(sizeof(collisionFace));
    firstFace = malloc(sizeof(collisionFace));
    newFace = firstFace;
    
    // good, now read the trianlges
    i = 0;
    while ((getc(f) != EOF) && (!done)) {
      // for norm
      //printf("norm\n");
      numValues = fscanf(f, "%s [%f, %f, %f]", key, &d1, &d2, &d3);
      if (numValues < 4) {
        // the file will end with EOF or a blank line, this shoudl catch this
        //printf("...!!!...\n");
        done = 1;
        break;
      }
      // allocate new face here
      if (i>0) { // on the first iteration there is no last face
        newFace = malloc(sizeof(collisionFace));
        newFace->nextFace = NULL;
        // link to old face
        lastFace->nextFace = newFace;
        // set values of new face
      }
      newFace->no.x = d1;
      newFace->no.y = d2;
      newFace->no.z = d3;
      vec_normalize(&newFace->no);
      // for each vertex in a triangle
      for (j=0; j<3; j++) {
        // for color
        numValues = fscanf(f, "%s [%hu, %hu, %hu]", key, &c1, &c2, &c3);
        if (numValues <4) {
          freeCollisionFaces(firstFace);
          printf("Colision file loading error\n");
          return NULL;
        }
        // for coord
        numValues = fscanf(f, "%s [%f, %f, %f]", key, &d1, &d2, &d3);
        if (numValues <4) {
          freeCollisionFaces(firstFace);
          printf("Colision file loading error\n");
          return NULL;
        }
        newFace->v[j].x = d1;
        newFace->v[j].y = d2;
        newFace->v[j].z = d3;

        // I should ideally test key to see if it is proper
        // hopefully later
      }
      // the dot product of the normal and a point
      newFace->offset =  vec_dot(newFace->no, newFace->v[0]);
      lastFace = newFace;
      i++;
    }
    if (i<numTriangles) {
      printf("Didn't find enough triangles in colision object\n");
      freeCollisionFaces(firstFace);
      return NULL;
    }
  } else {
    //sprintf(stderr,
    printf(
      "encountered file error, possibly an invalid first line\n"
      "or an invalid file\n or no file\nor something else\n"
      "when trying to load %s\n",fname);
    return NULL;
  }
  fclose(f);
  // because it wasn't initalized to null already...
  //lastFace->nextFace = NULL;
  return firstFace;
} 

/* free CollisionFaces,
 * collisionFace is an element in a linked list
 * this recursively frees their memory
 */
void freeCollisionFaces(collisionFace *firstFace) {
  // collision faces are a linked list
  // free them
  int i = 0; // debug
  collisionFace *thisFace, *nextFace;
  thisFace = firstFace;
  //printf("attempting to free collision faces...   ");
  while (thisFace) {
    // find the next face
    nextFace = thisFace->nextFace;
    // free this one
    free(thisFace);
    // make it this face
    thisFace = nextFace;
    i++;
  }
  //printf("done, freed %d tris\n", i);
}


/* draw x/y/z axes in 3 space
 * will likely be used as a placeholder for other objects
 */
void drawAxis() {
  // draw x/y/z axis
  float smallNum = 0.05f;
  // x axis
  glColor3f(1.0f, 0.0f, 0.0f);
  glBegin(GL_QUAD_STRIP);
    glVertex3f(1.0f,  smallNum, smallNum);
    glVertex3f(smallNum, smallNum, smallNum);
    glVertex3f(1.0f, -smallNum, smallNum);
    glVertex3f(smallNum, -smallNum, smallNum);
    glVertex3f(1.0f, -smallNum, -smallNum);
    glVertex3f(smallNum, -smallNum, -smallNum);
    glVertex3f(1.0f, smallNum, -smallNum);
    glVertex3f(smallNum, smallNum, -smallNum);
    glVertex3f(1.0f, smallNum, smallNum);
    glVertex3f(smallNum, smallNum, smallNum);
  glEnd();
  // y axis
  glColor3f(0.0f, 1.0f, 0.0f);
  glBegin(GL_QUAD_STRIP);
    glVertex3f(smallNum, smallNum, smallNum);
    glVertex3f(smallNum, 1.0f,  smallNum);
    glVertex3f(-smallNum, smallNum, smallNum);
    glVertex3f(-smallNum, 1.0f, smallNum);
    glVertex3f(-smallNum, smallNum, -smallNum);
    glVertex3f(-smallNum, 1.0f, -smallNum);
    glVertex3f(smallNum, smallNum, -smallNum);
    glVertex3f(smallNum, 1.0f, -smallNum);
    glVertex3f(smallNum, smallNum, smallNum);
    glVertex3f(smallNum, 1.0f, smallNum);
  glEnd();
  // z axis
  glColor3f(0.0f, 0.0f, 1.0f);
  glBegin(GL_QUAD_STRIP);
    glVertex3f(smallNum, smallNum, 1.0f);
    glVertex3f(smallNum, smallNum, smallNum);
    glVertex3f(-smallNum, smallNum, 1.0f);
    glVertex3f(-smallNum, smallNum, smallNum);
    glVertex3f(-smallNum, -smallNum, 1.0f);
    glVertex3f(-smallNum, -smallNum, smallNum);
    glVertex3f(smallNum, -smallNum, 1.0f);
    glVertex3f(smallNum, -smallNum, smallNum);
    glVertex3f(smallNum, smallNum, 1.0f);
    glVertex3f(smallNum, smallNum, smallNum);
  glEnd();
}
