/*==========================================================
  File:  ms3d.c
  Author:  _pragma

  Description:  Loads MilkShape3D models.
  ==========================================================*/


#include <limits.h>
#include <GL/gl.h>
#include <SDL/SDL.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "ms3d.h"
#include "texture.h"
#include "console.h"
#include "util.h"

ms3d_model_t *MS3D_loadModel(char *filename)
{
  FILE *fp;
  char *buffer, *p;
  int sizeij;
  ms3d_model_t *model = 0;

  if(!(fp = fopen(filename"rb")))
  {
    CON_printf("loadModel: failed to open '%s'"filename);
    perror("loadModel");
    return 0;
  }

  fseek(fp0SEEK_END);
  size = ftell(fp);
  fseek(fp0SEEK_SET);
 
  if(!(buffer = malloc(size)))
  {
    CON_printf("Failed to alloc memory for model buffer");
    perror("malloc buffer");
    fclose(fp);
    return 0;
  }

  fread(buffersize1fp);
  fclose(fp);

  p = buffer;

  if(!(model = malloc(sizeof(ms3d_model_t))))
  {
    CON_printf("Failed to allocate memory for model");
    perror("malloc model");
    free(buffer);
    return 0;
  }

  memcpy(&model->header, (ms3d_header_t *)psizeof(ms3d_header_t));
  p += sizeof(ms3d_header_t);

  if(strncmp(model->header.id"MS3D000000"10) != 0)
  {
    CON_printf("loadModel: '%s' is not a ms3d file"filename);
    free(buffer);
    return 0;
  }

  if(model->header.version < 3 || model->header.version > 4)
  {
     CON_printf("loadModel: '%s' is version %d (requires 3 or 4)",
                filenamemodel->header.version);
     free(buffer);
     return 0;
  }

  CON_printf("Loading '%s' - %d bytes, version %d"filenamesizemodel->header.version);

  /************** Vertices ***************/

  model->numVertices = *(unsigned short *)p;
  p += sizeof(unsigned short);
  
  CON_printf("vertices: %d"model->numVertices);  

  if(!(model->vertices = malloc(sizeof(ms3d_vertex_t) * model->numVertices)))
  {
    CON_printf("Failed to allocate memory for vertices");
    perror("malloc vertices");
    free(buffer);
    return 0;
  }

  for(i = 0i < model->numVerticesi++)
  {
    memcpy(&model->vertices[i],
           (ms3d_vertex_t *)psizeof(ms3d_vertex_t));
    p += sizeof(ms3d_vertex_t);

/* fixme: perhaps we can have a console variable 'm_verbose'
          that will display all these CON_printf()s

    CON_printf("read vertex %d: %d, %3.2f, %3.2f, %3.2f, %d, %d",
                i, model->vertices[i].flags,
                model->vertices[i].vertex[0],
                model->vertices[i].vertex[1],
                model->vertices[i].vertex[2],
                model->vertices[i].boneId,
                model->vertices[i].referenceCount);
*/

  }

  /***************************************/
  
  /************* Triangles ***************/

  model->numTriangles = *(unsigned short *)p;
  p += sizeof(unsigned short);
  
  CON_printf("triangles: %d"model->numTriangles);  

  if(!(model->triangles = malloc(sizeof(ms3d_triangle_t) * model->numTriangles)))
  {
    CON_printf("Failed to allocate memory for triangles");
    perror("malloc triangles");
    free(buffer);
    return 0;
  }

  for(i = 0i < model->numTrianglesi++)
  {
    memcpy(&model->triangles[i],
           (ms3d_triangle_t *)psizeof(ms3d_triangle_t));
    p += sizeof(ms3d_triangle_t);

/* fixme: perhaps we can have a console variable 'm_verbose'
          that will display all these CON_printf()s

    CON_printf("read triangle %d: %d, %d, %d, %d, %3.2f, %3.2f, %3.2f",
                i, model->triangles[i].flags,
                model->triangles[i].vertexIndices[0],
                model->triangles[i].vertexIndices[1],
                model->triangles[i].vertexIndices[2],
                model->triangles[i].vertexNormals[0],
                model->triangles[i].vertexNormals[1],
                model->triangles[i].vertexNormals[2]);
    CON_printf("                  %3.2f, %3.2f, %3.2f, %3.2f, %3.2f, %3.2f",
                model->triangles[i].s[0],
                model->triangles[i].s[1],
                model->triangles[i].s[2],
                model->triangles[i].t[0],
                model->triangles[i].t[1],
                model->triangles[i].t[2]);
    CON_printf("                  %d, %d",
                model->triangles[i].smoothingGroup,
                model->triangles[i].groupIndex);
*/

  }

  /***************************************/
  
  /*********** Groups (Meshes) ***********/

  model->numGroups = *(unsigned short *)p;
  p += sizeof(unsigned short);
  
  CON_printf("groups: %d"model->numGroups);  

  if(!(model->groups = malloc(sizeof(ms3d_group_t) * model->numGroups)))
  {
    CON_printf("Failed to allocate memory for groups");
    perror("malloc groups");
    free(buffer);
    return 0;
  }

  for(i = 0i < model->numGroupsi++)
  {
    memcpy(&model->groups[i],
           (ms3d_group_t *)psizeof(ms3d_group_t));
    p += sizeof(ms3d_group_t);
    p -= sizeof(unsigned short *);  // triangleIndices
    p -= sizeof(unsigned char);     // materialIndex

/* fixme: perhaps we can have a console variable 'm_verbose'
          that will display all these CON_printf()s
 */

    CON_printf("read group %d: %d, %s, %d",
                imodel->groups[i].flags,
                model->groups[i].name,
                model->groups[i].numTriangles);
/**/

    model->groups[i].triangleIndices = malloc(sizeof(unsigned short) * model->groups[i].numTriangles);

    for(j = 0j < model->groups[i].numTrianglesj++)
    {
      model->groups[i].triangleIndices[j] = *(unsigned short *)p;
      p += sizeof(unsigned short);

//      CON_printf("read index %d: %d", j, model->groups[i].triangleIndices[j]);
    }
    model->groups[i].materialIndex = *(unsigned char *)p;
    p += sizeof(unsigned char);
  }

  /***************************************/
  
  /************* Materials ***************/

  model->numMaterials = *(unsigned short *)p;
  p += sizeof(unsigned short);
  
  CON_printf("materials: %d"model->numMaterials);  

  if(!(model->materials = malloc(sizeof(ms3d_material_t) * model->numMaterials)))
  {
    CON_printf("Failed to allocate memory for materials");
    perror("malloc materials");
    free(buffer);
    return 0;
  }

  for(i = 0i < model->numMaterialsi++)
  {
    memcpy(&model->materials[i],
           (ms3d_material_t *)psizeof(ms3d_material_t));
    p += sizeof(ms3d_material_t);

/* fixme: perhaps we can have a console variable 'm_verbose'
          that will display all these CON_printf()s
*/

    CON_printf("read material %d: %s - %s",
                imodel->materials[i].namemodel->materials[i].texture);
  }

  /***************************************/
  
#if 0
  /******** Animation information ********/

  model->numVertices = *(unsigned short *)p;
  p += sizeof(unsigned short);
  
  CON_printf("vertices: %d"model->numVertices);  

  if(!(model->vertices = malloc(sizeof(ms3d_vertex_t) * model->numVertices)))
  {
    CON_printf("Failed to allocate memory for model");
    perror("malloc vertices");
    free(buffer);
    return 0;
  }

  for(i = 0i < model->numVerticesi++)
  {
    memcpy(&model->vertices[i],
           (ms3d_vertex_t *)psizeof(ms3d_vertex_t));
    p += sizeof(ms3d_vertex_t);

/* fixme: perhaps we can have a console variable 'm_verbose'
          that will display all these CON_printf()s

    CON_printf("read vertex %d: %d, %3.2f, %3.2f, %3.2f, %d, %d",
                i, model->vertices[i].flags,
                model->vertices[i].vertex[0],
                model->vertices[i].vertex[1],
                model->vertices[i].vertex[2],
                model->vertices[i].boneId,
                model->vertices[i].referenceCount);
*/

  }

  /***************************************/
  
  /************ Bones/Joints *************/

  model->numVertices = *(unsigned short *)p;
  p += sizeof(unsigned short);
  
  CON_printf("vertices: %d"model->numVertices);  

  if(!(model->vertices = malloc(sizeof(ms3d_vertex_t) * model->numVertices)))
  {
    CON_printf("Failed to allocate memory for model");
    perror("malloc vertices");
    free(buffer);
    return 0;
  }

  for(i = 0i < model->numVerticesi++)
  {
    memcpy(&model->vertices[i],
           (ms3d_vertex_t *)psizeof(ms3d_vertex_t));
    p += sizeof(ms3d_vertex_t);

/* fixme: perhaps we can have a console variable 'm_verbose'
          that will display all these CON_printf()s

    CON_printf("read vertex %d: %d, %3.2f, %3.2f, %3.2f, %d, %d",
                i, model->vertices[i].flags,
                model->vertices[i].vertex[0],
                model->vertices[i].vertex[1],
                model->vertices[i].vertex[2],
                model->vertices[i].boneId,
                model->vertices[i].referenceCount);
*/

  }

  /***************************************/
#endif  

  free(buffer);
  return model;
}

ms3d_model_t *MS3D_loadModelASCII(char *filename)
{
  return 0;
}

void MS3D_destroyModel(ms3d_model_t *model)
{
  int i;

  if(model)
  {
    if(model->vertices)
      free(model->vertices);
    if(model->triangles)
      free(model->triangles);
    if(model->groups)
    {
      for(i = 0i < model->numGroupsi++)
        if(model->groups[i].triangleIndices)
          free(model->groups[i].triangleIndices);
      free(model->groups);
    }
    if(model->materials)
      free(model->materials);
    free(model);
    model = 0;
  }  
}