/*
   CMSC 427 - Term Project Candidate
   ---------------------------------

   Beth Weinstein - bweinste@wam.umd.edu
   Ben Stewart - stewartb@wam.umd.edu
   Nawfel Tricha - Topaz@endorproductions.com

   Minimal OpenGL project using Microsoft Visual C++.
   This project is a premilinary candidate for the term 
   project required by CMSC 427.

   ABSTRACT:
      In this project, we will develop several fast 
      rendering and collision routines which would 
      require C/C++ speed and accuracy and then 
      implement a VisualJ++ interface.

   MODULE:
      Skeletal model part module.

   NOTE:
      Parts are hierarchical submodels of the 3d mesh. They 
      represent limbs, heads, torso's, etc. For this CMSC427
      project, we will not use animated parts; therefore, 
      part actions and frames should be ommited.
*/

#include "global.h"
#include <fstream.h>

/*
   NT:
   Spawn next available part in list, initialize, and return pointer:
*/
#define DEFAULT_DELTA_SPEED .7f
part_t *PartSpawn()
{
   int x = 0;
   while (g_parts[x].taken && x < G_MAX_PARTS)
      x++;
   if (x == G_MAX_PARTS)
      {
      EngineError("SpawnPart: Part library is full. Quitting.\n");
      return NULL;
      }
   memset (&g_parts[x], 0, sizeof(g_parts[0]));
   if (x >= eng.num_parts)
      eng.num_parts++;
   g_parts[x].taken = true;
   g_parts[x].model_index = NOT_FOUND;
   g_parts[x].skin_index = NOT_FOUND;
   VectorSet(g_parts[x].delta_angle, DEFAULT_DELTA_SPEED, DEFAULT_DELTA_SPEED, DEFAULT_DELTA_SPEED);
   return &g_parts[x];
}

/*
   NT:
   Return part to list for future use:
*/
void PartFree(part_t **p)
{
   int x = 0;
   while (&g_parts[x] != *p)
      x++;
   g_parts[x].taken = false;
   *p = NULL;   
}

/*
   NT:
   Spawn new action in part:
*/
pose_t *ActionSpawn()
{
   pose_t *a;
   a = new pose_t;
   memset (a, 0, sizeof(*a));
   return a;
}

/*
   NT:
   Add action frame to model:
*/
void FrameAdd(part_t *part, int i_action, vec3_t i_final_angle,
              vec3_t i_rotation, vec3_t i_translation)

{
   pose_t *f = new pose_t, *current;
   current = part->action[i_action];
   VectorCopy(i_final_angle, f->final_angle);
   VectorCopy(i_rotation, f->rotation);
   VectorScale(i_translation, MODEL_SCALE, f->translation);
   f->next = NULL;
   f->frame = 0;

   VectorClear(f->delta_angle); 
   if (!current)
      part->action[i_action] = f;
   else
      {
      while (current->next)
         current = current->next;
      current->next = f;
      }
}

/*
   NT:
   Rewind action to start frame:
*/
void FrameInit(part_t *part, int i_action)
{
   part->current_pose = part->action[i_action];
}

/*
   NT:
   Interpolate current frame:
*/
#define INTERPOLATION 9
void FrameInterpolate(part_t *part)
{
   if (!part->current_pose)
      return;
   if (!part->current_pose->rotation[0])
      part->current_pose->delta_angle[0] = 
         (part->current_pose->final_angle[0] - part->angle[0]) / INTERPOLATION;
   else
      part->current_pose->delta_angle[0] = 0;
   
   if (!part->current_pose->rotation[1])
      part->current_pose->delta_angle[1] = 
         (part->current_pose->final_angle[1] - part->angle[1]) / INTERPOLATION;
   else
      part->current_pose->delta_angle[1] = 0;
   
   if (!part->current_pose->rotation[2])
      part->current_pose->delta_angle[2] = 
         (part->current_pose->final_angle[2] - part->angle[2]) / INTERPOLATION;
   else
      part->current_pose->delta_angle[2] = 0;
}


/*
   NT:
   Return part containing the specified string:
*/
part_t *PartTag(char *tag_string)
{
   part_t *p = &g_parts[0];
   for (; p < &g_parts[eng.num_parts]; p++)
      {
      if (p->taken && p->tag_name)
         if (!strcmpi(p->tag_name, tag_string))
            return p;
      }
   return NULL;
}

/*
   NT:
   Set son of specified part:
*/
void PartSetSon(part_t *p, part_t *s)
{
   int x = 0;
   while (p->son[x] && x < G_MAX_SONS)
      x++;
   if (x == G_MAX_SONS)
      return;
   p->son[x] = s;
   s->father = p;
}

/*
   NT:
   Set father of specified part:
*/
void PartSetFather (char *tag_name, char *father)
{
   part_t *p, *b;
   if (tag_name)
      p = PartTag(tag_name);
   else
      p = last_part;
   if (!father)
      p->father = NULL;
   else
      {
      b = PartTag(father);
      if (!p)
         {
         EngineError ("PartSetFather: No part with such name %s  \n", tag_name);
         return;
         }
      if (!b)
         {
         EngineError ("PartSetFather: No father part with such name %s  \n", father);
         return;
         }
      PartSetSon(b, p);
      }
   
   last_part = p;   
}

/*
   NT:
   Set brother of specifed part:
*/
void PartSetBrother (char *tag_name, char *brother)
{
   part_t *p, *b;
   if (tag_name)
      p = PartTag(tag_name);
   else
      p = last_part;
   b = PartTag(brother);
   if (!p)
      {
      EngineError("PartSetBrother: No part with such name %s?  \n", tag_name);
      return;
      }
   p->brother = b;
   last_part = p;   
}

/*
   NT:
   Return number of action for a certain part:
*/
int PartActions(part_t *p)
{
   int count = 0;
   while (p->action[count])
      count++;
   return count;
}

/*
   NT:
   Return number of frames in a certain action in specified part:
*/
int PartActionFrames(part_t *p, int action_index)
{
   int count = 0;
   pose_t *current = p->action[action_index];
   while (current)
      {
      current = current->next;
      count++;
      }
   return count;
}
